Use a new GUI for the controlcenter.

The existing logic was mostly ported to the new activity, with the exception of device deletion (and all TODOs).
master
Daniele Gobbetti 2016-10-21 13:01:30 +02:00
parent 04673923b6
commit 371f0ecdd0
25 changed files with 1012 additions and 1 deletions

View File

@ -28,6 +28,7 @@ android {
// note: always bump BOTH versionCode and versionName!
versionName "0.13.4"
versionCode 66
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
@ -64,6 +65,7 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:cardview-v7:23.3.0'
compile 'com.android.support:support-v4:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'com.github.tony19:logback-android-classic:1.1.1-4'

View File

@ -297,7 +297,15 @@
<data android:scheme="gadgetbridge" />
</intent-filter>
</activity>
<activity
android:name=".activities.ControlCenterv2"
android:label="@string/title_activity_controlcenter"
android:theme="@style/GadgetbridgeTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,255 @@
package nodomain.freeyourgadget.gadgetbridge.activities;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import de.cketti.library.changelog.ChangeLog;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAdapterv2;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
//TODO: extend GBActivity, but it requires actionbar that is not available
public class ControlCenterv2 extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private DeviceManager deviceManager;
private ImageView background;
private TextView hintTextView;
private GBDeviceAdapterv2 mGBDeviceAdapter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case GBApplication.ACTION_QUIT:
finish();
break;
case DeviceManager.ACTION_DEVICES_CHANGED:
refreshPairedDevices();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_controlcenterv2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
launchDiscoveryActivity();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.controlcenter_navigation_drawer_open, R.string.controlcenter_navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
//end of material design boilerplate
deviceManager = GBApplication.getDeviceManager();
hintTextView = (TextView) findViewById(R.id.hintTextView);
ListView deviceListView = (ListView) findViewById(R.id.deviceListView);
background = (ImageView) findViewById(R.id.no_items_bg);
final List<GBDevice> deviceList = deviceManager.getDevices();
mGBDeviceAdapter = new GBDeviceAdapterv2(this, deviceList);
deviceListView.setAdapter(this.mGBDeviceAdapter);
deviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View v, int position, long id) {
GBDevice gbDevice = mGBDeviceAdapter.getItem(position);
if (gbDevice.isInitialized()) {
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
Class<? extends Activity> primaryActivity = coordinator.getPrimaryActivity();
if (primaryActivity != null) {
Intent startIntent = new Intent(ControlCenterv2.this, primaryActivity);
startIntent.putExtra(GBDevice.EXTRA_DEVICE, gbDevice);
startActivity(startIntent);
}
} else {
GBApplication.deviceService().connect(gbDevice);
}
}
});
registerForContextMenu(deviceListView);
IntentFilter filterLocal = new IntentFilter();
filterLocal.addAction(GBApplication.ACTION_QUIT);
filterLocal.addAction(DeviceManager.ACTION_DEVICES_CHANGED);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
refreshPairedDevices();
/*
* Ask for permission to intercept notifications on first run.
*/
Prefs prefs = GBApplication.getPrefs();
if (prefs.getBoolean("firstrun", true)) {
prefs.getPreferences().edit().putBoolean("firstrun", false).apply();
Intent enableIntent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
startActivity(enableIntent);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkAndRequestPermissions();
}
ChangeLog cl = new ChangeLog(this);
if (cl.isFirstRun()) {
cl.getLogDialog().show();
}
GBApplication.deviceService().start();
if (GB.isBluetoothEnabled() && deviceList.isEmpty() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
startActivity(new Intent(this, DiscoveryActivity.class));
} else {
GBApplication.deviceService().requestDeviceInfo();
}
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
return true;
case R.id.action_debug:
Intent debugIntent = new Intent(this, DebugActivity.class);
startActivity(debugIntent);
return true;
case R.id.action_db_management:
Intent dbIntent = new Intent(this, DbManagementActivity.class);
startActivity(dbIntent);
return true;
case R.id.action_quit:
GBApplication.quit();
return true;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
private void launchDiscoveryActivity() {
startActivity(new Intent(this, DiscoveryActivity.class));
}
private void refreshPairedDevices() {
List<GBDevice> deviceList = deviceManager.getDevices();
GBDevice connectedDevice = null;
for (GBDevice device : deviceList) {
if (device.isConnected() || device.isConnecting()) {
connectedDevice = device;
break;
}
}
if (deviceList.isEmpty()) {
background.setVisibility(View.VISIBLE);
} else {
background.setVisibility(View.INVISIBLE);
}
if (connectedDevice != null) {
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(connectedDevice);
hintTextView.setText(coordinator.getTapString());
} else if (!deviceList.isEmpty()) {
hintTextView.setText(R.string.tap_a_device_to_connect);
}
mGBDeviceAdapter.notifyDataSetChanged();
}
@TargetApi(Build.VERSION_CODES.M)
private void checkAndRequestPermissions() {
List<String> wantedPermissions = new ArrayList<>();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.BLUETOOTH);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.BLUETOOTH_ADMIN);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.READ_CONTACTS);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.CALL_PHONE);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.READ_PHONE_STATE);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.PROCESS_OUTGOING_CALLS) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.READ_SMS);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.SEND_SMS);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED)
wantedPermissions.add(Manifest.permission.READ_CALENDAR);
if (ContextCompat.checkSelfPermission(this, "com.fsck.k9.permission.READ_MESSAGES") == PackageManager.PERMISSION_DENIED)
wantedPermissions.add("com.fsck.k9.permission.READ_MESSAGES");
if (!wantedPermissions.isEmpty())
ActivityCompat.requestPermissions(this, wantedPermissions.toArray(new String[wantedPermissions.size()]), 0);
}
}

