mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 17:11:56 +01:00
Merge remote-tracking branch 'origin/master' into db-refactoring
This commit is contained in:
commit
9772d8af06
@ -4,6 +4,8 @@
|
||||
####Version 0.10.2
|
||||
* Pebble: allow to manually paste configuration data for legacy configuration pages
|
||||
* Pebble: various improvements to the configuration page
|
||||
* Pebble: Suppport FW 4.0-dp1 and Pebble2 emulator (needs recompilation of Gadgetbridge)
|
||||
* Pebble: Fix a problem with key events when using the Pebble music player
|
||||
|
||||
####Version 0.10.1
|
||||
* Pebble: set extended music info by dissecting notifications on Android 5.0+
|
||||
|
@ -18,8 +18,8 @@ android {
|
||||
targetSdkVersion 23
|
||||
|
||||
// note: always bump BOTH versionCode and versionName!
|
||||
versionName "0.10.1"
|
||||
versionCode 54
|
||||
versionName "0.10.2"
|
||||
versionCode 55
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@ -60,6 +60,7 @@ dependencies {
|
||||
compile 'de.cketti.library.changelog:ckchangelog:1.2.2'
|
||||
compile 'net.e175.klaus:solarpositioning:0.0.9'
|
||||
compile 'com.github.freeyourgadget:greendao:c3830951e5dd3d1e63d7bac600d5f773b81df363'
|
||||
compile 'com.github.woxthebox:draglistview:1.2.6'
|
||||
}
|
||||
|
||||
preBuild.dependsOn(":GBDaoGenerator:genSources")
|
||||
|
@ -55,7 +55,7 @@
|
||||
android:parentActivityName=".activities.SettingsActivity" />
|
||||
<activity
|
||||
android:launchMode="singleTop"
|
||||
android:name=".activities.AppManagerActivity"
|
||||
android:name=".activities.appmanager.AppManagerActivity"
|
||||
android:label="@string/title_activity_appmanager"
|
||||
android:parentActivityName=".activities.ControlCenter" />
|
||||
<activity
|
||||
@ -271,7 +271,7 @@
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:name=".activities.ExternalPebbleJSActivity"
|
||||
android:label="@string/app_configure"
|
||||
android:parentActivityName=".activities.AppManagerActivity">
|
||||
android:parentActivityName=".activities.appmanager.AppManagerActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter" />
|
||||
|
@ -1,286 +0,0 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAppAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
|
||||
public class AppManagerActivity extends GBActivity {
|
||||
public static final String ACTION_REFRESH_APPLIST
|
||||
= "nodomain.freeyourgadget.gadgetbridge.appmanager.action.refresh_applist";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AppManagerActivity.class);
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action.equals(GBApplication.ACTION_QUIT)) {
|
||||
finish();
|
||||
} else if (action.equals(ACTION_REFRESH_APPLIST)) {
|
||||
int appCount = intent.getIntExtra("app_count", 0);
|
||||
for (Integer i = 0; i < appCount; i++) {
|
||||
String appName = intent.getStringExtra("app_name" + i.toString());
|
||||
String appCreator = intent.getStringExtra("app_creator" + i.toString());
|
||||
UUID uuid = UUID.fromString(intent.getStringExtra("app_uuid" + i.toString()));
|
||||
GBDeviceApp.Type appType = GBDeviceApp.Type.values()[intent.getIntExtra("app_type" + i.toString(), 0)];
|
||||
|
||||
boolean found = false;
|
||||
for (final ListIterator<GBDeviceApp> iter = appList.listIterator(); iter.hasNext(); ) {
|
||||
final GBDeviceApp app = iter.next();
|
||||
if (app.getUUID().equals(uuid)) {
|
||||
app.setOnDevice(true);
|
||||
iter.set(app);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
GBDeviceApp app = new GBDeviceApp(uuid, appName, appCreator, "", appType);
|
||||
app.setOnDevice(true);
|
||||
appList.add(app);
|
||||
}
|
||||
}
|
||||
|
||||
mGBDeviceAppAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private Prefs prefs;
|
||||
|
||||
private final List<GBDeviceApp> appList = new ArrayList<>();
|
||||
private GBDeviceAppAdapter mGBDeviceAppAdapter;
|
||||
private GBDeviceApp selectedApp = null;
|
||||
private GBDevice mGBDevice = null;
|
||||
|
||||
private List<GBDeviceApp> getSystemApps() {
|
||||
List<GBDeviceApp> systemApps = new ArrayList<>();
|
||||
if (prefs.getBoolean("pebble_force_untested", false)) {
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getHardwareVersion()))) {
|
||||
systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_PEBBLE_HEALTH, "Health (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
|
||||
return systemApps;
|
||||
}
|
||||
|
||||
private List<GBDeviceApp> getCachedApps() {
|
||||
List<GBDeviceApp> cachedAppList = new ArrayList<>();
|
||||
File cachePath;
|
||||
try {
|
||||
cachePath = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache");
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not get external dir while reading pbw cache.");
|
||||
return cachedAppList;
|
||||
}
|
||||
|
||||
File files[] = cachePath.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.getName().endsWith(".pbw")) {
|
||||
String baseName = file.getName().substring(0, file.getName().length() - 4);
|
||||
//metadata
|
||||
File jsonFile = new File(cachePath, baseName + ".json");
|
||||
//configuration
|
||||
File configFile = new File(cachePath, baseName + "_config.js");
|
||||
try {
|
||||
String jsonstring = FileUtils.getStringFromFile(jsonFile);
|
||||
JSONObject json = new JSONObject(jsonstring);
|
||||
cachedAppList.add(new GBDeviceApp(json, configFile.exists()));
|
||||
} catch (Exception e) {
|
||||
LOG.warn("could not read json file for " + baseName, e.getMessage(), e);
|
||||
cachedAppList.add(new GBDeviceApp(UUID.fromString(baseName), baseName, "N/A", "", GBDeviceApp.Type.UNKNOWN));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cachedAppList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
mGBDevice = extras.getParcelable(GBDevice.EXTRA_DEVICE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Must provide a device when invoking this activity");
|
||||
}
|
||||
|
||||
prefs = GBApplication.getPrefs();
|
||||
|
||||
setContentView(R.layout.activity_appmanager);
|
||||
|
||||
ListView appListView = (ListView) findViewById(R.id.appListView);
|
||||
mGBDeviceAppAdapter = new GBDeviceAppAdapter(this, appList);
|
||||
appListView.setAdapter(this.mGBDeviceAppAdapter);
|
||||
|
||||
appListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView parent, View v, int position, long id) {
|
||||
UUID uuid = appList.get(position).getUUID();
|
||||
GBApplication.deviceService().onAppStart(uuid, true);
|
||||
}
|
||||
});
|
||||
|
||||
registerForContextMenu(appListView);
|
||||
|
||||
appList.addAll(getCachedApps());
|
||||
|
||||
appList.addAll(getSystemApps());
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(GBApplication.ACTION_QUIT);
|
||||
filter.addAction(ACTION_REFRESH_APPLIST);
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter);
|
||||
|
||||
GBApplication.deviceService().onAppInfoReq();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
getMenuInflater().inflate(R.menu.appmanager_context, menu);
|
||||
AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
selectedApp = appList.get(acmi.position);
|
||||
|
||||
if (!selectedApp.isInCache()) {
|
||||
menu.removeItem(R.id.appmanager_app_reinstall);
|
||||
menu.removeItem(R.id.appmanager_app_delete_cache);
|
||||
}
|
||||
if (!PebbleProtocol.UUID_PEBBLE_HEALTH.equals(selectedApp.getUUID())) {
|
||||
menu.removeItem(R.id.appmanager_health_activate);
|
||||
menu.removeItem(R.id.appmanager_health_deactivate);
|
||||
}
|
||||
if (selectedApp.getType() == GBDeviceApp.Type.APP_SYSTEM) {
|
||||
menu.removeItem(R.id.appmanager_app_delete);
|
||||
}
|
||||
if (!selectedApp.isConfigurable()) {
|
||||
menu.removeItem(R.id.appmanager_app_configure);
|
||||
}
|
||||
if (mGBDevice != null && !mGBDevice.getFirmwareVersion().startsWith("v3")) {
|
||||
menu.removeItem(R.id.appmanager_app_move_to_top);
|
||||
}
|
||||
menu.setHeaderTitle(selectedApp.getName());
|
||||
}
|
||||
|
||||
private void removeAppFromList(UUID uuid) {
|
||||
for (final ListIterator<GBDeviceApp> iter = appList.listIterator(); iter.hasNext(); ) {
|
||||
final GBDeviceApp app = iter.next();
|
||||
if (app.getUUID().equals(uuid)) {
|
||||
iter.remove();
|
||||
mGBDeviceAppAdapter.notifyDataSetChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.appmanager_health_deactivate:
|
||||
case R.id.appmanager_app_delete_cache:
|
||||
String baseName;
|
||||
try {
|
||||
baseName = FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID();
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not get external dir while trying to access pbw cache.");
|
||||
return true;
|
||||
}
|
||||
|
||||
String[] suffixToDelete = new String[]{".pbw", ".json", "_config.js"};
|
||||
|
||||
for (String suffix : suffixToDelete) {
|
||||
File fileToDelete = new File(baseName + suffix);
|
||||
if (!fileToDelete.delete()) {
|
||||
LOG.warn("could not delete file from pbw cache: " + fileToDelete.toString());
|
||||
} else {
|
||||
LOG.info("deleted file: " + fileToDelete.toString());
|
||||
}
|
||||
}
|
||||
removeAppFromList(selectedApp.getUUID());
|
||||
// fall through
|
||||
case R.id.appmanager_app_delete:
|
||||
GBApplication.deviceService().onAppDelete(selectedApp.getUUID());
|
||||
return true;
|
||||
case R.id.appmanager_app_reinstall:
|
||||
File cachePath;
|
||||
try {
|
||||
cachePath = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID() + ".pbw");
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not get external dir while trying to access pbw cache.");
|
||||
return true;
|
||||
}
|
||||
GBApplication.deviceService().onInstallApp(Uri.fromFile(cachePath));
|
||||
return true;
|
||||
case R.id.appmanager_health_activate:
|
||||
GBApplication.deviceService().onInstallApp(Uri.parse("fake://health"));
|
||||
return true;
|
||||
case R.id.appmanager_app_configure:
|
||||
GBApplication.deviceService().onAppStart(selectedApp.getUUID(), true);
|
||||
|
||||
Intent startIntent = new Intent(getApplicationContext(), ExternalPebbleJSActivity.class);
|
||||
startIntent.putExtra(DeviceService.EXTRA_APP_UUID, selectedApp.getUUID());
|
||||
startIntent.putExtra(GBDevice.EXTRA_DEVICE, mGBDevice);
|
||||
startActivity(startIntent);
|
||||
return true;
|
||||
case R.id.appmanager_app_move_to_top:
|
||||
GBApplication.deviceService().onAppReorder(new UUID[]{selectedApp.getUUID()});
|
||||
return true;
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
@ -0,0 +1,354 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.appmanager;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import com.woxthebox.draglistview.DragListView;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ExternalPebbleJSActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAppAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
|
||||
public abstract class AbstractAppManagerFragment extends Fragment {
|
||||
public static final String ACTION_REFRESH_APPLIST
|
||||
= "nodomain.freeyourgadget.gadgetbridge.appmanager.action.refresh_applist";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractAppManagerFragment.class);
|
||||
|
||||
|
||||
protected void refreshList() {
|
||||
}
|
||||
|
||||
protected String getSortFilename() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onChangedAppOrder() {
|
||||
List<UUID> uuidList = new ArrayList<>();
|
||||
for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getItemList()) {
|
||||
uuidList.add(gbDeviceApp.getUUID());
|
||||
}
|
||||
AppManagerActivity.rewriteAppOrderFile(getSortFilename(), uuidList);
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action.equals(GBApplication.ACTION_QUIT)) {
|
||||
// finish();
|
||||
} else if (action.equals(ACTION_REFRESH_APPLIST)) {
|
||||
if (intent.hasExtra("app_count")) {
|
||||
int appCount = intent.getIntExtra("app_count", 0);
|
||||
for (Integer i = 0; i < appCount; i++) {
|
||||
String appName = intent.getStringExtra("app_name" + i.toString());
|
||||
String appCreator = intent.getStringExtra("app_creator" + i.toString());
|
||||
UUID uuid = UUID.fromString(intent.getStringExtra("app_uuid" + i.toString()));
|
||||
GBDeviceApp.Type appType = GBDeviceApp.Type.values()[intent.getIntExtra("app_type" + i.toString(), 0)];
|
||||
|
||||
boolean found = false;
|
||||
for (final ListIterator<GBDeviceApp> iter = appList.listIterator(); iter.hasNext(); ) {
|
||||
final GBDeviceApp app = iter.next();
|
||||
if (app.getUUID().equals(uuid)) {
|
||||
app.setOnDevice(true);
|
||||
iter.set(app);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
GBDeviceApp app = new GBDeviceApp(uuid, appName, appCreator, "", appType);
|
||||
app.setOnDevice(true);
|
||||
appList.add(app);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
refreshList();
|
||||
}
|
||||
mGBDeviceAppAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private Prefs prefs;
|
||||
|
||||
protected final List<GBDeviceApp> appList = new ArrayList<>();
|
||||
private GBDeviceAppAdapter mGBDeviceAppAdapter;
|
||||
protected GBDevice mGBDevice = null;
|
||||
|
||||
protected List<GBDeviceApp> getSystemApps() {
|
||||
List<GBDeviceApp> systemApps = new ArrayList<>();
|
||||
if (prefs.getBoolean("pebble_force_untested", false)) {
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getHardwareVersion()))) {
|
||||
systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_PEBBLE_HEALTH, "Health (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
|
||||
return systemApps;
|
||||
}
|
||||
|
||||
protected List<GBDeviceApp> getSystemWatchfaces() {
|
||||
List<GBDeviceApp> systemWatchfaces = new ArrayList<>();
|
||||
systemWatchfaces.add(new GBDeviceApp(UUID.fromString("8f3c8686-31a1-4f5f-91f5-01600c9bdc59"), "Tic Toc (System)", "Pebble Inc.", "", GBDeviceApp.Type.WATCHFACE_SYSTEM));
|
||||
return systemWatchfaces;
|
||||
}
|
||||
|
||||
protected List<GBDeviceApp> getCachedApps(List<UUID> uuids) {
|
||||
List<GBDeviceApp> cachedAppList = new ArrayList<>();
|
||||
File cachePath;
|
||||
try {
|
||||
cachePath = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache");
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not get external dir while reading pbw cache.");
|
||||
return cachedAppList;
|
||||
}
|
||||
|
||||
File[] files;
|
||||
if (uuids == null) {
|
||||
files = cachePath.listFiles();
|
||||
} else {
|
||||
files = new File[uuids.size()];
|
||||
int index = 0;
|
||||
for (UUID uuid : uuids) {
|
||||
files[index++] = new File(uuid.toString() + ".pbw");
|
||||
}
|
||||
}
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.getName().endsWith(".pbw")) {
|
||||
String baseName = file.getName().substring(0, file.getName().length() - 4);
|
||||
//metadata
|
||||
File jsonFile = new File(cachePath, baseName + ".json");
|
||||
//configuration
|
||||
File configFile = new File(cachePath, baseName + "_config.js");
|
||||
try {
|
||||
String jsonstring = FileUtils.getStringFromFile(jsonFile);
|
||||
JSONObject json = new JSONObject(jsonstring);
|
||||
cachedAppList.add(new GBDeviceApp(json, configFile.exists()));
|
||||
} catch (Exception e) {
|
||||
LOG.info("could not read json file for " + baseName);
|
||||
//FIXME: this is really ugly, if we do not find system uuids in pbw cache add them manually
|
||||
if (prefs.getBoolean("pebble_force_untested", false)) {
|
||||
if (baseName.equals("4dab81a6-d2fc-458a-992c-7a1f3b96a970")) {
|
||||
cachedAppList.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
} else if (baseName.equals("cf1e816a-9db0-4511-bbb8-f60c48ca8fac")) {
|
||||
cachedAppList.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
}
|
||||
}
|
||||
if (baseName.equals("8f3c8686-31a1-4f5f-91f5-01600c9bdc59")) {
|
||||
cachedAppList.add(new GBDeviceApp(UUID.fromString("8f3c8686-31a1-4f5f-91f5-01600c9bdc59"), "Tic Toc (System)", "Pebble Inc.", "", GBDeviceApp.Type.WATCHFACE_SYSTEM));
|
||||
}
|
||||
if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getHardwareVersion()))) {
|
||||
if (baseName.equals(PebbleProtocol.UUID_PEBBLE_HEALTH.toString())) {
|
||||
cachedAppList.add(new GBDeviceApp(PebbleProtocol.UUID_PEBBLE_HEALTH, "Health (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (uuids == null) {
|
||||
cachedAppList.add(new GBDeviceApp(UUID.fromString(baseName), baseName, "N/A", "", GBDeviceApp.Type.UNKNOWN));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cachedAppList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
mGBDevice = ((AppManagerActivity) getActivity()).getGBDevice();
|
||||
|
||||
prefs = GBApplication.getPrefs();
|
||||
|
||||
refreshList();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(GBApplication.ACTION_QUIT);
|
||||
filter.addAction(ACTION_REFRESH_APPLIST);
|
||||
|
||||
LocalBroadcastManager.getInstance(getContext()).registerReceiver(mReceiver, filter);
|
||||
|
||||
GBApplication.deviceService().onAppInfoReq();
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
|
||||
View rootView = inflater.inflate(R.layout.activity_appmanager, container, false);
|
||||
|
||||
DragListView appListView = (DragListView) (rootView.findViewById(R.id.appListView));
|
||||
appListView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
mGBDeviceAppAdapter = new GBDeviceAppAdapter(appList, R.layout.item_with_details, R.id.item_image, this.getContext(), this);
|
||||
appListView.setAdapter(mGBDeviceAppAdapter, false);
|
||||
appListView.setCanDragHorizontally(false);
|
||||
appListView.setDragListListener(new DragListView.DragListListener() {
|
||||
@Override
|
||||
public void onItemDragStarted(int position) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemDragging(int itemPosition, float x, float y) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemDragEnded(int fromPosition, int toPosition) {
|
||||
onChangedAppOrder();
|
||||
}
|
||||
});
|
||||
return rootView;
|
||||
}
|
||||
|
||||
protected void sendOrderToDevice(String concatFilename) {
|
||||
ArrayList<UUID> uuids = new ArrayList<UUID>();
|
||||
for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getItemList()) {
|
||||
uuids.add(gbDeviceApp.getUUID());
|
||||
}
|
||||
if (concatFilename != null) {
|
||||
ArrayList<UUID> concatUuids = AppManagerActivity.getUuidsFromFile(concatFilename);
|
||||
uuids.addAll(concatUuids);
|
||||
}
|
||||
GBApplication.deviceService().onAppReorder(uuids.toArray(new UUID[uuids.size()]));
|
||||
}
|
||||
|
||||
private void removeAppFromList(UUID uuid) {
|
||||
for (final ListIterator<GBDeviceApp> iter = appList.listIterator(); iter.hasNext(); ) {
|
||||
final GBDeviceApp app = iter.next();
|
||||
if (app.getUUID().equals(uuid)) {
|
||||
iter.remove();
|
||||
mGBDeviceAppAdapter.notifyDataSetChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean openPopupMenu(View view, int position) {
|
||||
PopupMenu popupMenu = new PopupMenu(getContext(), view);
|
||||
popupMenu.getMenuInflater().inflate(R.menu.appmanager_context, popupMenu.getMenu());
|
||||
Menu menu = popupMenu.getMenu();
|
||||
final GBDeviceApp selectedApp = appList.get(position);
|
||||
|
||||
if (!selectedApp.isInCache()) {
|
||||
menu.removeItem(R.id.appmanager_app_reinstall);
|
||||
menu.removeItem(R.id.appmanager_app_delete_cache);
|
||||
}
|
||||
if (!PebbleProtocol.UUID_PEBBLE_HEALTH.equals(selectedApp.getUUID())) {
|
||||
menu.removeItem(R.id.appmanager_health_activate);
|
||||
menu.removeItem(R.id.appmanager_health_deactivate);
|
||||
}
|
||||
if (selectedApp.getType() == GBDeviceApp.Type.APP_SYSTEM) {
|
||||
menu.removeItem(R.id.appmanager_app_delete);
|
||||
}
|
||||
if (!selectedApp.isConfigurable()) {
|
||||
menu.removeItem(R.id.appmanager_app_configure);
|
||||
}
|
||||
//menu.setHeaderTitle(selectedApp.getName());
|
||||
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
return onContextItemSelected(item, selectedApp);
|
||||
}
|
||||
}
|
||||
);
|
||||
popupMenu.show();
|
||||
return false; // FIXME: whats that for?
|
||||
}
|
||||
|
||||
public boolean onContextItemSelected(MenuItem item, GBDeviceApp selectedApp) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.appmanager_health_deactivate:
|
||||
case R.id.appmanager_app_delete_cache:
|
||||
String baseName;
|
||||
try {
|
||||
baseName = FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID();
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not get external dir while trying to access pbw cache.");
|
||||
return true;
|
||||
}
|
||||
|
||||
String[] suffixToDelete = new String[]{".pbw", ".json", "_config.js"};
|
||||
|
||||
for (String suffix : suffixToDelete) {
|
||||
File fileToDelete = new File(baseName + suffix);
|
||||
if (!fileToDelete.delete()) {
|
||||
LOG.warn("could not delete file from pbw cache: " + fileToDelete.toString());
|
||||
} else {
|
||||
LOG.info("deleted file: " + fileToDelete.toString());
|
||||
}
|
||||
}
|
||||
AppManagerActivity.deleteFromAppOrderFile("pbwcacheorder.txt", selectedApp.getUUID()); // FIXME: only if successful
|
||||
// fall through
|
||||
case R.id.appmanager_app_delete:
|
||||
AppManagerActivity.deleteFromAppOrderFile(mGBDevice.getAddress() + ".watchapps", selectedApp.getUUID()); // FIXME: only if successful
|
||||
AppManagerActivity.deleteFromAppOrderFile(mGBDevice.getAddress() + ".watchfaces", selectedApp.getUUID()); // FIXME: only if successful
|
||||
Intent refreshIntent = new Intent(AbstractAppManagerFragment.ACTION_REFRESH_APPLIST);
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(refreshIntent);
|
||||
GBApplication.deviceService().onAppDelete(selectedApp.getUUID());
|
||||
return true;
|
||||
case R.id.appmanager_app_reinstall:
|
||||
File cachePath;
|
||||
try {
|
||||
cachePath = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID() + ".pbw");
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not get external dir while trying to access pbw cache.");
|
||||
return true;
|
||||
}
|
||||
GBApplication.deviceService().onInstallApp(Uri.fromFile(cachePath));
|
||||
return true;
|
||||
case R.id.appmanager_health_activate:
|
||||
GBApplication.deviceService().onInstallApp(Uri.parse("fake://health"));
|
||||
return true;
|
||||
case R.id.appmanager_app_configure:
|
||||
GBApplication.deviceService().onAppStart(selectedApp.getUUID(), true);
|
||||
|
||||
Intent startIntent = new Intent(getContext().getApplicationContext(), ExternalPebbleJSActivity.class);
|
||||
startIntent.putExtra(DeviceService.EXTRA_APP_UUID, selectedApp.getUUID());
|
||||
startIntent.putExtra(GBDevice.EXTRA_DEVICE, mGBDevice);
|
||||
startActivity(startIntent);
|
||||
return true;
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.appmanager;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractFragmentPagerAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragmentActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||
|
||||
|
||||
public class AppManagerActivity extends AbstractGBFragmentActivity {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractAppManagerFragment.class);
|
||||
|
||||
private GBDevice mGBDevice = null;
|
||||
|
||||
public GBDevice getGBDevice() {
|
||||
return mGBDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_fragmentappmanager);
|
||||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
if (extras != null) {
|
||||
mGBDevice = extras.getParcelable(GBDevice.EXTRA_DEVICE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Must provide a device when invoking this activity");
|
||||
}
|
||||
|
||||
|
||||
// Set up the ViewPager with the sections adapter.
|
||||
ViewPager viewPager = (ViewPager) findViewById(R.id.appmanager_pager);
|
||||
viewPager.setAdapter(getPagerAdapter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractFragmentPagerAdapter createFragmentPagerAdapter(FragmentManager fragmentManager) {
|
||||
return new SectionsPagerAdapter(fragmentManager);
|
||||
}
|
||||
|
||||
public static synchronized void deleteFromAppOrderFile(String filename, UUID uuid) {
|
||||
ArrayList<UUID> uuids = getUuidsFromFile(filename);
|
||||
uuids.remove(uuid);
|
||||
rewriteAppOrderFile(filename, uuids);
|
||||
}
|
||||
|
||||
public class SectionsPagerAdapter extends AbstractFragmentPagerAdapter {
|
||||
|
||||
public SectionsPagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
// getItem is called to instantiate the fragment for the given page.
|
||||
switch (position) {
|
||||
case 0:
|
||||
return new AppManagerFragmentCache();
|
||||
case 1:
|
||||
return new AppManagerFragmentInstalledApps();
|
||||
case 2:
|
||||
return new AppManagerFragmentInstalledWatchfaces();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return "Apps in cache";
|
||||
case 1:
|
||||
return "Installed apps";
|
||||
case 2:
|
||||
return "Installed watchfaces";
|
||||
case 3:
|
||||
}
|
||||
return super.getPageTitle(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
||||
static synchronized void rewriteAppOrderFile(String filename, List<UUID> uuids) {
|
||||
try {
|
||||
FileWriter fileWriter = new FileWriter(FileUtils.getExternalFilesDir() + "/" + filename);
|
||||
BufferedWriter out = new BufferedWriter(fileWriter);
|
||||
for (UUID uuid : uuids) {
|
||||
out.write(uuid.toString());
|
||||
out.newLine();
|
||||
}
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
LOG.warn("can't write app order to file!");
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public static void addToAppOrderFile(String filename, UUID uuid) {
|
||||
ArrayList<UUID> uuids = getUuidsFromFile(filename);
|
||||
uuids.remove(uuid); // if alread there
|
||||
uuids.add(uuid);
|
||||
rewriteAppOrderFile(filename, uuids);
|
||||
}
|
||||
|
||||
static synchronized ArrayList<UUID> getUuidsFromFile(String filename) {
|
||||
ArrayList<UUID> uuids = new ArrayList<>();
|
||||
try {
|
||||
FileReader fileReader = new FileReader(FileUtils.getExternalFilesDir() + "/" + filename);
|
||||
BufferedReader in = new BufferedReader(fileReader);
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
uuids.add(UUID.fromString(line));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warn("could not read sort file");
|
||||
}
|
||||
return uuids;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.appmanager;
|
||||
|
||||
public class AppManagerFragmentCache extends AbstractAppManagerFragment {
|
||||
@Override
|
||||
public void refreshList() {
|
||||
appList.clear();
|
||||
appList.addAll(getCachedApps(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSortFilename() {
|
||||
return "pbwcacheorder.txt";
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.appmanager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
|
||||
public class AppManagerFragmentInstalledApps extends AbstractAppManagerFragment {
|
||||
@Override
|
||||
protected void refreshList() {
|
||||
appList.clear();
|
||||
ArrayList uuids = AppManagerActivity.getUuidsFromFile(getSortFilename());
|
||||
if (uuids.isEmpty()) {
|
||||
appList.addAll(getSystemApps());
|
||||
for (GBDeviceApp gbDeviceApp : appList) {
|
||||
uuids.add(gbDeviceApp.getUUID());
|
||||
}
|
||||
AppManagerActivity.rewriteAppOrderFile(getSortFilename(), uuids);
|
||||
} else {
|
||||
appList.addAll(getCachedApps(uuids));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSortFilename() {
|
||||
return mGBDevice.getAddress() + ".watchapps";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangedAppOrder() {
|
||||
super.onChangedAppOrder();
|
||||
sendOrderToDevice(mGBDevice.getAddress() + ".watchfaces");
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.appmanager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
|
||||
public class AppManagerFragmentInstalledWatchfaces extends AbstractAppManagerFragment {
|
||||
@Override
|
||||
protected void refreshList() {
|
||||
appList.clear();
|
||||
ArrayList uuids = AppManagerActivity.getUuidsFromFile(getSortFilename());
|
||||
if (uuids.isEmpty()) {
|
||||
appList.addAll(getSystemWatchfaces());
|
||||
for (GBDeviceApp gbDeviceApp : appList) {
|
||||
uuids.add(gbDeviceApp.getUUID());
|
||||
}
|
||||
AppManagerActivity.rewriteAppOrderFile(getSortFilename(), uuids);
|
||||
} else {
|
||||
appList.addAll(getCachedApps(uuids));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSortFilename() {
|
||||
return mGBDevice.getAddress() + ".watchfaces";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChangedAppOrder() {
|
||||
super.onChangedAppOrder();
|
||||
sendOrderToDevice(mGBDevice.getAddress() + ".watchapps");
|
||||
}
|
||||
}
|
@ -4,69 +4,102 @@ import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
import com.woxthebox.draglistview.DragItemAdapter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
|
||||
/**
|
||||
* Adapter for displaying GBDeviceApp instances.
|
||||
*/
|
||||
public class GBDeviceAppAdapter extends ArrayAdapter<GBDeviceApp> {
|
||||
|
||||
private final Context context;
|
||||
public class GBDeviceAppAdapter extends DragItemAdapter<GBDeviceApp, GBDeviceAppAdapter.ViewHolder> {
|
||||
|
||||
public GBDeviceAppAdapter(Context context, List<GBDeviceApp> appList) {
|
||||
super(context, 0, appList);
|
||||
private final int mLayoutId;
|
||||
private final int mGrabHandleId;
|
||||
private final Context mContext;
|
||||
private final AbstractAppManagerFragment mParentFragment;
|
||||
|
||||
this.context = context;
|
||||
public GBDeviceAppAdapter(List<GBDeviceApp> list, int layoutId, int grabHandleId, Context context, AbstractAppManagerFragment parentFragment) {
|
||||
super(true); // longpress
|
||||
mLayoutId = layoutId;
|
||||
mGrabHandleId = grabHandleId;
|
||||
mContext = context;
|
||||
mParentFragment = parentFragment;
|
||||
setHasStableIds(true);
|
||||
setItemList(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup parent) {
|
||||
GBDeviceApp deviceApp = getItem(position);
|
||||
public long getItemId(int position) {
|
||||
return mItemList.get(position).getUUID().getLeastSignificantBits();
|
||||
}
|
||||
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
|
||||
view = inflater.inflate(R.layout.item_with_details, parent, false);
|
||||
}
|
||||
TextView deviceAppVersionAuthorLabel = (TextView) view.findViewById(R.id.item_details);
|
||||
TextView deviceAppNameLabel = (TextView) view.findViewById(R.id.item_name);
|
||||
ImageView deviceImageView = (ImageView) view.findViewById(R.id.item_image);
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
deviceAppVersionAuthorLabel.setText(getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator()));
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
super.onBindViewHolder(holder, position);
|
||||
GBDeviceApp deviceApp = mItemList.get(position);
|
||||
|
||||
|
||||
holder.mDeviceAppVersionAuthorLabel.setText(GBApplication.getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator()));
|
||||
// FIXME: replace with small icons
|
||||
String appNameLabelText = deviceApp.getName();
|
||||
if (deviceApp.isInCache() || deviceApp.isOnDevice()) {
|
||||
appNameLabelText += " (" + (deviceApp.isInCache() ? "C" : "")
|
||||
+ (deviceApp.isOnDevice() ? "D" : "") + ")";
|
||||
}
|
||||
deviceAppNameLabel.setText(appNameLabelText);
|
||||
holder.mDeviceAppNameLabel.setText(appNameLabelText);
|
||||
|
||||
switch (deviceApp.getType()) {
|
||||
case APP_GENERIC:
|
||||
deviceImageView.setImageResource(R.drawable.ic_watchapp);
|
||||
holder.mDeviceImageView.setImageResource(R.drawable.ic_watchapp);
|
||||
break;
|
||||
case APP_ACTIVITYTRACKER:
|
||||
deviceImageView.setImageResource(R.drawable.ic_activitytracker);
|
||||
holder.mDeviceImageView.setImageResource(R.drawable.ic_activitytracker);
|
||||
break;
|
||||
case APP_SYSTEM:
|
||||
deviceImageView.setImageResource(R.drawable.ic_systemapp);
|
||||
holder.mDeviceImageView.setImageResource(R.drawable.ic_systemapp);
|
||||
break;
|
||||
case WATCHFACE:
|
||||
deviceImageView.setImageResource(R.drawable.ic_watchface);
|
||||
holder.mDeviceImageView.setImageResource(R.drawable.ic_watchface);
|
||||
break;
|
||||
default:
|
||||
deviceImageView.setImageResource(R.drawable.ic_watchapp);
|
||||
holder.mDeviceImageView.setImageResource(R.drawable.ic_watchapp);
|
||||
}
|
||||
}
|
||||
|
||||
public class ViewHolder extends DragItemAdapter<GBDeviceApp, GBDeviceAppAdapter.ViewHolder>.ViewHolder {
|
||||
TextView mDeviceAppVersionAuthorLabel;
|
||||
TextView mDeviceAppNameLabel;
|
||||
ImageView mDeviceImageView;
|
||||
|
||||
public ViewHolder(final View itemView) {
|
||||
super(itemView, mGrabHandleId);
|
||||
mDeviceAppVersionAuthorLabel = (TextView) itemView.findViewById(R.id.item_details);
|
||||
mDeviceAppNameLabel = (TextView) itemView.findViewById(R.id.item_name);
|
||||
mDeviceImageView = (ImageView) itemView.findViewById(R.id.item_image);
|
||||
}
|
||||
|
||||
return view;
|
||||
@Override
|
||||
public void onItemClicked(View view) {
|
||||
UUID uuid = mItemList.get(getAdapterPosition()).getUUID();
|
||||
GBApplication.deviceService().onAppStart(uuid, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClicked(View view) {
|
||||
return mParentFragment.openPopupMenu(view, getAdapterPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import java.io.Writer;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||
@ -135,6 +136,8 @@ public class PBWInstallHandler implements InstallHandler {
|
||||
destDir = new File(FileUtils.getExternalFilesDir() + "/pbw-cache");
|
||||
destDir.mkdirs();
|
||||
FileUtils.copyURItoFile(mContext, mUri, new File(destDir, app.getUUID().toString() + ".pbw"));
|
||||
|
||||
AppManagerActivity.addToAppOrderFile("pbwcacheorder.txt", app.getUUID());
|
||||
} catch (IOException e) {
|
||||
LOG.error("Installation failed: " + e.getMessage(), e);
|
||||
return;
|
||||
@ -174,6 +177,7 @@ public class PBWInstallHandler implements InstallHandler {
|
||||
LOG.error("Failed to open output file: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
|
@ -6,17 +6,14 @@ import android.net.Uri;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AppManagerActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
|
@ -89,6 +89,7 @@ public class GBDeviceApp {
|
||||
public enum Type {
|
||||
UNKNOWN,
|
||||
WATCHFACE,
|
||||
WATCHFACE_SYSTEM,
|
||||
APP_GENERIC,
|
||||
APP_ACTIVITYTRACKER,
|
||||
APP_SYSTEM,
|
||||
|
@ -24,7 +24,7 @@ import java.util.Objects;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AppManagerActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsHost;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||
@ -160,7 +160,7 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
|
||||
Context context = getContext();
|
||||
LOG.info("Got event for APP_INFO");
|
||||
|
||||
Intent appInfoIntent = new Intent(AppManagerActivity.ACTION_REFRESH_APPLIST);
|
||||
Intent appInfoIntent = new Intent(AbstractAppManagerFragment.ACTION_REFRESH_APPLIST);
|
||||
int appCount = appInfoEvent.apps.length;
|
||||
appInfoIntent.putExtra("app_count", appCount);
|
||||
for (Integer i = 0; i < appCount; i++) {
|
||||
|
@ -9,6 +9,7 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelUuid;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
@ -28,6 +29,8 @@ import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement;
|
||||
@ -75,6 +78,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||
private boolean mIsInstalling = false;
|
||||
|
||||
private PBWReader mPBWReader = null;
|
||||
private GBDeviceApp mCurrentlyInstallingApp = null;
|
||||
private int mAppInstallToken = -1;
|
||||
private InputStream mFis = null;
|
||||
private PebbleAppInstallState mInstallState = PebbleAppInstallState.UNKNOWN;
|
||||
@ -613,12 +617,12 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||
*/
|
||||
writeInstallApp(mPebbleProtocol.encodeGetTime());
|
||||
} else {
|
||||
GBDeviceApp app = mPBWReader.getGBDeviceApp();
|
||||
mCurrentlyInstallingApp = mPBWReader.getGBDeviceApp();
|
||||
if (mPebbleProtocol.mFwMajor >= 3 && !mPBWReader.isLanguage()) {
|
||||
if (appId == 0) {
|
||||
// only install metadata - not the binaries
|
||||
write(mPebbleProtocol.encodeInstallMetadata(app.getUUID(), app.getName(), mPBWReader.getAppVersion(), mPBWReader.getSdkVersion(), mPBWReader.getFlags(), mPBWReader.getIconId()));
|
||||
write(mPebbleProtocol.encodeAppStart(app.getUUID(), true));
|
||||
write(mPebbleProtocol.encodeInstallMetadata(mCurrentlyInstallingApp.getUUID(), mCurrentlyInstallingApp.getName(), mPBWReader.getAppVersion(), mPBWReader.getSdkVersion(), mPBWReader.getFlags(), mPBWReader.getIconId()));
|
||||
write(mPebbleProtocol.encodeAppStart(mCurrentlyInstallingApp.getUUID(), true));
|
||||
} else {
|
||||
// this came from an app fetch request, so do the real stuff
|
||||
mIsInstalling = true;
|
||||
@ -637,7 +641,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||
writeInstallApp(mPebbleProtocol.encodeGetTime());
|
||||
} else {
|
||||
mInstallState = PebbleAppInstallState.WAIT_SLOT;
|
||||
writeInstallApp(mPebbleProtocol.encodeAppDelete(app.getUUID()));
|
||||
writeInstallApp(mPebbleProtocol.encodeAppDelete(mCurrentlyInstallingApp.getUUID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -651,6 +655,17 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||
GB.updateInstallNotification(getContext().getString(R.string.installation_failed_), false, 0, getContext());
|
||||
} else {
|
||||
GB.updateInstallNotification(getContext().getString(R.string.installation_successful), false, 0, getContext());
|
||||
String filenameSuffix;
|
||||
if (mCurrentlyInstallingApp != null) {
|
||||
if (mCurrentlyInstallingApp.getType() == GBDeviceApp.Type.WATCHFACE) {
|
||||
filenameSuffix = ".watchfaces";
|
||||
} else {
|
||||
filenameSuffix = ".watchapps";
|
||||
}
|
||||
AppManagerActivity.addToAppOrderFile(gbDevice.getAddress() + filenameSuffix, mCurrentlyInstallingApp.getUUID());
|
||||
Intent refreshIntent = new Intent(AbstractAppManagerFragment.ACTION_REFRESH_APPLIST);
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(refreshIntent);
|
||||
}
|
||||
}
|
||||
mInstallState = PebbleAppInstallState.UNKNOWN;
|
||||
|
||||
@ -660,6 +675,8 @@ public class PebbleIoThread extends GBDeviceIoThread {
|
||||
|
||||
mPBWReader = null;
|
||||
mIsInstalling = false;
|
||||
mCurrentlyInstallingApp = null;
|
||||
|
||||
if (mFis != null) {
|
||||
try {
|
||||
mFis.close();
|
||||
|
@ -1109,6 +1109,10 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||
}
|
||||
|
||||
public byte[] encodeSetMusicState(byte state, int position, int playRate, byte shuffle, byte repeat) {
|
||||
if (mFwMajor < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte playState;
|
||||
|
||||
switch (state) {
|
||||
@ -1144,7 +1148,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
||||
@Override
|
||||
public byte[] encodeSetMusicInfo(String artist, String album, String track, int duration, int trackCount, int trackNr) {
|
||||
String[] parts = {artist, album, track};
|
||||
if (duration == 0) {
|
||||
if (duration == 0 || mFwMajor < 3) {
|
||||
return encodeMessage(ENDPOINT_MUSICCONTROL, MUSICCONTROL_SETMUSICINFO, 0, parts);
|
||||
} else {
|
||||
// Calculate length first
|
||||
|
@ -1,16 +1,17 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.AppManagerActivity">
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment">
|
||||
|
||||
<ListView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/appListView"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
</RelativeLayout>
|
||||
<com.woxthebox.draglistview.DragListView
|
||||
android:id="@+id/appListView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
</FrameLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
32
app/src/main/res/layout/activity_fragmentappmanager.xml
Normal file
32
app/src/main/res/layout/activity_fragmentappmanager.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<android.widget.RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="0px"
|
||||
android:paddingLeft="0px"
|
||||
android:paddingRight="0px"
|
||||
android:paddingTop="0px"
|
||||
tools:context=".activities.appmanager.AppManagerActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/charts_main_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/appmanager_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activities.appmanager.AppManagerActivity">
|
||||
|
||||
<android.support.v4.view.PagerTabStrip
|
||||
android:id="@+id/charts_pagerTabStrip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom" />
|
||||
</android.support.v4.view.ViewPager>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</android.widget.RelativeLayout>
|
@ -18,8 +18,4 @@
|
||||
<item
|
||||
android:id="@+id/appmanager_app_configure"
|
||||
android:title="@string/app_configure"/>
|
||||
<item
|
||||
android:id="@+id/appmanager_app_move_to_top"
|
||||
android:title="@string/app_move_to_top"/>
|
||||
|
||||
</menu>
|
@ -1,11 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<changelog>
|
||||
<release
|
||||
version="0.10.2"
|
||||
versioncode="55">
|
||||
<change>Pebble: allow to manually paste configuration data for legacy configuration pages
|
||||
</change>
|
||||
<release version="0.10.2" versioncode="55">
|
||||
<change>Pebble: allow to manually paste configuration data for legacy configuration pages</change>
|
||||
<change>Pebble: various improvements to the configuration page</change>
|
||||
<change>Pebble: Suppport FW 4.0-dp1 and Pebble2 emulator (needs recompilation of Gadgetbridge)</change>
|
||||
<change>Pebble: Fix a problem with key events when using the Pebble music player</change>
|
||||
</release>
|
||||
<release version="0.10.1" versioncode="54">
|
||||
<change>Pebble: set extended music info by dissecting notifications on Android 5.0+</change>
|
||||
|
Loading…
Reference in New Issue
Block a user