View File

@ -0,0 +1,270 @@
package nodomain.freeyourgadget.gadgetbridge.adapter;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.Collections;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
/**
* Adapter for displaying GBDevice instances.
*/
public class GBDeviceAdapterv2 extends ArrayAdapter<GBDevice> {
private final Context context;
private DeviceCoordinator coordinator;
public GBDeviceAdapterv2(Context context, List<GBDevice> deviceList) {
super(context, 0, deviceList);
this.context = context;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
final GBDevice device = getItem(position);
coordinator = DeviceHelper.getInstance().getCoordinator(device);
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.device_itemv2, parent, false);
}
TextView deviceStatusLabel = (TextView) view.findViewById(R.id.device_status);
TextView deviceNameLabel = (TextView) view.findViewById(R.id.device_name);
TextView batteryStatusLabel = (TextView) view.findViewById(R.id.battery_status);
final ImageView deviceImageView = (ImageView) view.findViewById(R.id.device_image);
ProgressBar busyIndicator = (ProgressBar) view.findViewById(R.id.device_busy_indicator);
deviceNameLabel.setText(getUniqueDeviceName(device));
if (device.isBusy()) {
deviceStatusLabel.setText(device.getBusyTask());
busyIndicator.setVisibility(View.VISIBLE);
} else {
deviceStatusLabel.setText(device.getStateString());
busyIndicator.setVisibility(View.INVISIBLE);
}
//begin of action row
//battery
LinearLayout batteryStatusBox = (LinearLayout) view.findViewById(R.id.device_battery_status_box);
batteryStatusBox.setVisibility(View.GONE);
ImageView batteryIcon = (ImageView) view.findViewById(R.id.device_battery_status);
short batteryLevel = device.getBatteryLevel();
if (batteryLevel != GBDevice.BATTERY_UNKNOWN) {
batteryStatusBox.setVisibility(View.VISIBLE);
batteryStatusLabel.setText(device.getBatteryLevel() + "%");
BatteryState batteryState = device.getBatteryState();
if (BatteryState.BATTERY_LOW.equals(batteryState)) {
//batteryIcon.setImageTintMode(olor.RED);
} else {
batteryStatusLabel.setTextColor(ContextCompat.getColor(getContext(), R.color.secondarytext));
if (BatteryState.BATTERY_CHARGING.equals(batteryState) ||
BatteryState.BATTERY_CHARGING_FULL.equals(batteryState)) {
batteryStatusLabel.append(" CHG");
}
}
}
//fetch activity data
ImageView fetchActivityData = (ImageView) view.findViewById(R.id.device_action_fetch_activity);
LinearLayout fetchActivityDataBox = (LinearLayout) view.findViewById(R.id.device_action_fetch_activity_box);
fetchActivityDataBox.setVisibility((device.isConnected() && coordinator.supportsActivityDataFetching()) ? View.VISIBLE : View.GONE);
fetchActivityData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GBApplication.deviceService().onFetchActivityData();
}
}
);
//take screenshot
ImageView takeScreenshotView = (ImageView) view.findViewById(R.id.device_action_take_screenshot);
takeScreenshotView.setVisibility((device.isConnected() && coordinator.supportsScreenshots()) ? View.VISIBLE : View.GONE);
takeScreenshotView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GBApplication.deviceService().onScreenshotReq();
}
}
);
//set alarms
ImageView setAlarmsView = (ImageView) view.findViewById(R.id.device_action_set_alarms);
setAlarmsView.setVisibility(coordinator.supportsAlarmConfiguration() ? View.VISIBLE : View.GONE);
setAlarmsView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent startIntent;
startIntent = new Intent(context, ConfigureAlarms.class);
context.startActivity(startIntent);
}
}
);
//show graphs
ImageView showActivityGraphs = (ImageView) view.findViewById(R.id.device_action_show_activity_graphs);
showActivityGraphs.setVisibility(coordinator.supportsActivityTracking() ? View.VISIBLE : View.GONE);
showActivityGraphs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent startIntent;
startIntent = new Intent(context, ChartsActivity.class);
startIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
context.startActivity(startIntent); }
}
);
//Info icon is last in the row
ImageView deviceInfoView = (ImageView) view.findViewById(R.id.device_info_image);
final RelativeLayout deviceInfoBox = (RelativeLayout) view.findViewById(R.id.device_item_infos_box);
final ListView deviceInfoList = (ListView) view.findViewById(R.id.device_item_infos);
//TODO: can we spare all these additional layouts? find out more.
ItemWithDetailsAdapter infoAdapter = new ItemWithDetailsAdapter(context, device.getDeviceInfos());
infoAdapter.setHorizontalAlignment(true);
deviceInfoList.setAdapter(infoAdapter);
boolean showInfoIcon = device.hasDeviceInfos() && !device.isBusy();
deviceInfoView.setVisibility(showInfoIcon ? View.VISIBLE : View.GONE);
deviceInfoView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (deviceInfoBox.getVisibility() == View.VISIBLE) {
deviceInfoBox.setVisibility(View.GONE);
} else {
ArrayAdapter adapter = (ArrayAdapter) deviceInfoList.getAdapter();
adapter.clear();
List<ItemWithDetails> infos = device.getDeviceInfos();
Collections.sort(infos);
adapter.addAll(infos);
justifyListViewHeightBasedOnChildren(deviceInfoList);
deviceInfoBox.setVisibility(View.VISIBLE);
deviceInfoBox.setFocusable(false);
}
}
});
//remove device, hidden under details
ImageView removeDevice = (ImageView) view.findViewById(R.id.device_action_remove);
removeDevice.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//TODO: the logic is bolted to controlcenter, but I don't think it belongs here
}
}
);
switch (device.getType()) {
case PEBBLE:
if (device.isConnected()) {
deviceImageView.setImageResource(R.drawable.ic_device_pebble);
} else {
deviceImageView.setImageResource(R.drawable.ic_device_pebble_disabled);
}
break;
case MIBAND:
case MIBAND2:
if (device.isConnected()) {
deviceImageView.setImageResource(R.drawable.ic_device_miband);
} else {
deviceImageView.setImageResource(R.drawable.ic_device_miband_disabled);
}
break;
case VIBRATISSIMO:
if (device.isConnected()) {
deviceImageView.setImageResource(R.drawable.ic_device_lovetoy);
} else {
deviceImageView.setImageResource(R.drawable.ic_device_lovetoy_disabled);
}
break;
default:
if (device.isConnected()) {
deviceImageView.setImageResource(R.drawable.ic_launcher);
} else {
deviceImageView.setImageResource(R.drawable.ic_device_default_disabled);
}
}
return view;
}
public void justifyListViewHeightBasedOnChildren(ListView listView) {
ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter();
if (adapter == null) {
return;
}
ViewGroup vg = listView;
int totalHeight = 0;
for (int i = 0; i < adapter.getCount(); i++) {
View listItem = adapter.getView(i, null, vg);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams par = listView.getLayoutParams();
par.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1));
listView.setLayoutParams(par);
listView.requestLayout();
}
private String getUniqueDeviceName(GBDevice device) {
String deviceName = device.getName();
if (!isUniqueDeviceName(device, deviceName)) {
if (device.getModel() != null) {
deviceName = deviceName + " " + device.getModel();
if (!isUniqueDeviceName(device, deviceName)) {
deviceName = deviceName + " " + device.getShortAddress();
}
} else {
deviceName = deviceName + " " + device.getShortAddress();
}
}
return deviceName;
}
private boolean isUniqueDeviceName(GBDevice device, String deviceName) {
for (int i = 0; i < getCount(); i++) {
GBDevice item = getItem(i);
if (item == device) {
continue;
}
if (deviceName.equals(item.getName())) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,20h4L14,4h-4v16zM4,20h4v-8L4,12v8zM16,9v11h4L20,9h-4z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M11.5,9C10.12,9 9,10.12 9,11.5s1.12,2.5 2.5,2.5 2.5,-1.12 2.5,-2.5S12.88,9 11.5,9zM20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM16.79,18.21l-2.91,-2.91c-0.69,0.44 -1.51,0.7 -2.39,0.7C9.01,16 7,13.99 7,11.5S9.01,7 11.5,7 16,9.01 16,11.5c0,0.88 -0.26,1.69 -0.7,2.39l2.91,2.9 -1.42,1.42z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,6h18L21,4L3,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h4v-2L3,18L3,6zM13,12L9,12v1.78c-0.61,0.55 -1,1.33 -1,2.22s0.39,1.67 1,2.22L9,20h4v-1.78c0.61,-0.55 1,-1.34 1,-2.22s-0.39,-1.67 -1,-2.22L13,12zM11,17.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM22,8h-6c-0.5,0 -1,0.5 -1,1v10c0,0.5 0.5,1 1,1h6c0.5,0 1,-0.5 1,-1L23,9c0,-0.5 -0.5,-1 -1,-1zM21,18h-4v-8h4v8z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M22,5.7l-4.6,-3.9 -1.3,1.5 4.6,3.9L22,5.7zM7.9,3.4L6.6,1.9 2,5.7l1.3,1.5 4.6,-3.8zM12.5,8L11,8v6l4.7,2.9 0.8,-1.2 -4,-2.4L12.5,8zM12,4c-5,0 -9,4 -9,9s4,9 9,9 9,-4 9,-9 -4,-9 -9,-9zM12,20c-3.9,0 -7,-3.1 -7,-7s3.1,-7 7,-7 7,3.1 7,7 -3.1,7 -7,7z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M13,3h-2v10h2L13,3zM17.83,5.17l-1.42,1.42C17.99,7.86 19,9.81 19,12c0,3.87 -3.13,7 -7,7s-7,-3.13 -7,-7c0,-2.19 1.01,-4.14 2.58,-5.42L6.17,5.17C4.23,6.82 3,9.26 3,12c0,4.97 4.03,9 9,9s9,-4.03 9,-9c0,-2.74 -1.23,-5.18 -3.17,-6.83z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M4,4h7L11,2L4,2c-1.1,0 -2,0.9 -2,2v7h2L4,4zM10,13l-4,5h12l-3,-4 -2.03,2.71L10,13zM17,8.5c0,-0.83 -0.67,-1.5 -1.5,-1.5S14,7.67 14,8.5s0.67,1.5 1.5,1.5S17,9.33 17,8.5zM20,2h-7v2h7v7h2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,20h-7v2h7c1.1,0 2,-0.9 2,-2v-7h-2v7zM4,13L2,13v7c0,1.1 0.9,2 2,2h7v-2L4,20v-7z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
</vector>

View File

@ -0,0 +1,9 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="135"
android:centerColor="@color/primary_light"
android:endColor="@color/primary_light"
android:startColor="@color/primary_dark"
android:type="linear" />
</shape>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/activity_controlcenterv2_app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_controlcenterv2_main_drawer" />
</android.support.v4.widget.DrawerLayout>

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/GadgetbridgeTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/GadgetbridgeTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/activity_controlcenterv2_content_main" />
<TextView
android:id="@+id/hintTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/secondarytext"
android:textStyle="italic"
android:text="@string/tap_connected_device_for_app_mananger"
android:elevation="0dp" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_gravity="bottom|end"
android:src="@drawable/ic_add_white"
app:elevation="6dp"
app:pressedTranslationZ="12dp"
android:layout_marginBottom="30dp"
android:layout_marginRight="10dp"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2"
tools:showIn="@layout/activity_controlcenterv2_app_bar_main">
<ImageView
android:id="@+id/no_items_bg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/gadgetbridge_img" />
<ListView
android:id="@+id/deviceListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:paddingBottom="64dp"
android:divider="@null" />
</RelativeLayout>

View File

@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
card_view:contentPadding="16dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/device_image"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="left|top"
android:contentDescription="@string/candidate_item_device_image"
tools:src="@drawable/ic_device_pebble" />
<TextView
android:id="@+id/device_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/device_image"
android:gravity="center"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
tools:text="My Pebble Watch" />
<TextView
android:id="@+id/device_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/device_name"
android:layout_toRightOf="@id/device_image"
android:gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
tools:text="@string/connecting" />
<LinearLayout
android:id="@+id/device_battery_status_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/device_image"
android:layout_marginBottom="8dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:minWidth="36dp"
android:orientation="vertical">
<ImageView
android:id="@+id/device_battery_status"
android:layout_width="match_parent"
android:layout_height="36dp"
card_view:srcCompat="@drawable/ic_battery" />
<TextView
android:id="@+id/battery_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/secondarytext"
android:textStyle="bold"
tools:text="100% CHG" />
</LinearLayout>
<LinearLayout
android:id="@+id/device_action_fetch_activity_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_toRightOf="@id/device_battery_status_box"
android:gravity="center_vertical"
android:minWidth="36dp"
android:orientation="vertical">
<ImageView
android:id="@+id/device_action_fetch_activity"
android:layout_width="36dp"
android:layout_height="36dp"
android:clickable="true"
android:contentDescription="@string/controlcenter_fetch_activity_data"
card_view:srcCompat="@drawable/ic_action_fetch_activity_data" />
<ProgressBar
android:id="@+id/device_busy_indicator"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="4dp"
android:indeterminate="true"
android:visibility="visible"
tools:visibility="visible" />
</LinearLayout>
<ImageView
android:id="@+id/device_action_take_screenshot"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_toRightOf="@id/device_action_fetch_activity_box"
android:clickable="true"
android:contentDescription="@string/controlcenter_take_screenshot"
card_view:srcCompat="@drawable/ic_screenshot" />
<ImageView
android:id="@+id/device_action_set_alarms"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_toRightOf="@id/device_action_take_screenshot"
android:clickable="true"
android:contentDescription="@string/controlcenter_start_configure_alarms"
card_view:srcCompat="@drawable/ic_device_set_alarms" />
<ImageView
android:id="@+id/device_action_show_activity_graphs"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_toRightOf="@id/device_action_set_alarms"
android:clickable="true"
card_view:srcCompat="@drawable/ic_activity_graphs" />
<ImageView
android:id="@+id/device_info_image"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_alignParentRight="true"
android:layout_below="@id/device_image"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="0dp"
android:layout_marginTop="8dp"
android:clickable="true"
android:contentDescription="@string/candidate_item_device_image"
android:src="@drawable/ic_information_outline_grey600_24dp" />
<RelativeLayout
android:id="@+id/device_item_infos_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="@id/device_info_image"
android:layout_marginTop="8dp"
android:visibility="gone">
<!--TODO: set width-->
<ListView
android:id="@+id/device_item_infos"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true" />
<ImageView
android:id="@+id/device_action_remove"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_alignParentRight="true"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="0dp"
android:layout_marginTop="8dp"
android:clickable="true"
card_view:srcCompat="@drawable/ic_remove_device" />
</RelativeLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@drawable/ic_launcher" />
<!-- TODO: make visible when we support multiple users -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:text="User 1"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:visibility="gone" />
</LinearLayout>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:icon="@drawable/ic_settings" />
<item android:id="@+id/action_debug"
android:title="@string/action_debug"
android:icon="@drawable/ic_debug" />
<item android:id="@+id/action_db_management"
android:title="@string/action_db_management"
android:icon="@drawable/ic_database_management" />
<item android:id="@+id/action_quit"
android:title="@string/action_quit"
android:icon="@drawable/ic_quit" />
</group>
</menu>

View File

@ -0,0 +1,9 @@
<resources>
<style name="GadgetbridgeTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
</resources>

View File

@ -8,4 +8,8 @@ Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="widget_margin">8dp</dimen>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="nav_header_vertical_spacing">16dp</dimen>
<dimen name="nav_header_height">160dp</dimen>
<dimen name="fab_margin">16dp</dimen>
</resources>

View File

@ -14,6 +14,8 @@
<string name="controlcenter_delete_device">Delete Device</string>
<string name="controlcenter_delete_device_name">Delete %1$s</string>
<string name="controlcenter_delete_device_dialogmessage">This will delete the device and all associated data!</string>
<string name="controlcenter_navigation_drawer_open">Open navigation drawer</string>
<string name="controlcenter_navigation_drawer_close">Close navigation drawer</string>
<string name="title_activity_debug">Debug</string>

View File

@ -26,4 +26,13 @@
<item name="chart_activity">@color/chart_activity_dark</item>
-->
</style>
<style name="GadgetbridgeTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="GadgetbridgeTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="GadgetbridgeTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>