1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-25 18:15:49 +01:00

Merge branch 'master' into background-javascript

# Conflicts:
#	app/src/main/assets/app_config/js/gadgetbridge_boilerplate.js
#	app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java
#	app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java
This commit is contained in:
Daniele Gobbetti 2017-04-08 21:16:01 +02:00
commit 5c0c5581bb
91 changed files with 1517 additions and 804 deletions

View File

@ -1,3 +1,7 @@
#### Before opening an issue please confirm the following:
- [ ] I have read the [wiki](https://github.com/Freeyourgadget/Gadgetbridge/wiki), and I didn't find a solution to my problem / an answer to my question.
- [ ] I have searched the [issues](https://github.com/Freeyourgadget/Gadgetbridge/issues), and I didn't find a solution to my problem / an answer to my question.
#### Your issue is:
*In case of a bug, do not forget to attach logs!*
@ -8,3 +12,7 @@
#### Your android version is:
#### Your Gadgetbridge version is:
*New issues about already solved/documented topics could be closed without further comments. Same for too generic or incomplete reports.*

View File

@ -1,5 +1,26 @@
###Changelog
###Version next
* Applied some material design guidelines to Charts and (pebble) app management
* Pebble: improve compatiblity with watchapp configuration pages
###Version 0.18.4
* Mi Band 2: Display realtime steps in Live Activity
* Mi Band: Attempt to recognize Mi Band model with hwVersion = 8
* Alarms activity improvements and fixes
* Make Buttons in the main activity easier to hit
###Version 0.18.3
* Fix bug that caused the same value in weekly charts for every day on Android 6 and older
###Version 0.18.2
* Mi Band 2: Fix crash on "chat" or "social network" text notification (#603)
###Version 0.18.1
* Pebble: Fix Firmware insstallation on Pebble Time Round (broken since 0.16.0)
* Start VibrationActivity when using "find device" button with Vibratissimo
* Support material fork of K9
###Version 0.18.0
* All new GUI for the control center
* Add Portuguese pt_PT and pt_BR translations
@ -10,10 +31,10 @@
* Huge speedup for weekly charts when changing days
* Drop support for importing pre Gadgetbridge 0.12.0 database
* Pebble: allow configuration web pages (clay) to access device location
* Mi2: Initial support for text notifications, caller ID, and icons (requires font installation) (#560)
* Mi2: Support for flashing Mili_pro.ft* font files
* Mi2: Improved firmware/font updated
* Mi2: Set 12h/24h time format, following the Android configuration (#573)
* Mi Band 2: Initial support for text notifications, caller ID, and icons (requires font installation) (#560)
* Mi Band 2: Support for flashing Mili_pro.ft* font files
* Mi Band 2: Improved firmware/font updated
* Mi Band 2: Set 12h/24h time format, following the Android configuration (#573)
* Improved BLE discovery and connectivity
####Version 0.17.5

View File

@ -14,13 +14,13 @@ need to create an account and transmit any of your data to the vendor's servers.
[List of changes](CHANGELOG.md)
## Supported Devices
* Pebble, Pebble Steel, Pebble Time, Pebble Time Steel, Pebble Time Round
* Pebble 2, Pebble Time 2 (experimental, PAIR WITHIN GADGETBRIDGE)
* Mi Band, Mi Band 1A, Mi Band 1S
* Mi Band 2
* Pebble, Pebble Steel, Pebble Time, Pebble Time Steel, Pebble Time Round [Wiki section about this device](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Pebble)
* Pebble 2, Pebble Time 2 (experimental, PAIR WITHIN GADGETBRIDGE) [Wiki section about pebble](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Pebble), most parts apply to Pebble 2 as well
* Mi Band, Mi Band 1A, Mi Band 1S [Wiki section about this device](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Mi-Band)
* Mi Band 2 [Wiki section about mi band](https://github.com/Freeyourgadget/Gadgetbridge/wiki/Mi-Band), some parts apply to mi band 2 as well
* Vibratissimo (experimental)
* Liveview
* HPlus Devices (e.g. ZeBand)
* HPlus Devices (e.g. ZeBand) [Wiki section about this device](https://github.com/Freeyourgadget/Gadgetbridge/wiki/HPlus)
## Features (Pebble)

View File

@ -26,8 +26,8 @@ android {
targetSdkVersion 25
// note: always bump BOTH versionCode and versionName!
versionName "0.18.0"
versionCode 87
versionName "0.18.4"
versionCode 91
vectorDrawables.useSupportLibrary = true
}
buildTypes {
@ -64,19 +64,18 @@ dependencies {
testCompile "org.robolectric:robolectric:3.2.2"
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support:cardview-v7:25.2.0'
compile 'com.android.support:recyclerview-v7:25.2.0'
compile 'com.android.support:support-v4:25.2.0'
compile 'com.android.support:design:25.2.0'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.github.tony19:logback-android-classic:1.1.1-4'
compile 'org.slf4j:slf4j-api:1.7.7'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.1'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
compile 'com.github.pfichtner:durationformatter:0.1.1'
compile 'de.cketti.library.changelog:ckchangelog:1.2.2'
compile 'net.e175.klaus:solarpositioning:0.0.9'
compile 'com.github.freeyourgadget:greendao:1998d7cd2d21f662c6044f6ccf3b3a251bbad341'
compile 'com.github.woxthebox:draglistview:1.2.9'
compile 'org.apache.commons:commons-lang3:3.4'
// compile project(":DaoCore")

View File

@ -341,6 +341,7 @@
<activity
android:name=".activities.AlarmDetails"
android:label="@string/title_activity_alarm_details"
android:screenOrientation="portrait"
android:parentActivityName=".activities.ConfigureAlarms" />
<activity
android:name=".activities.VibrationActivity"

View File

@ -1,5 +1,14 @@
navigator.geolocation.getCurrentPosition = function(success, failure) { //override because default implementation requires GPS permission
success(JSON.parse(GBjs.getCurrentPosition()))
var reportedPositionFailures = 0;
navigator.geolocation.getCurrentPosition = function(success, failure, options) { //override because default implementation requires GPS permission
geoposition = JSON.parse(GBjs.getCurrentPosition());
if(options && options.maximumAge && (geoposition.timestamp < Date.now() - options.maximumAge) && reportedPositionFailures <= 10 ) {
reportedPositionFailures++;
failure({ code: 2, message: "POSITION_UNAVAILABLE"});
} else {
reportedPositionFailures = 0;
success(geoposition);
}
}
if (window.Storage){
@ -205,7 +214,7 @@ var storedPreset = GBjs.getAppStoredPreset();
document.addEventListener('DOMContentLoaded', function(){
if (jsConfigFile != null) {
loadScript(jsConfigFile, function() {
Pebble.evaluate('ready');
Pebble.evaluate('ready', [{'type': "ready"}]); //callback object apparently needed by some watchfaces
if(document.hasFocus() && !(getURLVariable('config') == 'true')) {
Pebble.evaluate('showConfiguration');
} else {

View File

@ -445,7 +445,7 @@ public class GBApplication extends Application {
public static int getTextColor(Context context) {
TypedValue typedValue = new TypedValue();
Resources.Theme theme = context.getTheme();
theme.resolveAttribute(android.R.attr.textColorPrimary, typedValue, true);
theme.resolveAttribute(R.attr.textColorPrimary, typedValue, true);
return typedValue.data;
}

View File

@ -18,7 +18,6 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
/**
* Abstract base class for fragments. Provides hooks that are called when
@ -28,7 +27,7 @@ import android.support.v4.app.FragmentActivity;
* @see AbstractGBFragmentActivity
*/
public abstract class AbstractGBFragment extends Fragment {
private boolean mVisibleInactivity;
private boolean mVisibleInActivity;
/**
* Called when this fragment has been fully scrolled into the activity.
@ -37,7 +36,6 @@ public abstract class AbstractGBFragment extends Fragment {
* @see #onMadeInvisibleInActivity()
*/
protected void onMadeVisibleInActivity() {
updateActivityTitle();
}
/**
@ -47,7 +45,7 @@ public abstract class AbstractGBFragment extends Fragment {
* @see #onMadeVisibleInActivity()
*/
protected void onMadeInvisibleInActivity() {
mVisibleInactivity = false;
mVisibleInActivity = false;
}
/**
@ -55,16 +53,7 @@ public abstract class AbstractGBFragment extends Fragment {
* activity, not taking into account whether the screen is enabled at all.
*/
public boolean isVisibleInActivity() {
return mVisibleInactivity;
}
protected void updateActivityTitle() {
FragmentActivity activity = getActivity();
if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
if (getTitle() != null) {
activity.setTitle(getTitle());
}
}
return mVisibleInActivity;
}
@Nullable
@ -76,7 +65,7 @@ public abstract class AbstractGBFragment extends Fragment {
* @hide
*/
public void onMadeVisibleInActivityInternal() {
mVisibleInactivity = true;
mVisibleInActivity = true;
if (isVisible()) {
onMadeVisibleInActivity();
}

View File

@ -105,7 +105,7 @@ public class AlarmDetails extends GBActivity {
}
private void updateAlarm() {
alarm.setSmartWakeup(cbSmartWakeup.isChecked());
alarm.setSmartWakeup(supportsSmartWakeup() && cbSmartWakeup.isChecked());
alarm.setRepetition(cbMonday.isChecked(), cbTuesday.isChecked(), cbWednesday.isChecked(), cbThursday.isChecked(), cbFriday.isChecked(), cbSaturday.isChecked(), cbSunday.isChecked());
alarm.setHour(timePicker.getCurrentHour());
alarm.setMinute(timePicker.getCurrentMinute());

View File

@ -19,8 +19,9 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.MenuItem;
import android.widget.ListView;
import java.util.Arrays;
import java.util.HashSet;
@ -64,8 +65,10 @@ public class ConfigureAlarms extends GBActivity {
mGBAlarmListAdapter = new GBAlarmListAdapter(this, preferencesAlarmListSet);
ListView listView = (ListView) findViewById(R.id.alarm_list);
listView.setAdapter(mGBAlarmListAdapter);
RecyclerView alarmsRecyclerView = (RecyclerView) findViewById(R.id.alarm_list);
alarmsRecyclerView.setHasFixedSize(true);
alarmsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
alarmsRecyclerView.setAdapter(mGBAlarmListAdapter);
updateAlarmsFromPrefs();
}

View File

@ -250,15 +250,6 @@ public class ControlCenterv2 extends AppCompatActivity
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 {

View File

@ -20,8 +20,10 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.view.MenuItem;
import android.view.View;
@ -33,6 +35,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
@ -40,10 +43,13 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.ImportExportSharedPreferences;
public class DbManagementActivity extends GBActivity {
private static final Logger LOG = LoggerFactory.getLogger(DbManagementActivity.class);
private static SharedPreferences sharedPrefs;
private ImportExportSharedPreferences shared_file = new ImportExportSharedPreferences();
private Button exportDBButton;
private Button importDBButton;
@ -95,6 +101,8 @@ public class DbManagementActivity extends GBActivity {
deleteActivityDatabase();
}
});
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
}
private boolean hasOldActivityDatabase() {
@ -110,8 +118,33 @@ public class DbManagementActivity extends GBActivity {
return getString(R.string.dbmanagementactivvity_cannot_access_export_path);
}
private void exportShared() {
// BEGIN EXAMPLE
File myPath = null;
try {
myPath = FileUtils.getExternalFilesDir();
File myFile = new File(myPath, "Export_preference");
shared_file.exportToFile(sharedPrefs,myFile,null);
} catch (IOException ex) {
GB.toast(this, getString(R.string.dbmanagementactivity_error_exporting_shared, ex.getMessage()), Toast.LENGTH_LONG, GB.ERROR, ex);
}
}
private void importShared() {
// BEGIN EXAMPLE
File myPath = null;
try {
myPath = FileUtils.getExternalFilesDir();
File myFile = new File(myPath, "Export_preference");
shared_file.importFromFile(sharedPrefs,myFile );
} catch (Exception ex) {
GB.toast(DbManagementActivity.this, getString(R.string.dbmanagementactivity_error_importing_db, ex.getMessage()), Toast.LENGTH_LONG, GB.ERROR, ex);
}
}
private void exportDB() {
try (DBHandler dbHandler = GBApplication.acquireDB()) {
exportShared();
DBHelper helper = new DBHelper(this);
File dir = FileUtils.getExternalFilesDir();
File destFile = helper.exportDB(dbHandler, dir);
@ -130,6 +163,7 @@ public class DbManagementActivity extends GBActivity {
@Override
public void onClick(DialogInterface dialog, int which) {
try (DBHandler dbHandler = GBApplication.acquireDB()) {
importShared();
DBHelper helper = new DBHelper(DbManagementActivity.this);
File dir = FileUtils.getExternalFilesDir();
SQLiteOpenHelper sqLiteOpenHelper = dbHandler.getHelper();

View File

@ -20,6 +20,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
@ -30,6 +31,7 @@ import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
@ -123,7 +125,7 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC
}
case BluetoothDevice.ACTION_BOND_STATE_CHANGED: {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device != null && device.getAddress().equals(bondingAddress)) {
if (device != null && bondingDevice != null && device.getAddress().equals(bondingDevice.getMacAddress())) {
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
if (bondState == BluetoothDevice.BOND_BONDED) {
handleDeviceBonded();
@ -134,11 +136,57 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC
}
};
private void handleDeviceBonded() {
GB.toast(DiscoveryActivity.this, "Successfully bonded with: " + bondingAddress, Toast.LENGTH_SHORT, GB.INFO);
private void connectAndFinish(GBDevice device) {
GB.toast(DiscoveryActivity.this, getString(R.string.discovery_trying_to_connect_to, device.getName()), Toast.LENGTH_SHORT, GB.INFO);
GBApplication.deviceService().connect(device, true);
finish();
}
private void createBond(final GBDeviceCandidate deviceCandidate, int bondingStyle) {
if (bondingStyle == DeviceCoordinator.BONDING_STYLE_NONE) {
return;
}
if (bondingStyle == DeviceCoordinator.BONDING_STYLE_ASK) {
new AlertDialog.Builder(this)
.setCancelable(true)
.setTitle(DiscoveryActivity.this.getString(R.string.discovery_pair_title, deviceCandidate.getName()))
.setMessage(DiscoveryActivity.this.getString(R.string.discovery_pair_question))
.setPositiveButton(DiscoveryActivity.this.getString(R.string.discovery_yes_pair), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
doCreatePair(deviceCandidate);
}
})
.setNegativeButton(R.string.discovery_dont_pair, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
GBDevice device = DeviceHelper.getInstance().toSupportedDevice(deviceCandidate);
connectAndFinish(device);
}
})
.show();
} else {
doCreatePair(deviceCandidate);
}
}
private void doCreatePair(GBDeviceCandidate deviceCandidate) {
GB.toast(DiscoveryActivity.this, getString(R.string.discovery_attempting_to_pair, deviceCandidate.getName()), Toast.LENGTH_SHORT, GB.INFO);
if (deviceCandidate.getDevice().createBond()) {
// async, wait for bonding event to finish this activity
LOG.info("Bonding in progress...");
bondingDevice = deviceCandidate;
} else {
GB.toast(DiscoveryActivity.this, getString(R.string.discovery_bonding_failed_immediately, deviceCandidate.getName()), Toast.LENGTH_SHORT, GB.ERROR);
}
}
private void handleDeviceBonded() {
GB.toast(DiscoveryActivity.this, getString(R.string.discovery_successfully_bonded, bondingDevice.getName()), Toast.LENGTH_SHORT, GB.INFO);
GBDevice device = DeviceHelper.getInstance().toSupportedDevice(bondingDevice);
connectAndFinish(device);
}
private final BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
@ -203,7 +251,7 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC
private DeviceCandidateAdapter cadidateListAdapter;
private Button startButton;
private Scanning isScanning = Scanning.SCANNING_OFF;
private String bondingAddress;
private GBDeviceCandidate bondingDevice;
private enum Scanning {
SCANNING_BT,
@ -358,7 +406,7 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC
}
} else {
discoveryFinished();
Toast.makeText(this, "Enable Bluetooth to discover devices.", Toast.LENGTH_LONG).show();
GB.toast(DiscoveryActivity.this, getString(R.string.discovery_enable_bluetooth), Toast.LENGTH_SHORT, GB.ERROR);
}
}
@ -535,19 +583,24 @@ public class DiscoveryActivity extends GBActivity implements AdapterView.OnItemC
intent.putExtra(DeviceCoordinator.EXTRA_DEVICE_CANDIDATE, deviceCandidate);
startActivity(intent);
} else {
GBDevice device = DeviceHelper.getInstance().toSupportedDevice(deviceCandidate);
int bondingStyle = coordinator.getBondingStyle(deviceCandidate);
if (bondingStyle == DeviceCoordinator.BONDING_STYLE_NONE) {
LOG.info("No bonding needed, according to coordinator, so connecting right away");
connectAndFinish(device);
return;
}
try {
BluetoothDevice btDevice = adapter.getRemoteDevice(deviceCandidate.getMacAddress());
switch (btDevice.getBondState()) {
case BluetoothDevice.BOND_NONE: {
if (btDevice.createBond()) {
// async, wait for bonding event to finish this activity
bondingAddress = btDevice.getAddress();
}
createBond(deviceCandidate, bondingStyle);
break;
}
case BluetoothDevice.BOND_BONDING:
// async, wait for bonding event to finish this activity
bondingAddress = btDevice.getAddress();
bondingDevice = deviceCandidate;
break;
case BluetoothDevice.BOND_BONDED:
handleDeviceBonded();

View File

@ -24,10 +24,12 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.LinearLayoutManager;
import android.view.HapticFeedbackConstants;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@ -35,8 +37,6 @@ 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;
@ -65,6 +65,8 @@ public abstract class AbstractAppManagerFragment extends Fragment {
= "nodomain.freeyourgadget.gadgetbridge.appmanager.action.refresh_applist";
private static final Logger LOG = LoggerFactory.getLogger(AbstractAppManagerFragment.class);
private ItemTouchHelper appManagementTouchHelper;
protected abstract List<GBDeviceApp> getSystemAppsInCategory();
protected abstract String getSortFilename();
@ -73,9 +75,13 @@ public abstract class AbstractAppManagerFragment extends Fragment {
protected abstract boolean filterApp(GBDeviceApp gbDeviceApp);
public void startDragging(RecyclerView.ViewHolder viewHolder) {
appManagementTouchHelper.startDrag(viewHolder);
}
protected void onChangedAppOrder() {
List<UUID> uuidList = new ArrayList<>();
for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getItemList()) {
for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getAppList()) {
uuidList.add(gbDeviceApp.getUUID());
}
AppManagerActivity.rewriteAppOrderFile(getSortFilename(), uuidList);
@ -134,7 +140,6 @@ public abstract class AbstractAppManagerFragment extends Fragment {
}
};
private DragListView appListView;
protected final List<GBDeviceApp> appList = new ArrayList<>();
private GBDeviceAppAdapter mGBDeviceAppAdapter;
protected GBDevice mGBDevice = null;
@ -238,10 +243,6 @@ public abstract class AbstractAppManagerFragment extends Fragment {
super.onActivityCreated(savedInstanceState);
mGBDevice = ((AppManagerActivity) getActivity()).getGBDevice();
if (PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) < 3 && !isCacheManager()) {
appListView.setDragEnabled(false);
}
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_REFRESH_APPLIST);
@ -260,33 +261,35 @@ public abstract class AbstractAppManagerFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final FloatingActionButton appListFab = ((FloatingActionButton) getActivity().findViewById(R.id.fab));
View rootView = inflater.inflate(R.layout.activity_appmanager, container, false);
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) {
}
RecyclerView appListView = (RecyclerView) (rootView.findViewById(R.id.appListView));
appListView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onItemDragging(int itemPosition, float x, float y) {
}
@Override
public void onItemDragEnded(int fromPosition, int toPosition) {
onChangedAppOrder();
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) {
appListFab.hide();
} else if (dy < 0) {
appListFab.show();
}
}
});
appListView.setLayoutManager(new LinearLayoutManager(getActivity()));
mGBDeviceAppAdapter = new GBDeviceAppAdapter(appList, R.layout.item_with_details_and_drag_handle, this);
appListView.setAdapter(mGBDeviceAppAdapter);
ItemTouchHelper.Callback appItemTouchHelperCallback = new AppItemTouchHelperCallback(mGBDeviceAppAdapter);
appManagementTouchHelper = new ItemTouchHelper(appItemTouchHelperCallback);
appManagementTouchHelper.attachToRecyclerView(appListView);
return rootView;
}
protected void sendOrderToDevice(String concatFilename) {
ArrayList<UUID> uuids = new ArrayList<>();
for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getItemList()) {
for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getAppList()) {
uuids.add(gbDeviceApp.getUUID());
}
if (concatFilename != null) {
@ -296,11 +299,11 @@ public abstract class AbstractAppManagerFragment extends Fragment {
GBApplication.deviceService().onAppReorder(uuids.toArray(new UUID[uuids.size()]));
}
public boolean openPopupMenu(View view, int position) {
public boolean openPopupMenu(View view, GBDeviceApp deviceApp) {
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);
final GBDeviceApp selectedApp = deviceApp;
if (!selectedApp.isInCache()) {
menu.removeItem(R.id.appmanager_app_reinstall);
@ -353,12 +356,11 @@ public abstract class AbstractAppManagerFragment extends Fragment {
}
);
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
popupMenu.show();
return true;
}
public boolean onContextItemSelected(MenuItem item, GBDeviceApp selectedApp) {
private boolean onContextItemSelected(MenuItem item, GBDeviceApp selectedApp) {
switch (item.getItemId()) {
case R.id.appmanager_app_delete_cache:
String baseName;
@ -441,4 +443,46 @@ public abstract class AbstractAppManagerFragment extends Fragment {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mReceiver);
super.onDestroy();
}
public class AppItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final GBDeviceAppAdapter gbDeviceAppAdapter;
public AppItemTouchHelperCallback(GBDeviceAppAdapter gbDeviceAppAdapter) {
this.gbDeviceAppAdapter = gbDeviceAppAdapter;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
//app reordering is not possible on old firmwares
if (PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) < 3 && !isCacheManager()) {
return 0;
}
//we only support up and down movement and only for moving, not for swiping apps away
return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
}
@Override
public boolean isLongPressDragEnabled() {
return false;
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
gbDeviceAppAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
//nothing to do
}
@Override
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
onChangedAppOrder();
}
}
}

View File

@ -154,10 +154,10 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
mIntentFilterActions = new HashSet<>();
if (intentFilterActions != null) {
mIntentFilterActions.addAll(Arrays.asList(intentFilterActions));
mIntentFilterActions.add(ChartsHost.DATE_NEXT);
mIntentFilterActions.add(ChartsHost.DATE_PREV);
mIntentFilterActions.add(ChartsHost.REFRESH);
}
mIntentFilterActions.add(ChartsHost.DATE_NEXT);
mIntentFilterActions.add(ChartsHost.DATE_PREV);
mIntentFilterActions.add(ChartsHost.REFRESH);
}
@Override
@ -182,9 +182,9 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
HEARTRATE_FILL_COLOR = ContextCompat.getColor(getContext(), R.color.chart_heartrate_fill);
getContext().getTheme().resolveAttribute(R.attr.chart_activity, runningColor, true);
AK_ACTIVITY_COLOR = runningColor.data;
getContext().getTheme().resolveAttribute(R.attr.chart_light_sleep, runningColor, true);
AK_DEEP_SLEEP_COLOR = runningColor.data;
getContext().getTheme().resolveAttribute(R.attr.chart_deep_sleep, runningColor, true);
AK_DEEP_SLEEP_COLOR = runningColor.data;
getContext().getTheme().resolveAttribute(R.attr.chart_light_sleep, runningColor, true);
AK_LIGHT_SLEEP_COLOR = runningColor.data;
getContext().getTheme().resolveAttribute(R.attr.chart_not_worn, runningColor, true);
AK_NOT_WORN_COLOR = runningColor.data;
@ -234,7 +234,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment {
}
protected void showDateBar(boolean show) {
getChartsHost().getDateBar().setVisibility(show ? View.VISIBLE : View.GONE);
getChartsHost().getDateBar().setVisibility(show ? View.VISIBLE : View.INVISIBLE);
}
@Override

View File

@ -25,7 +25,6 @@ import android.view.View;
import android.view.ViewGroup;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
@ -81,13 +80,12 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
protected void updateChartsnUIThread(ChartsData chartsData) {
MyChartsData mcd = (MyChartsData) chartsData;
// setupLegend(mWeekChart);
setupLegend(mWeekChart);
mTodayPieChart.setCenterText(mcd.getDayData().centerText);
mTodayPieChart.setData(mcd.getDayData().data);
mWeekChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317
mWeekChart.setData(mcd.getWeekBeforeData().getData());
mWeekChart.getLegend().setEnabled(false);
mWeekChart.getXAxis().setValueFormatter(mcd.getWeekBeforeData().getXValueFormatter());
}
@ -133,23 +131,35 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
ActivityAmounts amounts = getActivityAmountsForDay(db, day, device);
float totalValues[] = getTotalsForActivityAmounts(amounts);
String[] pieLabels = getPieLabels();
float totalValue = 0;
for (float value : totalValues) {
for (int i = 0; i < totalValues.length; i++) {
float value = totalValues[i];
totalValue += value;
entries.add(new PieEntry(value));
entries.add(new PieEntry(value, pieLabels[i]));
}
set.setValueFormatter(getPieValueFormatter());
set.setColors(getColors());
if (totalValue < mTargetValue) {
entries.add(new PieEntry((mTargetValue - totalValue)));
set.addColor(Color.GRAY);
if (totalValues.length < 2) {
if (totalValue < mTargetValue) {
entries.add(new PieEntry((mTargetValue - totalValue)));
set.addColor(Color.GRAY);
}
}
data.setDataSet(set);
//this hides the values (numeric) added to the set. These would be shown aside the strings set with addXValue above
data.setDrawValues(false);
if (totalValues.length < 2) {
data.setDrawValues(false);
}
else {
set.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
set.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
set.setValueTextColor(DESCRIPTION_COLOR);
set.setValueTextSize(13f);
set.setValueFormatter(getPieValueFormatter());
}
return new DayData(data, formatPieValue((int) totalValue));
}
@ -181,11 +191,11 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
private void setupTodayPieChart() {
mTodayPieChart.setBackgroundColor(BACKGROUND_COLOR);
mTodayPieChart.getDescription().setTextColor(DESCRIPTION_COLOR);
mTodayPieChart.setEntryLabelColor(DESCRIPTION_COLOR);
mTodayPieChart.getDescription().setText(getPieDescription(mTargetValue));
// mTodayPieChart.setNoDataTextDescription("");
mTodayPieChart.setNoDataText("");
mTodayPieChart.getLegend().setEnabled(false);
// setupLegend(mTodayPieChart);
}
private void setupWeekChart() {
@ -222,16 +232,6 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
yAxisRight.setTextColor(CHART_TEXT_COLOR);
}
@Override
protected void setupLegend(Chart chart) {
// List<Integer> legendColors = new ArrayList<>(1);
// List<String> legendLabels = new ArrayList<>(1);
// legendColors.add(akActivity.color);
// legendLabels.add(getContext().getString(R.string.chart_steps));
// chart.getLegend().setCustom(legendColors, legendLabels);
// chart.getLegend().setTextColor(LEGEND_TEXT_COLOR);
}
private List<? extends ActivitySample> getSamplesOfDay(DBHandler db, Calendar day, int offsetHours, GBDevice device) {
int startTs;
int endTs;
@ -287,16 +287,17 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
ActivityAmounts amounts = null;
Activity activity = getActivity();
int key = (int) (day.getTimeInMillis() / 1000) + (mOffsetHours * 3600);
if (activity != null) {
activityAmountCache = ((ChartsActivity) activity).mActivityAmountCache;
amounts = (ActivityAmounts) (activityAmountCache.lookup(day.hashCode() ^ mOffsetHours));
amounts = (ActivityAmounts) (activityAmountCache.lookup(key));
}
if (amounts == null) {
ActivityAnalysis analysis = new ActivityAnalysis();
amounts = analysis.calculateActivityAmounts(getSamplesOfDay(db, day, mOffsetHours, device));
if (activityAmountCache != null) {
activityAmountCache.add(day.hashCode() ^ mOffsetHours, amounts);
activityAmountCache.add(key, amounts);
}
}
@ -311,6 +312,8 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
abstract String formatPieValue(int value);
abstract String[] getPieLabels();
abstract IValueFormatter getPieValueFormatter();
abstract IValueFormatter getBarValueFormatter();

View File

@ -27,7 +27,6 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.Menu;
@ -67,7 +66,6 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
private Date mStartDate;
private Date mEndDate;
private SwipeRefreshLayout swipeLayout;
private PagerTabStrip mPagerTabStrip;
private ViewPager viewPager;
LimitedQueue mActivityAmountCache = new LimitedQueue(60);
@ -200,7 +198,6 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
handleNextButtonClicked();
}
});
mPagerTabStrip = (PagerTabStrip) findViewById(R.id.charts_pagerTabStrip);
LinearLayout mainLayout = (LinearLayout) findViewById(R.id.charts_main_layout);
}

View File

@ -282,13 +282,14 @@ public class LiveActivityFragment extends AbstractChartFragment {
@Override
public void onPause() {
enableRealtimeTracking(false);
super.onPause();
stopActivityPulse();
}
@Override
public void onResume() {
super.onResume();
enableRealtimeTracking(true);
}
private ScheduledExecutorService startActivityPulse() {
@ -345,23 +346,34 @@ public class LiveActivityFragment extends AbstractChartFragment {
@Override
protected void onMadeVisibleInActivity() {
GBApplication.deviceService().onEnableRealtimeSteps(true);
GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(true);
super.onMadeVisibleInActivity();
if (getActivity() != null) {
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
enableRealtimeTracking(true);
}
private void enableRealtimeTracking(boolean enable) {
if (enable && pulseScheduler != null) {
// already running
return;
}
GBApplication.deviceService().onEnableRealtimeSteps(enable);
GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(enable);
if (enable) {
if (getActivity() != null) {
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
pulseScheduler = startActivityPulse();
} else {
stopActivityPulse();
if (getActivity() != null) {
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
pulseScheduler = startActivityPulse();
}
@Override
protected void onMadeInvisibleInActivity() {
stopActivityPulse();
GBApplication.deviceService().onEnableRealtimeSteps(false);
GBApplication.deviceService().onEnableRealtimeHeartRateMeasurement(false);
if (getActivity() != null) {
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
enableRealtimeTracking(false);
super.onMadeInvisibleInActivity();
}

View File

@ -105,6 +105,10 @@ public class SleepChartFragment extends AbstractChartFragment {
}
});
set.setColors(colors);
set.setValueTextColor(DESCRIPTION_COLOR);
set.setValueTextSize(13f);
set.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
set.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
data.setDataSet(set);
//setupLegend(pieChart);
@ -162,6 +166,7 @@ public class SleepChartFragment extends AbstractChartFragment {
private void setupSleepAmountChart() {
mSleepAmountChart.setBackgroundColor(BACKGROUND_COLOR);
mSleepAmountChart.getDescription().setTextColor(DESCRIPTION_COLOR);
mSleepAmountChart.setEntryLabelColor(DESCRIPTION_COLOR);
mSleepAmountChart.getDescription().setText("");
// mSleepAmountChart.getDescription().setNoDataTextDescription("");
mSleepAmountChart.setNoDataText("");

View File

@ -16,12 +16,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.LegendEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@ -72,6 +76,11 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
return DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.MINUTES);
}
@Override
String[] getPieLabels() {
return new String[]{getString(R.string.abstract_chart_fragment_kind_deep_sleep), getString(R.string.abstract_chart_fragment_kind_light_sleep)};
}
@Override
IValueFormatter getPieValueFormatter() {
return new IValueFormatter() {
@ -106,4 +115,22 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
int[] getColors() {
return new int[]{akDeepSleep.color, akLightSleep.color};
}
@Override
protected void setupLegend(Chart chart) {
List<LegendEntry> legendEntries = new ArrayList<>(2);
LegendEntry lightSleepEntry = new LegendEntry();
lightSleepEntry.label = akLightSleep.label;
lightSleepEntry.formColor = akLightSleep.color;
legendEntries.add(lightSleepEntry);
LegendEntry deepSleepEntry = new LegendEntry();
deepSleepEntry.label = akDeepSleep.label;
deepSleepEntry.formColor = akDeepSleep.color;
legendEntries.add(deepSleepEntry);
chart.getLegend().setCustom(legendEntries);
chart.getLegend().setTextColor(LEGEND_TEXT_COLOR);
}
}

View File

@ -17,6 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.IValueFormatter;
@ -62,6 +63,11 @@ public class WeekStepsChartFragment extends AbstractWeekChartFragment {
return String.valueOf(value);
}
@Override
String[] getPieLabels() {
return new String[]{""};
}
@Override
IValueFormatter getPieValueFormatter() {
return null;
@ -81,4 +87,10 @@ public class WeekStepsChartFragment extends AbstractWeekChartFragment {
int[] getColors() {
return new int[]{akActivity.color};
}
@Override
protected void setupLegend(Chart chart) {
// no legend here, it is all about the steps here
chart.getLegend().setEnabled(false);
}
}

View File

@ -19,20 +19,21 @@ package nodomain.freeyourgadget.gadgetbridge.adapter;
import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
@ -41,22 +42,18 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
/**
* Adapter for displaying GBAlarm instances.
*/
public class GBAlarmListAdapter extends ArrayAdapter<GBAlarm> {
public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.ViewHolder> {
private final Context mContext;
private ArrayList<GBAlarm> alarmList;
public GBAlarmListAdapter(Context context, ArrayList<GBAlarm> alarmList) {
super(context, 0, alarmList);
private List<GBAlarm> alarmList;
public GBAlarmListAdapter(Context context, List<GBAlarm> alarmList) {
this.mContext = context;
this.alarmList = alarmList;
}
public GBAlarmListAdapter(Context context, Set<String> preferencesAlarmListSet) {
super(context, 0, new ArrayList<GBAlarm>());
this.mContext = context;
alarmList = new ArrayList<>();
@ -81,7 +78,7 @@ public class GBAlarmListAdapter extends ArrayAdapter<GBAlarm> {
}
public ArrayList<? extends Alarm> getAlarmList() {
return alarmList;
return (ArrayList) alarmList;
}
@ -95,53 +92,26 @@ public class GBAlarmListAdapter extends ArrayAdapter<GBAlarm> {
}
@Override
public int getCount() {
if (alarmList != null) {
return alarmList.size();
}
return 0;
public GBAlarmListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.alarm_item, parent, false);
ViewHolder vh = new ViewHolder(view);
return vh;
}
@Override
public GBAlarm getItem(int position) {
if (alarmList != null) {
return alarmList.get(position);
}
return null;
}
public void onBindViewHolder(ViewHolder holder, final int position) {
@Override
public long getItemId(int position) {
if (alarmList != null) {
return alarmList.get(position).getIndex();
}
return 0;
}
final GBAlarm alarm = alarmList.get(position);
@Override
public View getView(int position, View view, ViewGroup parent) {
holder.alarmDayMonday.setChecked(alarm.getRepetition(Alarm.ALARM_MON));
holder.alarmDayTuesday.setChecked(alarm.getRepetition(Alarm.ALARM_TUE));
holder.alarmDayWednesday.setChecked(alarm.getRepetition(Alarm.ALARM_WED));
holder.alarmDayThursday.setChecked(alarm.getRepetition(Alarm.ALARM_THU));
holder.alarmDayFriday.setChecked(alarm.getRepetition(Alarm.ALARM_FRI));
holder.alarmDaySaturday.setChecked(alarm.getRepetition(Alarm.ALARM_SAT));
holder.alarmDaySunday.setChecked(alarm.getRepetition(Alarm.ALARM_SUN));
final GBAlarm alarm = getItem(position);
if (view == null) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.alarm_item, parent, false);
}
TextView alarmTime = (TextView) view.findViewById(R.id.alarm_item_time);
Switch isEnabled = (Switch) view.findViewById(R.id.alarm_item_toggle);
TextView isSmartWakeup = (TextView) view.findViewById(R.id.alarm_smart_wakeup);
highlightDay((TextView) view.findViewById(R.id.alarm_item_sunday), alarm.getRepetition(Alarm.ALARM_SUN));
highlightDay((TextView) view.findViewById(R.id.alarm_item_monday), alarm.getRepetition(Alarm.ALARM_MON));
highlightDay((TextView) view.findViewById(R.id.alarm_item_tuesday), alarm.getRepetition(Alarm.ALARM_TUE));
highlightDay((TextView) view.findViewById(R.id.alarm_item_wednesday), alarm.getRepetition(Alarm.ALARM_WED));
highlightDay((TextView) view.findViewById(R.id.alarm_item_thursday), alarm.getRepetition(Alarm.ALARM_THU));
highlightDay((TextView) view.findViewById(R.id.alarm_item_friday), alarm.getRepetition(Alarm.ALARM_FRI));
highlightDay((TextView) view.findViewById(R.id.alarm_item_saturday), alarm.getRepetition(Alarm.ALARM_SAT));
isEnabled.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
holder.isEnabled.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
alarm.setEnabled(isChecked);
@ -149,28 +119,62 @@ public class GBAlarmListAdapter extends ArrayAdapter<GBAlarm> {
}
});
view.setOnClickListener(new View.OnClickListener() {
holder.container.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
((ConfigureAlarms) mContext).configureAlarm(alarm);
}
});
alarmTime.setText(alarm.getTime());
isEnabled.setChecked(alarm.isEnabled());
holder.alarmTime.setText(alarm.getTime());
holder.isEnabled.setChecked(alarm.isEnabled());
if (alarm.isSmartWakeup()) {
isSmartWakeup.setVisibility(TextView.VISIBLE);
holder.isSmartWakeup.setVisibility(TextView.VISIBLE);
} else {
isSmartWakeup.setVisibility(TextView.GONE);
}
return view;
}
private void highlightDay(TextView view, boolean isOn) {
if (isOn) {
view.setTextColor(Color.BLUE);
} else {
view.setTextColor(GBApplication.getTextColor(mContext));
holder.isSmartWakeup.setVisibility(TextView.GONE);
}
}
@Override
public int getItemCount() {
return alarmList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
CardView container;
TextView alarmTime;
Switch isEnabled;
TextView isSmartWakeup;
CheckedTextView alarmDayMonday;
CheckedTextView alarmDayTuesday;
CheckedTextView alarmDayWednesday;
CheckedTextView alarmDayThursday;
CheckedTextView alarmDayFriday;
CheckedTextView alarmDaySaturday;
CheckedTextView alarmDaySunday;
ViewHolder(View view) {
super(view);
container = (CardView) view.findViewById(R.id.card_view);
alarmTime = (TextView) view.findViewById(R.id.alarm_item_time);
isEnabled = (Switch) view.findViewById(R.id.alarm_item_toggle);
isSmartWakeup = (TextView) view.findViewById(R.id.alarm_smart_wakeup);
alarmDayMonday = (CheckedTextView) view.findViewById(R.id.alarm_item_monday);
alarmDayTuesday = (CheckedTextView) view.findViewById(R.id.alarm_item_tuesday);
alarmDayWednesday = (CheckedTextView) view.findViewById(R.id.alarm_item_wednesday);
alarmDayThursday = (CheckedTextView) view.findViewById(R.id.alarm_item_thursday);
alarmDayFriday = (CheckedTextView) view.findViewById(R.id.alarm_item_friday);
alarmDaySaturday = (CheckedTextView) view.findViewById(R.id.alarm_item_saturday);
alarmDaySunday = (CheckedTextView) view.findViewById(R.id.alarm_item_sunday);
}
}
}

View File

@ -16,15 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.woxthebox.draglistview.DragItemAdapter;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@ -37,40 +37,41 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
* Adapter for displaying GBDeviceApp instances.
*/
public class GBDeviceAppAdapter extends DragItemAdapter<GBDeviceApp, GBDeviceAppAdapter.ViewHolder> {
public class GBDeviceAppAdapter extends RecyclerView.Adapter<GBDeviceAppAdapter.AppViewHolder> {
private final int mLayoutId;
private final int mGrabHandleId;
private final Context mContext;
private final List<GBDeviceApp> appList;
private final AbstractAppManagerFragment mParentFragment;
public GBDeviceAppAdapter(List<GBDeviceApp> list, int layoutId, int grabHandleId, Context context, AbstractAppManagerFragment parentFragment) {
super(true); // longpress
public List<GBDeviceApp> getAppList() {
return appList;
}
public GBDeviceAppAdapter(List<GBDeviceApp> list, int layoutId, AbstractAppManagerFragment parentFragment) {
mLayoutId = layoutId;
mGrabHandleId = grabHandleId;
mContext = context;
appList = list;
mParentFragment = parentFragment;
setHasStableIds(true);
setItemList(list);
}
@Override
public long getItemId(int position) {
return mItemList.get(position).getUUID().getLeastSignificantBits();
return appList.get(position).getUUID().getLeastSignificantBits();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
public int getItemCount() {
return appList.size();
}
@Override
public GBDeviceAppAdapter.AppViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);
return new ViewHolder(view);
return new AppViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
GBDeviceApp deviceApp = mItemList.get(position);
public void onBindViewHolder(final AppViewHolder holder, int position) {
final GBDeviceApp deviceApp = appList.get(position);
holder.mDeviceAppVersionAuthorLabel.setText(GBApplication.getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator()));
// FIXME: replace with small icons
@ -93,29 +94,51 @@ public class GBDeviceAppAdapter extends DragItemAdapter<GBDeviceApp, GBDeviceApp
default:
holder.mDeviceImageView.setImageResource(R.drawable.ic_watchapp);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
UUID uuid = deviceApp.getUUID();
GBApplication.deviceService().onAppStart(uuid, true);
}
});
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
return mParentFragment.openPopupMenu(view, deviceApp);
}
});
holder.mDragHandle.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mParentFragment.startDragging(holder);
return true;
}
});
}
public class ViewHolder extends DragItemAdapter<GBDeviceApp, GBDeviceAppAdapter.ViewHolder>.ViewHolder {
TextView mDeviceAppVersionAuthorLabel;
TextView mDeviceAppNameLabel;
ImageView mDeviceImageView;
public void onItemMove(int from, int to) {
Collections.swap(appList, from, to);
notifyItemMoved(from, to);
}
public ViewHolder(final View itemView) {
super(itemView, mGrabHandleId);
public class AppViewHolder extends RecyclerView.ViewHolder {
final TextView mDeviceAppVersionAuthorLabel;
final TextView mDeviceAppNameLabel;
final ImageView mDeviceImageView;
final ImageView mDragHandle;
AppViewHolder(View itemView) {
super(itemView);
mDeviceAppVersionAuthorLabel = (TextView) itemView.findViewById(R.id.item_details);
mDeviceAppNameLabel = (TextView) itemView.findViewById(R.id.item_name);
mDeviceImageView = (ImageView) itemView.findViewById(R.id.item_image);
mDragHandle = (ImageView) itemView.findViewById(R.id.drag_handle);
}
@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());
}
}
}

View File

@ -124,4 +124,9 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
public boolean needsBackgroundWebView(GBDevice device) {
return false;
}
@Override
public int getBondingStyle(GBDeviceCandidate deviceCandidate) {
return BONDING_STYLE_ASK;
}
}

View File

@ -47,6 +47,21 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
*/
public interface DeviceCoordinator {
String EXTRA_DEVICE_CANDIDATE = "nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate.EXTRA_DEVICE_CANDIDATE";
/**
* Do not attempt to bond after discovery.
*/
int BONDING_STYLE_NONE = 0;
/**
* Bond after discovery.
* This is not recommended, as there are mobile devices on which bonding does not work.
* Prefer to use #BONDING_STYLE_ASK instead.
*/
int BONDING_STYLE_BOND = 1;
/**
* Let the user decide whether to bond or not after discovery.
* Prefer this over #BONDING_STYLE_BOND
*/
int BONDING_STYLE_ASK = 2;
/**
* Checks whether this coordinator handles the given candidate.
@ -215,4 +230,10 @@ public interface DeviceCoordinator {
* @param device
*/
boolean needsBackgroundWebView(GBDevice device);
/**
* Returns how/if the given device should be bonded before connecting to it.
* @param deviceCandidate
*/
int getBondingStyle(GBDeviceCandidate deviceCandidate);
}

View File

@ -34,6 +34,9 @@ import java.util.Comparator;
import java.util.List;
import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
@ -88,6 +91,12 @@ public class DeviceManager {
} else {
deviceList.add(dev);
}
if (dev.isInitialized()) {
try (DBHandler dbHandler = GBApplication.acquireDB()) {
DBHelper.getDevice(dev, dbHandler.getDaoSession()); // implicitly creates the device in database if not present, and updates device attributes
} catch (Exception ignore) {
}
}
}
updateSelectedDevice(dev);
refreshPairedDevices();

View File

@ -34,24 +34,10 @@ import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
* @param <T> the device/provider specific sample type (must extend AbstractActivitySample)
*/
public interface SampleProvider<T extends AbstractActivitySample> {
// TODO: these constants can all be removed
int PROVIDER_MIBAND = 0;
// These are only used for SharedPreferences
int PROVIDER_PEBBLE_MORPHEUZ = 1;
int PROVIDER_PEBBLE_GADGETBRIDGE = 2; // removed
int PROVIDER_PEBBLE_MISFIT = 3;
int PROVIDER_PEBBLE_HEALTH = 4;
int PROVIDER_MIBAND2 = 5;
int PROVIDER_HPLUS = 6;
int PROVIDER_UNKNOWN = 100;
// TODO: can also be removed
/**
* Returns the "id" of this sample provider, as used in Gadgetbridge versions < 0.12.0.
* Only used for importing old samples.
* @deprecated
*/
int getID();
int normalizeType(int rawType);

View File

@ -87,11 +87,6 @@ public class UnknownDeviceCoordinator extends AbstractDeviceCoordinator {
public AbstractActivitySample getLatestActivitySample() {
return null;
}
@Override
public int getID() {
return PROVIDER_UNKNOWN;
}
}
public UnknownDeviceCoordinator() {

View File

@ -21,7 +21,6 @@ package nodomain.freeyourgadget.gadgetbridge.devices.hplus;
*/
import android.support.annotation.NonNull;
import android.util.Log;
import java.util.Calendar;
import java.util.Collections;
@ -34,7 +33,6 @@ import de.greenrobot.dao.Property;
import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.HPlusHealthActivityOverlay;
@ -58,11 +56,6 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
mDevice = device;
}
public int getID() {
return SampleProvider.PROVIDER_HPLUS;
}
public int normalizeType(int rawType) {
switch (rawType){
case HPlusDataRecord.TYPE_DAY_SLOT:
@ -200,6 +193,9 @@ public class HPlusHealthSampleProvider extends AbstractSampleProvider<HPlusHealt
for (HPlusHealthActivitySample sample : samples) {
if (sample.getTimestamp() >= overlay.getTimestampFrom() && sample.getTimestamp() < overlay.getTimestampTo()) {
if(overlay.getRawKind() == ActivityKind.TYPE_LIGHT_SLEEP || overlay.getRawKind() == ActivityKind.TYPE_DEEP_SLEEP)
sample.setRawIntensity(10);
sample.setRawKind(overlay.getRawKind());
}
}

View File

@ -20,7 +20,6 @@ package nodomain.freeyourgadget.gadgetbridge.devices.miband;
import java.util.List;
import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.MiBandActivitySampleDao;
@ -63,12 +62,6 @@ public class MiBand2SampleProvider extends AbstractMiBandSampleProvider {
super(device, session);
}
@Override
public int getID() {
return SampleProvider.PROVIDER_MIBAND2;
}
@Override
protected List<MiBandActivitySample> getGBActivitySamples(int timestamp_from, int timestamp_to, int activityType) {
List<MiBandActivitySample> samples = super.getGBActivitySamples(timestamp_from, timestamp_to, activityType);

View File

@ -43,7 +43,7 @@ public class MiBand2Service {
public static final UUID UUID_UNKNOWN_CHARACTERISTIC4 = UUID.fromString("00000004-0000-3512-2118-0009af100700");
public static final UUID UUID_CHARACTERISTIC_5_ACTIVITY_DATA = UUID.fromString("00000005-0000-3512-2118-0009af100700");
public static final UUID UUID_CHARACTERISTIC_6_BATTERY_INFO = UUID.fromString("00000006-0000-3512-2118-0009af100700");
public static final UUID UUID_UNKNOWN_CHARACTERISTIC7 = UUID.fromString("00000007-0000-3512-2118-0009af100700");
public static final UUID UUID_CHARACTERISTIC_7_REALTIME_STEPS = UUID.fromString("00000007-0000-3512-2118-0009af100700");
public static final UUID UUID_UNKNOWN_CHARACTERISTIC8 = UUID.fromString("00000008-0000-3512-2118-0009af100700");
// service uuid fee1
public static final UUID UUID_CHARACTERISTIC_AUTH = UUID.fromString("00000009-0000-3512-2118-0009af100700");

View File

@ -17,7 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.miband;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
@ -42,11 +41,6 @@ public class MiBandSampleProvider extends AbstractMiBandSampleProvider {
super(device, session);
}
@Override
public int getID() {
return SampleProvider.PROVIDER_MIBAND;
}
@Override
public int normalizeType(int rawType) {
switch (rawType) {

View File

@ -97,9 +97,13 @@ public class PBWReader {
return;
}
String platformDir = determinePlatformDir(uriHelper, platform);
if (platform.equals("chalk") && platformDir.equals("")) {
return;
String platformDir = "";
if (!uriHelper.getFileName().endsWith(".pbz")) {
platformDir = determinePlatformDir(uriHelper, platform);
if (platform.equals("chalk") && platformDir.equals("")) {
return;
}
}
LOG.info("using platformdir: '" + platformDir + "'");
@ -237,9 +241,6 @@ public class PBWReader {
private String determinePlatformDir(UriHelper uriHelper, String platform) throws IOException {
String platformDir = "";
if (uriHelper.getFileName().endsWith(".pbz")) {
return platformDir;
}
/*
* for aplite and basalt it is possible to install 2.x apps which have no subfolder
* we still prefer the subfolders if present.

View File

@ -25,7 +25,6 @@ import de.greenrobot.dao.Property;
import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivityOverlay;
@ -139,9 +138,4 @@ public class PebbleHealthSampleProvider extends AbstractSampleProvider<PebbleHea
public float normalizeIntensity(int rawIntensity) {
return rawIntensity / movementDivisor;
}
@Override
public int getID() {
return SampleProvider.PROVIDER_PEBBLE_HEALTH;
}
}

View File

@ -19,7 +19,6 @@ package nodomain.freeyourgadget.gadgetbridge.devices.pebble;
import de.greenrobot.dao.AbstractDao;
import de.greenrobot.dao.Property;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMisfitSample;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMisfitSampleDao;
@ -53,11 +52,6 @@ public class PebbleMisfitSampleProvider extends AbstractSampleProvider<PebbleMis
return new PebbleMisfitSample();
}
@Override
public int getID() {
return SampleProvider.PROVIDER_PEBBLE_MISFIT;
}
@Override
public AbstractDao<PebbleMisfitSample, ?> getSampleDao() {
return getSession().getPebbleMisfitSampleDao();

View File

@ -19,7 +19,6 @@ package nodomain.freeyourgadget.gadgetbridge.devices.pebble;
import de.greenrobot.dao.AbstractDao;
import de.greenrobot.dao.Property;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMorpheuzSample;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleMorpheuzSampleDao;
@ -64,11 +63,6 @@ public class PebbleMorpheuzSampleProvider extends AbstractSampleProvider<PebbleM
return rawIntensity / movementDivisor;
}
@Override
public int getID() {
return SampleProvider.PROVIDER_PEBBLE_MORPHEUZ;
}
@Override
public int normalizeType(int rawType) {
return rawType;

View File

@ -417,6 +417,10 @@ public class NotificationListener extends NotificationListenerService {
@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
//FIXME: deduplicate code
if (!isServiceRunning() || sbn == null) {
return;
}
String source = sbn.getPackageName();
Notification notification = sbn.getNotification();
if ((notification.flags & Notification.FLAG_ONGOING_EVENT) == Notification.FLAG_ONGOING_EVENT) {

View File

@ -41,9 +41,6 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
@ -207,14 +204,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
boolean enableReceivers = mDeviceSupport != null && (mDeviceSupport.useAutoConnect() || mGBDevice.isInitialized());
setReceiversEnableState(enableReceivers);
GB.updateNotification(mGBDevice.getName() + " " + mGBDevice.getStateString(), mGBDevice.isInitialized(), context);
if (device.isInitialized()) {
try (DBHandler dbHandler = GBApplication.acquireDB()) {
DaoSession session = dbHandler.getDaoSession();
DBHelper.getDevice(device, session); // implicitly creates the device in database if not present, and updates device attributes
} catch (Exception ignore) {
}
}
} else {
LOG.error("Got ACTION_DEVICE_CHANGED from unexpected device: " + mGBDevice);
}

View File

@ -44,6 +44,7 @@ import java.util.List;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -52,6 +53,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
@ -72,6 +74,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
public BluetoothGattCharacteristic ctrlCharacteristic = null;
public BluetoothGattCharacteristic measureCharacteristic = null;
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
private HPlusHandlerThread syncHelper;
private DeviceType deviceType = DeviceType.UNKNOWN;
@ -154,7 +158,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusSupport syncPreferences(TransactionBuilder transaction) {
if(deviceType == DeviceType.HPLUS) {
if (deviceType == DeviceType.HPLUS) {
setSIT(transaction); //Sync SIT Interval
}
@ -252,7 +256,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
//Makibes F68 doesn't like this command.
//Just ignore.
if(deviceType == DeviceType.MAKIBESF68){
if (deviceType == DeviceType.MAKIBESF68) {
return this;
}
@ -368,7 +372,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
byte hour = HPlusConstants.ARG_ALARM_DISABLE;
byte minute = HPlusConstants.ARG_ALARM_DISABLE;
if(t != null){
if (t != null) {
hour = (byte) t.get(Calendar.HOUR_OF_DAY);
minute = (byte) t.get(Calendar.MINUTE);
}
@ -654,8 +658,8 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
StringBuilder number = new StringBuilder();
//Clean up number as the device only accepts digits
for(char c : rawNumber.toCharArray()){
if(Character.isDigit(c)){
for (char c : rawNumber.toCharArray()) {
if (Character.isDigit(c)) {
number.append(c);
}
}
@ -708,7 +712,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
private void showText(String title, String body) {
LOG.debug("Show Notification: "+title+" --> "+body);
LOG.debug("Show Notification: " + title + " --> " + body);
try {
TransactionBuilder builder = performInitialized("notification");
@ -718,7 +722,7 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
message = StringUtils.pad(StringUtils.truncate(title, 16), 16); //Limit title to top row
}
if(body != null) {
if (body != null) {
message += body;
}
@ -784,26 +788,26 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
* @param s The String to transliterate
* @return An array of bytes ready to be sent to the device
*/
private byte[] encodeStringToDevice(String s){
private byte[] encodeStringToDevice(String s) {
List<Byte> outBytes = new ArrayList<Byte>();
for(int i = 0; i < s.length(); i++){
Character c = s.charAt(i);
byte[] cs;
for (int i = 0; i < s.length(); i++) {
Character c = s.charAt(i);
byte[] cs;
if(HPlusConstants.transliterateMap.containsKey(c)){
cs = new byte[] {HPlusConstants.transliterateMap.get(c)};
}else {
try {
cs = c.toString().getBytes("GB2312");
} catch (UnsupportedEncodingException e) {
//Fallback. Result string may be strange, but better than nothing
cs = c.toString().getBytes();
}
if (HPlusConstants.transliterateMap.containsKey(c)) {
cs = new byte[]{HPlusConstants.transliterateMap.get(c)};
} else {
try {
cs = c.toString().getBytes("GB2312");
} catch (UnsupportedEncodingException e) {
//Fallback. Result string may be strange, but better than nothing
cs = c.toString().getBytes();
}
for(int j = 0; j < cs.length; j++)
outBytes.add(cs[j]);
}
for (int j = 0; j < cs.length; j++)
outBytes.add(cs[j]);
}
return ArrayUtils.toPrimitive(outBytes.toArray(new Byte[outBytes.size()]));
@ -826,7 +830,11 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
return syncHelper.processVersion(data);
case HPlusConstants.DATA_STATS:
return syncHelper.processRealtimeStats(data);
boolean result = syncHelper.processRealtimeStats(data);
if (result) {
processExtraInfo (data);
}
return result;
case HPlusConstants.DATA_SLEEP:
return syncHelper.processIncomingSleepData(data);
@ -844,4 +852,44 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
}
}
private void processExtraInfo (byte[] data) {
try {
HPlusDataRecordRealtime record = new HPlusDataRecordRealtime(data);
handleBatteryInfo(record.battery);
String DEVINFO_STEP = getContext().getString(R.string.chart_steps) + ": ";
String DEVINFO_DISTANCE = getContext().getString(R.string.distance) + ": ";
String DEVINFO_CALORY = getContext().getString(R.string.calories) + ": ";
String DEVINFO_HEART = "HR: ";
String info = "";
if (record.steps > 0) {
info += DEVINFO_STEP + String.valueOf(record.steps) + " ";
}
if (record.distance > 0) {
info += DEVINFO_DISTANCE + String.valueOf(record.distance) + " ";
}
if (record.calories > 0) {
info += DEVINFO_CALORY + String.valueOf(record.calories) + " ";
}
if (record.heartRate > 0) {
info += DEVINFO_HEART + String.valueOf(record.heartRate) + " ";
}
if (!info.equals("")) {
getDevice().addDeviceInfo(new GenericItem("", info));
}
} catch (IllegalArgumentException e) {
LOG.debug((e.getMessage()));
}
}
private void handleBatteryInfo(byte data) {
if (batteryCmd.level != (short) data) {
batteryCmd.level = (short) data;
handleGBDeviceEvent(batteryCmd);
}
}
}

View File

@ -117,7 +117,7 @@ public class DeviceInfo extends AbstractInfo {
}
public boolean isMili1() {
return hwVersion == 2;
return hwVersion == 2 || (feature == 0 && appearance == 0 && hwVersion == 8 && fw2Version == -1);
}
public boolean isMili1A() {

View File

@ -73,6 +73,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
@ -965,7 +966,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
}
private void handleRealtimeSteps(byte[] value) {
int steps = 0xff & value[0] | (0xff & value[1]) << 8;
int steps = BLETypeConversions.toUint16(value);
if (LOG.isDebugEnabled()) {
LOG.debug("realtime steps: " + steps);
}

View File

@ -42,6 +42,7 @@ import java.util.UUID;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.Logging;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
@ -84,9 +85,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.OverflowStrategy;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile;
import nodomain.freeyourgadget.gadgetbridge.service.devices.common.SimpleNotification;
@ -689,6 +687,17 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
@Override
public void onEnableRealtimeSteps(boolean enable) {
try {
TransactionBuilder builder = performInitialized(enable ? "Enabling realtime steps notifications" : "Disabling realtime steps notifications");
if (enable) {
builder.read(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_7_REALTIME_STEPS));
}
builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_7_REALTIME_STEPS), enable);
builder.queue(getQueue());
enableRealtimeSamplesTimer(enable);
} catch (IOException e) {
LOG.error("Unable to change realtime steps notification to: " + enable, e);
}
}
private byte[] getHighLatency() {
@ -783,9 +792,6 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
} else if (GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristicUUID)) {
handleHeartrate(characteristic.getValue());
return true;
// } else if (MiBand2Service.UUID_UNKNOQN_CHARACTERISTIC0.equals(characteristicUUID)) {
// handleUnknownCharacteristic(characteristic.getValue());
// return true;
} else if (MiBand2Service.UUID_CHARACTERISTIC_AUTH.equals(characteristicUUID)) {
LOG.info("AUTHENTICATION?? " + characteristicUUID);
logMessageContent(characteristic.getValue());
@ -793,6 +799,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
} else if (MiBand2Service.UUID_CHARACTERISTIC_10_BUTTON.equals(characteristicUUID)) {
handleButtonPressed(characteristic.getValue());
return true;
} else if (MiBand2Service.UUID_CHARACTERISTIC_7_REALTIME_STEPS.equals(characteristicUUID)) {
handleRealtimeSteps(characteristic.getValue());
return true;
} else {
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
logMessageContent(characteristic.getValue());
@ -824,6 +833,9 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
} else if (GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT.equals(characteristicUUID)) {
logHeartrate(characteristic.getValue(), status);
return true;
} else if (MiBand2Service.UUID_CHARACTERISTIC_7_REALTIME_STEPS.equals(characteristicUUID)) {
handleRealtimeSteps(characteristic.getValue());
return true;
} else if (MiBand2Service.UUID_CHARACTERISTIC_10_BUTTON.equals(characteristicUUID)) {
handleButtonPressed(characteristic.getValue());
return true;
@ -874,11 +886,21 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
}
private void handleRealtimeSteps(byte[] value) {
int steps = 0xff & value[0] | (0xff & value[1]) << 8;
if (LOG.isDebugEnabled()) {
LOG.debug("realtime steps: " + steps);
if (value == null) {
LOG.error("realtime steps: value is null");
return;
}
if (value.length == 13) {
byte[] stepsValue = new byte[] {value[1], value[2]};
int steps = BLETypeConversions.toUint16(stepsValue);
if (LOG.isDebugEnabled()) {
LOG.debug("realtime steps: " + steps);
}
getRealtimeSamplesSupport().setSteps(steps);
} else {
LOG.warn("Unrecognized realtime steps value: " + Logging.formatBytes(value));
}
getRealtimeSamplesSupport().setSteps(steps);
}
private void enableRealtimeSamplesTimer(boolean enable) {
@ -1073,10 +1095,8 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
@Override
public void onTestNewFunction() {
try {
TransactionBuilder builder = performInitialized("incoming call from peter");
NewAlert alert = new NewAlert(AlertCategory.Custom, 1, new String(new byte[] {0x19}));
AlertNotificationProfile<MiBand2Support> profile = new AlertNotificationProfile<>(this);
profile.newAlert(builder, alert, OverflowStrategy.MAKE_MULTIPLE);
TransactionBuilder builder = performInitialized("test realtime steps");
builder.read(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_7_REALTIME_STEPS));
builder.queue(getQueue());
} catch (IOException e) {
}

View File

@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.pebble.GBDeviceEventDataLogging;
class DatalogSession {
@ -44,15 +45,15 @@ class DatalogSession {
this.itemSize = itemSize;
}
boolean handleMessage(ByteBuffer buf, int length) {
return true;
GBDeviceEvent[] handleMessage(ByteBuffer buf, int length) {
return new GBDeviceEvent[]{null};
}
String getTaginfo() {
return taginfo;
}
GBDeviceEventDataLogging handleMessageForPebbleKit(ByteBuffer buf, int length) {
GBDeviceEvent[] handleMessageForPebbleKit(ByteBuffer buf, int length) {
if (0 != (length % itemSize)) {
LOG.warn("invalid length");
return null;
@ -89,6 +90,6 @@ class DatalogSession {
break;
}
}
return dataLogging;
return new GBDeviceEvent[]{dataLogging, null};
}
}

View File

@ -0,0 +1,97 @@
/* Copyright (C) 2016-2017 Daniele Gobbetti
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
class DatalogSessionAnalytics extends DatalogSession {
private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionAnalytics.class);
private GBDeviceEventBatteryInfo mGBDeviceEventBatteryInfo = new GBDeviceEventBatteryInfo();
private GBDevice mGBDevice;
DatalogSessionAnalytics(byte id, UUID uuid, int timestamp, int tag, byte itemType, short itemSize, GBDevice device) {
super(id, uuid, timestamp, tag, itemType, itemSize);
if (mGBDevice == null || !device.equals(mGBDevice)) { //prevent showing information of other pebble watches when switching devices
mGBDevice = device;
mGBDeviceEventBatteryInfo.state = BatteryState.UNKNOWN;
}
// The default notification should not be too bad (one per hour) but we can override this if needed
//mGBDevice.setBatteryThresholdPercent((short) 5);
taginfo = "(analytics - " + tag + ")";
}
@Override
GBDeviceEvent[] handleMessage(ByteBuffer datalogMessage, int length) {
LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length));
datalogMessage.position(datalogMessage.position() + 3);
int messageTS = datalogMessage.getInt();
datalogMessage.position(datalogMessage.position() + 12);
short reportedMilliVolts = datalogMessage.getShort();
LOG.info("Battery reading for TS " + messageTS + " is: " + reportedMilliVolts + " milliVolts, mapped to percentage: " + milliVoltstoPercentage(reportedMilliVolts));
if (messageTS > 0 && reportedMilliVolts < 5000) { //some safety checks
// mGBDeviceEventBatteryInfo.state = BatteryState.BATTERY_NORMAL; //uncoomment this to show the battery status in the control center
mGBDeviceEventBatteryInfo.level = milliVoltstoPercentage(reportedMilliVolts);
return new GBDeviceEvent[]{mGBDeviceEventBatteryInfo, null};
} else { //invalid data, but we ack nevertheless
return new GBDeviceEvent[]{null};
}
}
private short milliVoltstoPercentage(short batteryMilliVolts) {
if (batteryMilliVolts > 4145) { //(4146 is still 100, next reported value is already 90)
return 100;
} else if (batteryMilliVolts > 4053) { //(4054 is still 90, next reported value is already 80)
return 90;
} else if (batteryMilliVolts > 4000) { //guessed
return 80;
} else if (batteryMilliVolts > 3890) { //3890 was already 60
return 70;
} else if (batteryMilliVolts > 3855) { //probably
return 60;
} else if (batteryMilliVolts > 3780) { //3781 is still 50, next reading is 3776 but percentage on pebble unknown
return 50;
} else if (batteryMilliVolts >= 3750) { //3750 is still 40, next reported value is 3746 and already 30
return 40;
} else if (batteryMilliVolts > 3720) { //3723 is still 30, next reported value is 3719 and already 20
return 30;
} else if (batteryMilliVolts > 3680) { //3683 is still 20, next reported value is 3675 and already 10
return 20;
} else if (batteryMilliVolts > 3650) { //3657 is still 10
return 10;
} else {
return 0; //or -1 for invalid?
}
}
}

View File

@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -35,9 +36,9 @@ class DatalogSessionHealthHR extends DatalogSessionPebbleHealth {
}
@Override
public boolean handleMessage(ByteBuffer datalogMessage, int length) {
public GBDeviceEvent[] handleMessage(ByteBuffer datalogMessage, int length) {
LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length));
return isPebbleHealthEnabled();
return isPebbleHealthEnabled() ? new GBDeviceEvent[]{null} : null;
}
}

View File

@ -29,6 +29,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivityOverlay;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivityOverlayDao;
@ -45,11 +46,11 @@ class DatalogSessionHealthOverlayData extends DatalogSessionPebbleHealth {
}
@Override
public boolean handleMessage(ByteBuffer datalogMessage, int length) {
public GBDeviceEvent[] handleMessage(ByteBuffer datalogMessage, int length) {
LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length));
if (!isPebbleHealthEnabled()) {
return false;
return null;
}
int initialPosition = datalogMessage.position();
@ -58,7 +59,7 @@ class DatalogSessionHealthOverlayData extends DatalogSessionPebbleHealth {
short recordType; //probably: 1=sleep, 2=deep sleep, 5=??run??ignored for now
if (0 != (length % itemSize))
return false;//malformed message?
return null;//malformed message?
int recordCount = length / itemSize;
OverlayRecord[] overlayRecords = new OverlayRecord[recordCount];
@ -72,7 +73,7 @@ class DatalogSessionHealthOverlayData extends DatalogSessionPebbleHealth {
}
store(overlayRecords);
return true;
return new GBDeviceEvent[]{null};
}
private void store(OverlayRecord[] overlayRecords) {

View File

@ -29,6 +29,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivityOverlay;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivityOverlayDao;
@ -45,11 +46,11 @@ class DatalogSessionHealthSleep extends DatalogSessionPebbleHealth {
}
@Override
public boolean handleMessage(ByteBuffer datalogMessage, int length) {
public GBDeviceEvent[] handleMessage(ByteBuffer datalogMessage, int length) {
LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length));
if (!isPebbleHealthEnabled()) {
return false;
return null;
}
int initialPosition = datalogMessage.position();
@ -57,7 +58,7 @@ class DatalogSessionHealthSleep extends DatalogSessionPebbleHealth {
short recordVersion; //probably
if (0 != (length % itemSize))
return false;//malformed message?
return null;//malformed message?
int recordCount = length / itemSize;
SleepRecord[] sleepRecords = new SleepRecord[recordCount];
@ -72,7 +73,7 @@ class DatalogSessionHealthSleep extends DatalogSessionPebbleHealth {
}
store(sleepRecords);
return true;
return new GBDeviceEvent[]{null};
}
private void store(SleepRecord[] sleepRecords) {

View File

@ -28,6 +28,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleHealthSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.PebbleHealthActivitySample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -43,11 +44,11 @@ class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth {
}
@Override
public boolean handleMessage(ByteBuffer datalogMessage, int length) {
public GBDeviceEvent[] handleMessage(ByteBuffer datalogMessage, int length) {
LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length));
if (!isPebbleHealthEnabled()) {
return false;
return null;
}
int timestamp;
@ -57,7 +58,7 @@ class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth {
int initialPosition = datalogMessage.position();
if (0 != (length % itemSize))
return false;//malformed message?
return null;//malformed message?
int packetCount = length / itemSize;
@ -68,7 +69,7 @@ class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth {
recordVersion = datalogMessage.getShort();
if ((recordVersion != 5) && (recordVersion != 6) && (recordVersion != 7) && (recordVersion != 12) && (recordVersion != 13))
return false; //we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it
return null; //we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it
timestamp = datalogMessage.getInt();
datalogMessage.get(); //unknown, throw away
@ -88,7 +89,7 @@ class DatalogSessionHealthSteps extends DatalogSessionPebbleHealth {
store(stepsRecords);
}
return true;//ACK by default
return new GBDeviceEvent[]{null};//ACK by default
}
private void store(StepsRecord[] stepsRecords) {

View File

@ -2232,10 +2232,9 @@ public class PebbleProtocol extends GBDeviceProtocol {
}
private GBDeviceEvent[] decodeDatalog(ByteBuffer buf, short length) {
boolean ack = true;
byte command = buf.get();
byte id = buf.get();
GBDeviceEventDataLogging devEvtDataLogging = null;
GBDeviceEvent[] devEvtsDataLogging = null;
switch (command) {
case DATALOG_TIMEOUT:
LOG.info("DATALOG TIMEOUT. id=" + (id & 0xff) + " - ignoring");
@ -2249,12 +2248,9 @@ public class PebbleProtocol extends GBDeviceProtocol {
if (datalogSession != null) {
LOG.info("DATALOG UUID=" + datalogSession.uuid + ", tag=" + datalogSession.tag + datalogSession.getTaginfo() + ", itemSize=" + datalogSession.itemSize + ", itemType=" + datalogSession.itemType);
if (!datalogSession.uuid.equals(UUID_ZERO) && datalogSession.getClass().equals(DatalogSession.class) && mEnablePebbleKit) {
devEvtDataLogging = datalogSession.handleMessageForPebbleKit(buf, length - 10);
if (devEvtDataLogging == null) {
ack = false;
}
devEvtsDataLogging = datalogSession.handleMessageForPebbleKit(buf, length - 10);
} else {
ack = datalogSession.handleMessage(buf, length - 10);
devEvtsDataLogging = datalogSession.handleMessage(buf, length - 10);
}
}
break;
@ -2267,7 +2263,9 @@ public class PebbleProtocol extends GBDeviceProtocol {
short item_size = buf.getShort();
LOG.info("DATALOG OPENSESSION. id=" + (id & 0xff) + ", App UUID=" + uuid.toString() + ", log_tag=" + log_tag + ", item_type=" + item_type + ", itemSize=" + item_size);
if (!mDatalogSessions.containsKey(id)) {
if (uuid.equals(UUID_ZERO) && log_tag == 81) {
if (uuid.equals(UUID_ZERO) && log_tag == 78) {
mDatalogSessions.put(id, new DatalogSessionAnalytics(id, uuid, timestamp, log_tag, item_type, item_size, getDevice()));
} else if (uuid.equals(UUID_ZERO) && log_tag == 81) {
mDatalogSessions.put(id, new DatalogSessionHealthSteps(id, uuid, timestamp, log_tag, item_type, item_size, getDevice()));
} else if (uuid.equals(UUID_ZERO) && log_tag == 83) {
mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, timestamp, log_tag, item_type, item_size, getDevice()));
@ -2279,6 +2277,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
mDatalogSessions.put(id, new DatalogSession(id, uuid, timestamp, log_tag, item_type, item_size));
}
}
devEvtsDataLogging = new GBDeviceEvent[]{null};
break;
case DATALOG_CLOSE:
LOG.info("DATALOG_CLOSE. id=" + (id & 0xff));
@ -2289,7 +2288,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
dataLogging.command = GBDeviceEventDataLogging.COMMAND_FINISH_SESSION;
dataLogging.appUUID = datalogSession.uuid;
dataLogging.tag = datalogSession.tag;
devEvtDataLogging = dataLogging;
devEvtsDataLogging = new GBDeviceEvent[]{dataLogging, null};
}
mDatalogSessions.remove(id);
}
@ -2299,15 +2298,18 @@ public class PebbleProtocol extends GBDeviceProtocol {
break;
}
GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes();
if (ack) {
if (devEvtsDataLogging != null) {
// append ack
LOG.info("sending ACK (0x85)");
sendBytes.encodedBytes = encodeDatalog(id, DATALOG_ACK);
devEvtsDataLogging[devEvtsDataLogging.length - 1] = sendBytes;
} else {
LOG.info("sending NACK (0x86)");
sendBytes.encodedBytes = encodeDatalog(id, DATALOG_NACK);
devEvtsDataLogging = new GBDeviceEvent[]{sendBytes};
}
// append ack/nack
return new GBDeviceEvent[]{devEvtDataLogging, sendBytes};
return devEvtsDataLogging;
}
private GBDeviceEvent decodeAppReorder(ByteBuffer buf) {

View File

@ -0,0 +1,131 @@
package nodomain.freeyourgadget.gadgetbridge.util;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import android.content.SharedPreferences;
import android.util.Xml;
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.blacklist;
public class ImportExportSharedPreferences {
private static final String BOOLEAN = Boolean.class.getSimpleName();
private static final String FLOAT = Float.class.getSimpleName();
private static final String INTEGER = Integer.class.getSimpleName();
private static final String LONG = Long.class.getSimpleName();
private static final String STRING = String.class.getSimpleName();
private static final String HASTSET = HashSet.class.getSimpleName();
private static final String NAME = "name";
private static final String PREFERENCES = "preferences";
public static void exportToFile(SharedPreferences sharedPreferences, File outFile,
Set<String> doNotExport) throws IOException {
export(sharedPreferences, new FileWriter(outFile), doNotExport);
}
public static void export(SharedPreferences sharedPreferences, Writer writer,
Set<String> doNotExport) throws IOException {
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(writer);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument("UTF-8", true);
serializer.startTag("", PREFERENCES);
for (Map.Entry<String, ?> entry : sharedPreferences.getAll().entrySet()) {
String key = entry.getKey();
if (doNotExport != null && doNotExport.contains(key)) continue;
Object valueObject = entry.getValue();
// Skip this entry if the value is null;
if (valueObject == null) continue;
String valueType = valueObject.getClass().getSimpleName();
String value = valueObject.toString();
serializer.startTag("", valueType);
serializer.attribute("", NAME, key);
serializer.text(value);
serializer.endTag("", valueType);
}
serializer.endTag("", PREFERENCES);
serializer.endDocument();
writer.close();
}
public static boolean importFromFile(SharedPreferences sharedPreferences, File inFile)
throws Exception {
return importFromReader(sharedPreferences, new FileReader(inFile));
}
/**
*
* @param sharedPreferences
* @param in
* @return
* @throws Exception
*/
public static boolean importFromReader(SharedPreferences sharedPreferences, Reader in)
throws Exception {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in);
int eventType = parser.getEventType();
String name = null;
String key = null;
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
name = parser.getName();
key = parser.getAttributeValue("", NAME);
break;
case XmlPullParser.TEXT:
// The parser is reading text outside an element if name is null,
// so simply ignore this text part (which is usually something like '\n')
if (name == null) break;
String text = parser.getText();
if (BOOLEAN.equals(name)) {
editor.putBoolean(key, Boolean.parseBoolean(text));
} else if (FLOAT.equals(name)) {
editor.putFloat(key, Float.parseFloat(text));
} else if (INTEGER.equals(name)) {
editor.putInt(key, Integer.parseInt(text));
} else if (LONG.equals(name)) {
editor.putLong(key, Long.parseLong(text));
} else if (STRING.equals(name)) {
editor.putString(key, text);
} else if (HASTSET.equals(name)) {
if (key.equals("package_blacklist")) {
blacklist.clear();
text=text.replace("[","").replace("]","");
for (int z=0;z<text.split(",").length;z++){
blacklist.add(text.split(",")[z].trim());
}
editor.putStringSet(key, blacklist);
}
} else if (!PREFERENCES.equals(name)) {
throw new Exception("Unkown type " + name);
}
break;
case XmlPullParser.END_TAG:
name = null;
break;
}
eventType = parser.next();
}
return editor.commit();
}
}

View File

@ -42,7 +42,7 @@ public class NotificationUtils {
case CONVERSATIONS:
case FACEBOOK:
case FACEBOOK_MESSENGER:
return notificationSpec.body;
return StringUtils.ensureNotNull(notificationSpec.body);
}
return "";
}

View File

@ -20,6 +20,7 @@ import android.support.annotation.NonNull;
public class StringUtils {
@NonNull
public static String truncate(String s, int maxLength){
if (s == null) {
return "";

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="M20,9H4v2h16V9zM4,15h16v-2H4v2z" />
</vector>

View File

@ -5,10 +5,17 @@
<item android:maxLevel="110" android:drawable="@drawable/ic_device_miband_disabled" />
<item android:maxLevel="111" android:drawable="@drawable/ic_device_miband_disabled" />
<item android:maxLevel="120" android:drawable="@drawable/ic_device_lovetoy_disabled" />
<item android:maxLevel="130" android:drawable="@drawable/ic_device_default_disabled" />
<item android:maxLevel="140" android:drawable="@drawable/ic_device_hplus_disabled" />
<item android:maxLevel="141" android:drawable="@drawable/ic_device_hplus_disabled" />
<item android:maxLevel="199" android:drawable="@drawable/ic_launcher" />
<item android:maxLevel="201" android:drawable="@drawable/ic_device_pebble" />
<item android:maxLevel="210" android:drawable="@drawable/ic_device_miband" />
<item android:maxLevel="211" android:drawable="@drawable/ic_device_miband" />
<item android:maxLevel="220" android:drawable="@drawable/ic_device_lovetoy" />
<item android:maxLevel="230" android:drawable="@drawable/ic_launcher" />
<item android:maxLevel="240" android:drawable="@drawable/ic_device_hplus" />
<item android:maxLevel="241" android:drawable="@drawable/ic_device_hplus" />
</level-list>

View File

@ -1,209 +1,211 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
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:paddingBottom="@dimen/activity_vertical_margin"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.AlarmDetails">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp">
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<CheckBox
android:id="@+id/alarm_cb_smart_wakeup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_smart_wakeup"/>
android:layout_height="wrap_content" />
<TextView
android:id="@+id/alarm_label_smart_wakeup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/alarm_smart_wakeup"
android:id="@+id/alarm_label_smart_wakeup"
android:labelFor="@id/alarm_cb_smart_wakeup" />
android:labelFor="@id/alarm_cb_smart_wakeup"
android:text="@string/alarm_smart_wakeup" />
</LinearLayout>
<TimePicker
android:id="@+id/alarm_time_picker"
android:timePickerMode="clock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp" />
android:layout_marginBottom="20dp"
android:timePickerMode="clock" />
<LinearLayout
android:orientation="horizontal"
android:id="@+id/dowSelector"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:id="@+id/dowSelector">
android:orientation="horizontal">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_mon"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_mon_short"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom" />
<TextView
android:id="@+id/alarm_label_cb_mon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|top"
android:labelFor="@id/alarm_cb_mon"
android:gravity="center_horizontal|top"/>
android:text="@string/alarm_mon_short" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
android:layout_weight="1"
android:orientation="vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_tue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_tue_short"
android:id="@+id/alarm_label_cb_tue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|top"
android:labelFor="@id/alarm_cb_tue"
android:gravity="center_horizontal|top" />
android:text="@string/alarm_tue_short" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
android:layout_weight="1"
android:orientation="vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_wed"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_wed_short"
android:id="@+id/alarm_label_cb_wed"
android:layout_gravity="center_horizontal"
android:labelFor="@id/alarm_cb_wed"
android:gravity="center_horizontal|top" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_thu"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom" />
<TextView
android:id="@+id/alarm_label_cb_wed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_thu_short"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|top"
android:labelFor="@id/alarm_cb_wed"
android:text="@string/alarm_wed_short" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<CheckBox
android:id="@+id/alarm_cb_thu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom" />
<TextView
android:id="@+id/alarm_label_cb_thu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|top"
android:labelFor="@id/alarm_cb_thu"
android:gravity="center_horizontal|top" />
android:text="@string/alarm_thu_short" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
android:layout_weight="1"
android:orientation="vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_fri"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_fri_short"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom" />
<TextView
android:id="@+id/alarm_label_cb_fri"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|top"
android:labelFor="@id/alarm_cb_fri"
android:gravity="center_horizontal|top" />
android:text="@string/alarm_fri_short" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
android:layout_weight="1"
android:orientation="vertical">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_sat"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_sat_short"
android:id="@+id/alarm_label_cb_sat"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|bottom" />
<TextView
android:id="@+id/alarm_label_cb_sat"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|top"
android:labelFor="@id/alarm_cb_sat"
android:gravity="center_horizontal|top" />
android:text="@string/alarm_sat_short" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1">
android:layout_weight="1"
android:orientation="vertical">
<CheckBox
android:id="@+id/alarm_cb_sun"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/alarm_cb_sun"
android:layout_gravity="center_horizontal"/>
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/alarm_label_cb_sun"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/alarm_sun_short"
android:id="@+id/alarm_label_cb_sun"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal|top"
android:labelFor="@id/alarm_cb_sun"
android:gravity="center_horizontal|top" />
android:text="@string/alarm_sun_short" />
</LinearLayout>

View File

@ -1,12 +1,16 @@
<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"
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.AndroidPairingActivity">
<TextView android:text="@string/android_pairing_hint" android:layout_width="wrap_content"
<TextView
android:text="@string/android_pairing_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>

View File

@ -1,6 +1,8 @@
<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"
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"

View File

@ -14,8 +14,7 @@
android:id="@+id/itemListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="false">
</ListView>
android:layout_alignParentEnd="false"></ListView>
<TextView
android:id="@+id/infoTextView"
@ -67,8 +66,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/installButton"
android:layout_alignParentEnd="false">
</ListView>
android:layout_alignParentEnd="false"></ListView>
<android.widget.Space
android:layout_width="wrap_content"

View File

@ -3,8 +3,12 @@
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment">
<com.woxthebox.draglistview.DragListView
android:id="@+id/appListView"
android:layout_width="match_parent"
android:layout_height="fill_parent" />
<android.support.v7.widget.RecyclerView
android:id="@+id/appListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:divider="@null" />
</RelativeLayout>

View File

@ -1,56 +1,59 @@
<android.support.v4.widget.SwipeRefreshLayout 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/activity_swipe_layout"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity"
android:paddingLeft="0px"
android:paddingRight="0px"
android:paddingTop="0px"
android:paddingBottom="0px"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent"
android:orientation="vertical"
android:id="@+id/charts_main_layout"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity">
<LinearLayout
android:id="@+id/charts_date_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/charts_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="&lt;" />
<TextView
android:id="@+id/charts_text_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:text="Today"
/>
android:id="@+id/charts_main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/charts_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=">" />
</LinearLayout>
<android.support.v4.view.ViewPager android:id="@+id/charts_pager"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity">
<android.support.v4.view.PagerTabStrip
android:id="@+id/charts_pagerTabStrip"
<android.support.v4.view.ViewPager
android:id="@+id/charts_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity">
<android.support.design.widget.TabLayout
android:id="@+id/charts_pagerTabStrip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
app:tabMode="scrollable" />
</android.support.v4.view.ViewPager>
<LinearLayout
android:id="@+id/charts_date_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
</android.support.v4.view.ViewPager>
android:gravity="fill_horizontal"
android:orientation="horizontal">
<Button
android:id="@+id/charts_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="&lt;" />
</LinearLayout>
<TextView
android:id="@+id/charts_text_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_weight="1"
android:text="Today" />
<Button
android:id="@+id/charts_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=">" />
</LinearLayout>
</LinearLayout>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/charts_duration_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
android:layout_height="wrap_content"></TextView>
</LinearLayout>

View File

@ -1,14 +1,17 @@
<FrameLayout 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"
<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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:fitsSystemWindows="true"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms">
<ListView
android:descendantFocusability="blocksDescendants"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:divider="@null"
android:id="@+id/alarm_list" />
</FrameLayout>
</RelativeLayout>

View File

@ -34,7 +34,7 @@
app:elevation="6dp"
app:pressedTranslationZ="12dp"
android:layout_marginBottom="30dp"
android:layout_marginRight="10dp"/>
android:layout_marginEnd="10dp" />
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,6 +1,8 @@
<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"
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"

View File

@ -3,14 +3,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
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:id="@+id/appmanager_main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
@ -21,14 +17,15 @@
android:layout_height="match_parent"
tools:context=".activities.appmanager.AppManagerActivity">
<android.support.v4.view.PagerTabStrip
<android.support.design.widget.TabLayout
android:id="@+id/charts_pagerTabStrip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
android:layout_gravity="top" />
</android.support.v4.view.ViewPager>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
@ -39,7 +36,7 @@
android:src="@drawable/ic_add_white"
app:elevation="6dp"
app:pressedTranslationZ="12dp"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp" />
android:layout_marginBottom="30dp"
android:layout_marginEnd="10dp" />
</android.widget.RelativeLayout>

View File

@ -1,12 +1,16 @@
<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"
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.devices.miband.MiBandPairingActivity">
<TextView android:text="@string/pairing" android:layout_width="wrap_content"
<TextView
android:text="@string/pairing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/miband_pair_message" />

View File

@ -1,12 +1,16 @@
<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"
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.devices.pebble.PebblePairingActivity">
<TextView android:text="@string/pairing" android:layout_width="wrap_content"
<TextView
android:text="@string/pairing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/pebble_pair_message" />

View File

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_margin="10dp">
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp">
<TextView
android:text="Weather on your Pebble"
@ -9,17 +11,16 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="20dp"/>
android:textSize="20dp" />
<android.support.v4.widget.Space
android:layout_width="match_parent"
android:layout_height="@dimen/activity_vertical_margin" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/weather_notification_label"
android:text="@string/weather_notification_label"
/>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/weather_notification_label"
android:text="@string/weather_notification_label" />
</LinearLayout>

View File

@ -1,109 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content">
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
<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="16dp" >
android:layout_margin="8dp"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="4dp"
card_view:contentPadding="8dp">
<TextView
android:id="@+id/alarm_item_time"
android:layout_width="wrap_content"
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="00:00"
android:textAppearance="?android:attr/textAppearanceLarge" />
android:layout_margin="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(Smart)"
android:layout_toRightOf="@+id/alarm_item_time"
android:id="@+id/alarm_smart_wakeup"
android:visibility="invisible"
android:layout_alignBaseline="@+id/alarm_item_time" />
<TextView
android:id="@+id/alarm_item_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="8dp"
android:text="00:00"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/alarm_item_monday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/alarm_item_time"
android:layout_marginLeft="4dp"
android:text="@string/alarm_mon_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/alarm_smart_wakeup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/alarm_item_time"
android:layout_toEndOf="@+id/alarm_item_time"
android:text="(Smart)"
android:visibility="invisible" />
<TextView
android:id="@+id/alarm_item_tuesday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/alarm_item_monday"
android:layout_below="@+id/alarm_item_time"
android:layout_marginLeft="4dp"
android:text="@string/alarm_tue_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<Switch
android:id="@+id/alarm_item_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true" />
<TextView
android:id="@+id/alarm_item_wednesday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/alarm_item_tuesday"
android:layout_below="@+id/alarm_item_time"
android:layout_marginLeft="4dp"
android:text="@string/alarm_wed_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<LinearLayout
android:id="@+id/dowSelector"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/alarm_item_time"
android:baselineAligned="false"
android:orientation="horizontal">
<TextView
android:id="@+id/alarm_item_thursday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/alarm_item_wednesday"
android:layout_below="@+id/alarm_item_time"
android:layout_marginLeft="4dp"
android:text="@string/alarm_thu_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<android.support.v7.widget.AppCompatCheckedTextView
android:id="@+id/alarm_item_monday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:checked="false"
android:drawableTop="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_mon_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/alarm_item_friday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/alarm_item_thursday"
android:layout_below="@+id/alarm_item_time"
android:layout_marginLeft="4dp"
android:text="@string/alarm_fri_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<android.support.v7.widget.AppCompatCheckedTextView
android:id="@+id/alarm_item_tuesday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:checked="false"
android:drawableTop="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_tue_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/alarm_item_saturday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/alarm_item_friday"
android:layout_below="@+id/alarm_item_time"
android:layout_marginLeft="4dp"
android:text="@string/alarm_sat_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<android.support.v7.widget.AppCompatCheckedTextView
android:id="@+id/alarm_item_wednesday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:checked="false"
android:drawableTop="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_wed_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/alarm_item_sunday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/alarm_item_saturday"
android:layout_below="@+id/alarm_item_time"
android:layout_marginLeft="4dp"
android:text="@string/alarm_sun_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<android.support.v7.widget.AppCompatCheckedTextView
android:id="@+id/alarm_item_thursday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:checked="false"
android:drawableTop="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_thu_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<Switch
android:id="@+id/alarm_item_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />
<android.support.v7.widget.AppCompatCheckedTextView
android:id="@+id/alarm_item_friday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:checked="false"
android:drawableTop="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_fri_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
<android.support.v7.widget.AppCompatCheckedTextView
android:id="@+id/alarm_item_saturday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:checked="false"
android:drawableTop="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_sat_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
<android.support.v7.widget.AppCompatCheckedTextView
android:id="@+id/alarm_item_sunday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:checked="false"
android:drawableTop="?android:attr/listChoiceIndicatorMultiple"
android:gravity="center"
android:text="@string/alarm_sun_short"
android:textAppearance="?android:attr/textAppearanceSmall" />
</FrameLayout>
</LinearLayout>
</RelativeLayout>
</android.support.v7.widget.CardView>
</android.support.design.widget.CoordinatorLayout>

View File

@ -22,7 +22,7 @@
<RelativeLayout
android:id="@+id/device_item_infos_box"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="8dp"
@ -48,7 +48,7 @@
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:contentDescription="@string/controlcenter_delete_device"
android:tint="?android:textColorTertiary"
android:tint="?attr/textColorTertiary"
card_view:srcCompat="@drawable/ic_remove_device" />
</RelativeLayout>
@ -62,7 +62,7 @@
android:clickable="true"
android:longClickable="true"
android:background="?android:attr/selectableItemBackground"
tools:src="@drawable/ic_device_pebble"
android:src="@drawable/ic_device_pebble"
android:layout_marginTop="8dp" />
<TextView
@ -111,17 +111,16 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/device_image"
android:layout_marginBottom="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="0dp"
android:layout_marginTop="8dp"
android:minWidth="48dp"
android:layout_alignParentStart="true"
android:layout_margin="4dp"
android:orientation="vertical">
<ImageView
android:id="@+id/device_battery_status"
android:layout_width="48dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="4dp"
android:scaleType="fitXY"
android:tint="@color/secondarytext"
card_view:srcCompat="@drawable/level_list_battery" />
@ -142,7 +141,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_margin="4dp"
android:layout_toEndOf="@id/device_battery_status_box"
android:gravity="center_vertical"
android:minWidth="36dp"
@ -150,12 +149,14 @@
<ImageView
android:id="@+id/device_action_fetch_activity"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="4dp"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:contentDescription="@string/controlcenter_fetch_activity_data"
android:scaleType="fitXY"
android:tint="@color/secondarytext"
android:background="?android:attr/selectableItemBackground"
card_view:srcCompat="@drawable/ic_action_fetch_activity_data" />
<ProgressBar
@ -171,65 +172,75 @@
<ImageView
android:id="@+id/device_action_take_screenshot"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_margin="4dp"
android:layout_toEndOf="@id/device_action_fetch_activity_box"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:contentDescription="@string/controlcenter_take_screenshot"
android:padding="4dp"
android:scaleType="fitXY"
android:tint="@color/secondarytext"
android:background="?android:attr/selectableItemBackground"
card_view:srcCompat="@drawable/ic_screenshot" />
<ImageView
android:id="@+id/device_action_manage_apps"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_margin="4dp"
android:layout_toEndOf="@id/device_action_take_screenshot"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:contentDescription="@string/title_activity_appmanager"
android:padding="4dp"
android:scaleType="fitXY"
android:tint="@color/secondarytext"
android:background="?android:attr/selectableItemBackground"
card_view:srcCompat="@drawable/ic_action_manage_apps" />
<ImageView
android:id="@+id/device_action_set_alarms"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_margin="4dp"
android:layout_toEndOf="@id/device_action_manage_apps"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:contentDescription="@string/controlcenter_start_configure_alarms"
android:padding="4dp"
android:scaleType="fitXY"
android:tint="@color/secondarytext"
android:background="?android:attr/selectableItemBackground"
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_width="40dp"
android:layout_height="40dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_margin="4dp"
android:layout_toEndOf="@id/device_action_set_alarms"
android:clickable="true"
android:tint="@color/secondarytext"
card_view:srcCompat="@drawable/ic_activity_graphs"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/controlcenter_start_activitymonitor" />
android:clickable="true"
android:contentDescription="@string/controlcenter_start_activitymonitor"
android:padding="4dp"
android:scaleType="fitXY"
android:tint="@color/secondarytext"
card_view:srcCompat="@drawable/ic_activity_graphs" />
<ImageView
android:id="@+id/device_action_find"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_below="@id/device_image"
android:layout_margin="8dp"
android:layout_margin="4dp"
android:layout_toEndOf="@id/device_action_show_activity_graphs"
android:clickable="true"
android:contentDescription="@string/controlcenter_find_device"
android:padding="4dp"
android:scaleType="fitXY"
android:tint="@color/secondarytext"
card_view:srcCompat="@drawable/ic_action_find_lost_device" />

View File

@ -1,5 +1,6 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment">
@ -7,6 +8,6 @@
android:id="@+id/activitysleepchart"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
android:layout_marginTop="@dimen/activity_vertical_margin" />
</RelativeLayout>

View File

@ -1,12 +1,16 @@
<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"
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.charts.ChartsActivity$PlaceholderFragment">
<TextView android:id="@+id/section_label" android:layout_width="wrap_content"
<TextView
android:id="@+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
@ -13,15 +14,13 @@
android:id="@+id/livechart_steps_per_minute_current"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="20">
</nodomain.freeyourgadget.gadgetbridge.activities.charts.CustomBarChart>
android:layout_weight="20"></nodomain.freeyourgadget.gadgetbridge.activities.charts.CustomBarChart>
<nodomain.freeyourgadget.gadgetbridge.activities.charts.CustomBarChart
android:id="@+id/livechart_steps_total"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="20">
</nodomain.freeyourgadget.gadgetbridge.activities.charts.CustomBarChart>
android:layout_weight="20"></nodomain.freeyourgadget.gadgetbridge.activities.charts.CustomBarChart>
<!--
<com.github.mikephil.charting.charts.PieChart
@ -44,8 +43,7 @@
android:id="@+id/livechart_steps_per_minute_history"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="20">
</com.github.mikephil.charting.charts.LineChart>
android:layout_weight="20"></com.github.mikephil.charting.charts.LineChart>
</LinearLayout>

View File

@ -1,5 +1,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment"
android:orientation="vertical">
@ -8,8 +9,7 @@
android:id="@+id/sleepchart_pie_light_deep"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="20">
</com.github.mikephil.charting.charts.PieChart>
android:layout_weight="20"></com.github.mikephil.charting.charts.PieChart>
<com.github.mikephil.charting.charts.CombinedChart
android:id="@+id/sleepchart"

View File

@ -1,5 +1,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment"
android:orientation="vertical">
@ -8,8 +9,7 @@
android:id="@+id/todaystepschart"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="20">
</com.github.mikephil.charting.charts.PieChart>
android:layout_weight="20"></com.github.mikephil.charting.charts.PieChart>
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/weekstepschart"

View File

@ -3,7 +3,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/activatedBackgroundIndicator"
android:padding="8dp" >
android:padding="8dp">
<ImageView
android:id="@+id/item_image"
@ -28,15 +28,14 @@
android:scrollHorizontally="false"
style="@style/Base.TextAppearance.AppCompat.SearchResult.Title"
android:text="Item Name"
android:maxLines="1"/>
android:maxLines="1" />
<TextView
android:id="@+id/item_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Base.TextAppearance.AppCompat.SearchResult"
android:text="Item Description"
/>
android:text="Item Description" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,63 @@
<?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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="60dp">
<ImageView
android:id="@+id/item_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentStart="true"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_centerVertical="true"
android:contentDescription="@string/candidate_item_device_image" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignWithParentIfMissing="true"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_toEndOf="@+id/item_image"
android:layout_toStartOf="@+id/drag_handle"
android:orientation="vertical"
android:paddingBottom="8dp"
android:paddingTop="8dp">
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:scrollHorizontally="false"
android:text="Item Name"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
<TextView
android:id="@+id/item_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Item Description"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
</LinearLayout>
<ImageView
android:id="@+id/drag_handle"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_alignParentEnd="true"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:layout_centerVertical="true"
android:contentDescription="drag handle"
android:tint="@color/secondarytext"
app:srcCompat="@drawable/ic_drag_handle_black_24dp" />
</RelativeLayout>

View File

@ -37,8 +37,7 @@
android:layout_height="wrap_content"
android:textColor="@color/secondarytext"
android:textSize="12sp"
android:text="Item Description"
/>
android:text="Item Description" />
</LinearLayout>
</RelativeLayout>

View File

@ -3,7 +3,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/activatedBackgroundIndicator"
android:padding="4dp" >
android:padding="4dp">
<ImageView
android:id="@+id/item_image"
@ -28,15 +28,14 @@
android:scrollHorizontally="false"
style="@style/Base.TextAppearance.AppCompat.Body1"
android:text="Item Name"/>
android:text="Item Name" />
<TextView
android:id="@+id/item_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Base.TextAppearance.AppCompat.Body2"
android:text="Item Description"
/>
android:text="Item Description" />
</LinearLayout>
</RelativeLayout>

View File

@ -84,6 +84,7 @@
<string name="pref_title_call_privacy_mode">Modo de privacidad de llamada</string>
<string name="pref_call_privacy_mode_off">Mostrar nombre y número</string>
<string name="pref_call_privacy_mode_name">Ocultar nombre pero mostrar número</string>
<string name="pref_call_privacy_mode_number">Ocultar el número pero mostrar el nombre</string>
<string name="pref_call_privacy_mode_complete">Ocultar nombre y número</string>
<string name="pref_blacklist">Excluir aplicaciones</string>
<string name="pref_header_cannned_messages">Mensajes predeterminados</string>
@ -247,7 +248,7 @@
<string name="notif_battery_low_bigtext_last_charge_time">Última carga: %s \n</string>
<string name="notif_battery_low_bigtext_number_of_charges">Número de cargas: %s</string>
<string name="sleepchart_your_sleep">Tu sueño</string>
<string name="weeksleepchart_sleep_a_week">Dormir una semana</string>
<string name="weeksleepchart_sleep_a_week">Sueño esta semana</string>
<string name="weeksleepchart_today_sleep_description">Sueño hoy, objetivo: %1$s</string>
<string name="weekstepschart_steps_a_week">Pasos por semana</string>
<string name="activity_sleepchart_activity_and_sleep">Tu actividad y sueño</string>
@ -356,4 +357,8 @@
<string name="StringUtils_sender">(%1$s)</string>
<string name="find_device_you_found_it">¡Lo ha encontrado!</string>
<string name="miband2_prefs_timeformat">Mi2: formato de hora</string>
<string name="mi2_fw_installhandler_fw53_hint">¡Debes instalar la versión %1$s antes de instalar este firmware!</string>
<string name="mi2_enable_text_notifications">Notificaciones textuales</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Needs firmware >= 1.0.1.28 and Mili_pro.ft* installed.]]></string>
<string name="off">off</string>
</resources>

View File

@ -84,6 +84,7 @@
<string name="pref_title_call_privacy_mode">Mode de confidentialité d\'appel</string>
<string name="pref_call_privacy_mode_off">Afficher le nom et le numéro</string>
<string name="pref_call_privacy_mode_name">Masquer le nom mais afficher le numéro</string>
<string name="pref_call_privacy_mode_number">Masquer le numéro mais afficher le nom</string>
<string name="pref_call_privacy_mode_complete">Masquer le nom et le numéro</string>
<string name="pref_blacklist">Applications bloquées</string>
<string name="pref_header_cannned_messages">Modèles de messages</string>
@ -247,7 +248,7 @@
<string name="notif_battery_low_bigtext_last_charge_time">Dernière charge: %s \n</string>
<string name="notif_battery_low_bigtext_number_of_charges">Nombre de charges: %s</string>
<string name="sleepchart_your_sleep">Votre sommeil</string>
<string name="weeksleepchart_sleep_a_week">Dormir une semaine</string>
<string name="weeksleepchart_sleep_a_week">Sommeil cette semaine</string>
<string name="weeksleepchart_today_sleep_description">Sommeil aujourd\'hui, objectif: %1$s</string>
<string name="weekstepschart_steps_a_week">Pas de la semaine</string>
<string name="activity_sleepchart_activity_and_sleep">Votre activité et sommeil</string>
@ -306,7 +307,8 @@
<string name="authentication_required">authentification requise</string>
<string name="appwidget_text">ZzZz</string>
<string name="add_widget">Ajouter un widget</string>
<string name="activity_prefs_sleep_duration">Préférer le mode heure pendant le sommeil</string>
<string name="activity_prefs_sleep_duration">
Temps de sommeil péféré en heures</string>
<string name="appwidget_alarms_set">Une alarme a été enregistré pour %1$02d:%2$02d</string>
<string name="device_hw">Modèle: %1$s</string>
<string name="device_fw">Micrologiciel: %1$s</string>
@ -357,4 +359,8 @@ NOTE: la base de données sera bien évidement plus grande !</string>
<string name="StringUtils_sender">(%1$s)</string>
<string name="find_device_you_found_it">Vous l\'avez trouvé!</string>
<string name="miband2_prefs_timeformat">Mi2: format de l\'heure</string>
<string name="mi2_fw_installhandler_fw53_hint">Vous devez installer la version %1$s avant d\'installer ce micrologiciel!</string>
<string name="mi2_enable_text_notifications">Notifications textuelles</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Needs firmware >= 1.0.1.28 and Mili_pro.ft* installed.]]></string>
<string name="off">off</string>
</resources>

View File

@ -289,7 +289,7 @@
<string name="FetchActivityOperation_about_to_transfer_since">Sobre para transferir dados desde %1$s</string>
<string name="waiting_for_reconnect">aguarde para reconectar</string>
<string name="activity_prefs_about_you">Sobre você</string>
<string name="activity_prefs_year_birth">Ano de anoversário</string>
<string name="activity_prefs_year_birth">Ano de aniversário</string>
<string name="activity_prefs_gender">Gênero</string>
<string name="activity_prefs_height_cm">Altura em cm</string>
<string name="activity_prefs_weight_kg">Peso em kg</string>

View File

@ -5,9 +5,9 @@
<string name="action_quit">Sair</string>
<string name="controlcenter_fetch_activity_data">Sincronizar</string>
<string name="controlcenter_start_sleepmonitor">Monitor de sono (ALPHA)</string>
<string name="controlcenter_find_device">Buscando dispositivo perdido...</string>
<string name="controlcenter_take_screenshot">Print da tela</string>
<string name="controlcenter_disconnect">Desconectar</string>
<string name="controlcenter_find_device">Procurando dispositivo perdido...</string>
<string name="controlcenter_take_screenshot">Captura de ecrã</string>
<string name="controlcenter_disconnect">Desligar</string>
<string name="controlcenter_delete_device">Apagar dispositivo</string>
<string name="controlcenter_delete_device_name">Apagar %1$s</string>
<string name="controlcenter_delete_device_dialogmessage">Isto irá apagar o dispositivo e apagar os dados associados!</string>
@ -20,29 +20,29 @@
<string name="appmananger_app_delete">Apagar</string>
<string name="appmananger_app_delete_cache">Apagar e remover do cache</string>
<string name="appmananger_app_reinstall">Reinstalar</string>
<string name="appmanager_app_openinstore">Buscar na loja Pebble</string>
<string name="appmanager_app_openinstore">Procurar na loja Pebble</string>
<string name="appmanager_health_activate">Ativar</string>
<string name="appmanager_health_deactivate">Desativar</string>
<string name="appmanager_hrm_activate">Ativar HRM</string>
<string name="appmanager_hrm_deactivate">Desativar HRM</string>
<string name="appmanager_weather_activate">Ativas app de clima do sistema</string>
<string name="appmanager_weather_activate">Ativar app de clima do sistema</string>
<string name="appmanager_weather_deactivate">Desativar app de clima do sistema</string>
<string name="appmanager_weather_install_provider">Instalar notificações do app de clima</string>
<string name="app_configure">Configurar</string>
<string name="app_move_to_top">Mover para o topo</string>
<!--Strings related to AppBlacklist-->
<string name="title_activity_appblacklist">Blacklist de notificações</string>
<string name="title_activity_appblacklist">Bloqueio de notificações</string>
<!--Strings related to FwAppInstaller-->
<string name="title_activity_fw_app_insaller">Instalador FW/App</string>
<string name="fw_upgrade_notice">Você está prestes a instalar o firmware %s no lugar do atual em sua Mi Band.</string>
<string name="miband_firmware_known">O firmware foi testado e é compatível com Gadgetbridge.</string>
<string name="fw_upgrade_notice">Está prestes a instalar o firmware %s no lugar do atual na sua Mi Band.</string>
<string name="miband_firmware_known">O firmware foi testado e é compatível com o Gadgetbridge.</string>
<!--Strings related to Settings-->
<string name="title_activity_settings">Configurações</string>
<string name="pref_header_general">Configurações Gerais</string>
<string name="pref_title_general_autoconnectonbluetooth">Conecte o dispositivo com o ligar o Bluetooth</string>
<string name="pref_title_general_autoconnectonbluetooth">Ligar ao dispositivo ao ativar o Bluetooth</string>
<string name="pref_title_general_autostartonboot">Iniciar automaticamente</string>
<string name="pref_title_general_autocreonnect">Reconectar automaticamente</string>
<string name="pref_title_audo_player">Player de música preferencial</string>
<string name="pref_title_general_autocreonnect">Religar automaticamente</string>
<string name="pref_title_audo_player">Aplicação de música preferencial</string>
<string name="pref_default">Padrão</string>
<string name="pref_header_datetime">Data e Hora</string>
<string name="pref_title_datetime_syctimeonconnect">Sincronizar hora</string>
@ -51,33 +51,33 @@
<string name="pref_theme_dark">Escuro</string>
<string name="pref_title_language">Idioma</string>
<string name="pref_title_minimize_priority">Ocultar notificações do Gadgetbridge</string>
<string name="pref_summary_minimize_priority_off">Exibir ícone na barra de status e nas notificações na tela inicial</string>
<string name="pref_summary_minimize_priority_on">Ocultar ícone na barra de status e nas notificações na tela inicial</string>
<string name="pref_summary_minimize_priority_off">Exibir ícone na barra de status e nas notificações no ecrã inicial</string>
<string name="pref_summary_minimize_priority_on">Ocultar ícone na barra de status e nas notificações no ecrã inicial</string>
<string name="pref_header_notifications">Notificações</string>
<string name="pref_title_notifications_repetitions">Repetições</string>
<string name="pref_title_notifications_call">Chamadas de telefone</string>
<string name="pref_title_notifications_call">Chamadas telefónicas</string>
<string name="pref_title_notifications_sms">SMS</string>
<string name="pref_title_notifications_pebblemsg">Mensagens do Pebble</string>
<string name="pref_summary_notifications_pebblemsg">Suportar notificações de aplicações que enviam notificações pelo PebbleKit.</string>
<string name="pref_title_notifications_generic">Suportar notificações genéricas</string>
<string name="pref_title_whenscreenon">... e quando a tela estiver ligada</string>
<string name="pref_title_whenscreenon">... e quando o ecrã estiver ligado</string>
<string name="pref_title_notification_filter">Não perturbe</string>
<string name="pref_summary_notification_filter">Parar com notificações indesejadas enquanto estiver no modo Não Perturbe.</string>
<string name="pref_summary_notification_filter">Ignorar notificações indesejadas enquanto estiver no modo Não Perturbe.</string>
<string name="always">sempre</string>
<string name="when_screen_off">quando a tela estiver desligada</string>
<string name="when_screen_off">quando o ecrã estiver desligado</string>
<string name="never">nunca</string>
<string name="pref_header_privacy">Privacidade</string>
<string name="pref_title_call_privacy_mode">Modo de chamada privada</string>
<string name="pref_call_privacy_mode_off">Exibir nome e número</string>
<string name="pref_call_privacy_mode_name">Ocultar nome e exibir número</string>
<string name="pref_call_privacy_mode_complete">Ocultar nome e número</string>
<string name="pref_blacklist">Apps em Blacklist</string>
<string name="pref_blacklist">Aplicações ignoradas</string>
<string name="pref_header_cannned_messages">Histórico de mensagens</string>
<string name="pref_title_canned_replies">Respostas</string>
<string name="pref_title_canned_reply_suffix">Sufixo comum</string>
<string name="pref_title_canned_messages_dismisscall">Chamadas recusadas</string>
<string name="pref_title_canned_messages_set">Atualizar no Pebble</string>
<string name="pref_header_development">Opções do desenvolvedor</string>
<string name="pref_header_development">Opções do programador</string>
<string name="pref_title_development_miaddr">Endereço do Mi Band</string>
<string name="pref_title_pebble_settings">Configurações Pebble</string>
<string name="pref_header_activitytrackers">Ativar monitores</string>
@ -85,48 +85,48 @@
<string name="pref_title_pebble_sync_health">Sincronizar com Pebble Health</string>
<string name="pref_title_pebble_sync_misfit">Sincronizar com Misfit</string>
<string name="pref_title_pebble_sync_morpheuz">Sincronizar com Morpheuz</string>
<string name="pref_summary_enable_pebblekit">Habilitar suporte experimental ao App Android que use PebbleKit</string>
<string name="pref_summary_enable_pebblekit">Ativar suporte experimental a Apps Android que usem PebbleKit</string>
<string name="pref_title_sunrise_sunset">Despertar e pôr do sol</string>
<string name="pref_summary_sunrise_sunset">Enviar despertar e pôr do sol baseado na localização do pebble</string>
<string name="pref_summary_sunrise_sunset">Enviar despertar e pôr do sol com base na localização do pebble</string>
<string name="pref_title_autoremove_notifications">Auto remover notificações rejeitadas</string>
<string name="pref_summary_autoremove_notifications">Notificações são automaticamente removidas quando rejeitadas no Android</string>
<string name="pref_title_pebble_privacy_mode">Modo de privacidade</string>
<string name="pref_pebble_privacy_mode_off">Notificações</string>
<string name="pref_pebble_privacy_mode_content">Deslocar texto de notificações que extrapolar a tela </string>
<string name="pref_pebble_privacy_mode_content">Deslocar texto de notificações que extravasar o ecrã </string>
<string name="pref_pebble_privacy_mode_complete">Apenas mostrar ícone de notificações</string>
<string name="pref_header_location">Localização</string>
<string name="pref_title_location_aquire">Obter localização</string>
<string name="pref_title_location_latitude">Latitude</string>
<string name="pref_title_location_longitude">Longitude</string>
<string name="pref_title_location_keep_uptodate">Mantenha a localização atualizada</string>
<string name="pref_summary_location_keep_uptodate">Tente obter a localização online, use dados armazenados como fallback</string>
<string name="toast_enable_networklocationprovider">Por favor, habilite localização de rede</string>
<string name="pref_summary_location_keep_uptodate">Tente obter a localização online, use dados armazenados como alternativa</string>
<string name="toast_enable_networklocationprovider">Por favor, ative a localização de rede</string>
<string name="toast_aqurired_networklocation">localização obtida</string>
<string name="pref_title_pebble_forceprotocol">Forçar o protocolo de notificação</string>
<string name="pref_summary_pebble_forceprotocol">Esta opção força o uso do protocolo de notificação mais recente. HABILITE APENAS SE SABE O QUE ESTÁ FAZENDO!</string>
<string name="pref_title_pebble_forceuntested">Habilitar recursos não certificados</string>
<string name="pref_summary_pebble_forceuntested">Habilitar recursos não certificados. FAÇA ISSO SE SOUBER O QUE REALMENTE ESTÁ FAZENDO!</string>
<string name="pref_title_pebble_forcele">Sempre preferir BLE</string>
<string name="pref_summary_pebble_forceprotocol">Esta opção força o uso do protocolo de notificação mais recente. APENAS ATIVE SE SOUBER O QUE ESTÁ A FAZER!</string>
<string name="pref_title_pebble_forceuntested">Permitir recursos não certificados</string>
<string name="pref_summary_pebble_forceuntested">Permitir recursos não certificados. APENAS ATIVE SE SOUBER O QUE ESTÁ A FAZER!</string>
<string name="pref_title_pebble_forcele">Preferir sempre BLE</string>
<string name="pref_title_unit_system">Unidades</string>
<string name="pref_title_timeformat">Formato da hora</string>
<string name="pref_title_screentime">Duração de tela</string>
<string name="not_connected">desconectado</string>
<string name="connecting">conectando</string>
<string name="connected">conectado</string>
<string name="pref_title_screentime">Duração do ecrã</string>
<string name="not_connected">desligado</string>
<string name="connecting">a ligar</string>
<string name="connected">ligado</string>
<string name="unknown_state">estado desconhecido</string>
<string name="test">Teste</string>
<string name="test_notification">Teste de notificação</string>
<string name="test_notification">Teste de notificações</string>
<string name="bluetooth_is_not_supported_">Bluetooth não suportado</string>
<string name="bluetooth_is_disabled_">Bluetooth desabilitado</string>
<string name="bluetooth_is_disabled_">Bluetooth desligado</string>
<string name="installation_failed_">falha na instalação!</string>
<string name="installation_successful">instalação bem sucedida</string>
<string name="initialized">inicializado</string>
<string name="title_activity_discovery">Dispositivo encontrado</string>
<string name="discovery_stop_scanning">Parar com a busca</string>
<string name="discovery_start_scanning">Iniciar busca</string>
<string name="action_discover">Conecte novo dispositivo</string>
<string name="title_activity_android_pairing">Parear dispositivo</string>
<string name="pairing">Pareando com %s...</string>
<string name="discovery_stop_scanning">Terminar a procura</string>
<string name="discovery_start_scanning">Iniciar a procura</string>
<string name="action_discover">Ligue o novo dispositivo</string>
<string name="title_activity_android_pairing">Emparelhar dispositivo</string>
<string name="pairing">A emparelhar com %s...</string>
<string name="male">masculino</string>
<string name="female">feminino</string>
<string name="other">outro</string>
@ -137,7 +137,7 @@
<string name="miband_prefs_alias">Nome/Apelido</string>
<string name="pref_header_vibration_count">Quantidade de vibrações</string>
<string name="title_activity_sleepmonitor">Monitor de sono</string>
<string name="pref_write_logfiles">Escrever arquivos de Log</string>
<string name="pref_write_logfiles">Escrever arquivos de registo</string>
<string name="initializing">Inicializando</string>
<string name="vibration_profile_short">Pequeno</string>
<string name="vibration_profile_medium">Médio</string>
@ -150,10 +150,10 @@
<string name="pref_screen_notification_profile_generic">Notificação genérica</string>
<string name="pref_screen_notification_profile_email">Notificação de email</string>
<string name="pref_screen_notification_profile_incoming_call">Notificações de chamadas</string>
<string name="pref_screen_notification_profile_generic_chat">Bate papo</string>
<string name="pref_screen_notification_profile_generic_chat">Conversas</string>
<string name="pref_screen_notification_profile_generic_navigation">Navegação</string>
<string name="pref_screen_notification_profile_generic_social">Rede social</string>
<string name="title_activity_charts">Sua atividade</string>
<string name="title_activity_charts">A sua atividade</string>
<string name="title_activity_set_alarm">Configurar Alarmes</string>
<string name="controlcenter_start_configure_alarms">Configurar alarmes</string>
<string name="title_activity_alarm_details">Detalhes do alarme</string>
@ -165,16 +165,16 @@
<string name="alarm_fri_short">Sex</string>
<string name="alarm_sat_short">Sab</string>
<string name="alarm_smart_wakeup">despertar inteligente</string>
<string name="user_feedback_miband_set_alarms_failed">Tem algum erro ao definir o alarme, tente novamente!</string>
<string name="user_feedback_miband_set_alarms_failed">Existiu um erro ao definir o alarme, tente novamente!</string>
<string name="user_feedback_miband_set_alarms_ok">Alarme enviado para o dispositivo!</string>
<string name="chart_no_data_synchronize">Sem data. Sincronizar com dispositivo?</string>
<string name="chart_no_data_synchronize">Sem data. Sincronizar com o dispositivo?</string>
<string name="miband_prefs_fitness_goal">Objetivo de passos por dia</string>
<string name="controlcenter_start_activitymonitor">Sua Atividade (ALPHA)</string>
<string name="controlcenter_start_activitymonitor">A Sua Atividade (ALPHA)</string>
<string name="installer_activity_unable_to_find_handler">Não foi possível encontrar um manipulador para instalar o arquivo.</string>
<string name="notif_battery_low_title">Gadget com bateria baixa!</string>
<string name="sleepchart_your_sleep">Seu Sono</string>
<string name="notif_battery_low_title">Dispositivo com bateria baixa!</string>
<string name="sleepchart_your_sleep">O Seu Sono</string>
<string name="weekstepschart_steps_a_week">Passos na semana</string>
<string name="activity_sleepchart_activity_and_sleep">Sua Atividade e Sono</string>
<string name="activity_sleepchart_activity_and_sleep">A Sua Atividade e Sono</string>
<string name="updating_firmware">Atualizando Firmware...</string>
<string name="fwapp_install_device_not_ready">Arquivo não pode ser instalado, o dispositivo não está pronto.</string>
<string name="miband_fwinstaller_compatible_version">Versão compatível</string>
@ -184,44 +184,44 @@
<string name="updatefirmwareoperation_update_complete_rebooting">Instalação do Firmware completa, reiniciando o dispositivo...</string>
<string name="updatefirmwareoperation_write_failed">Falha ao instalar o Firmware</string>
<string name="chart_steps">Passos</string>
<string name="liveactivity_live_activity">Atividade ao vivo</string>
<string name="liveactivity_live_activity">Atividade em Tempo Real</string>
<string name="live_activity_steps_history">Histórico de passos</string>
<string name="live_activity_current_steps_per_minute">Passos/min atuais</string>
<string name="live_activity_total_steps">Total de passos</string>
<string name="live_activity_steps_per_minute_history">Histórico de passos por minuto</string>
<string name="live_activity_start_your_activity">Iniciar sua atividade</string>
<string name="live_activity_start_your_activity">Iniciar a sua atividade</string>
<string name="abstract_chart_fragment_kind_activity">Atividade</string>
<string name="abstract_chart_fragment_kind_light_sleep">Sono leve</string>
<string name="abstract_chart_fragment_kind_deep_sleep">Sono pesado</string>
<string name="abstract_chart_fragment_kind_deep_sleep">Sono profundo</string>
<string name="abstract_chart_fragment_kind_not_worn">Não utilizado</string>
<string name="device_not_connected">Desconectado.</string>
<string name="user_feedback_all_alarms_disabled">Todos os alarmes desabilitados</string>
<string name="device_not_connected">Desligado.</string>
<string name="user_feedback_all_alarms_disabled">Todos os alarmes desligados</string>
<string name="pref_title_keep_data_on_device">Manter dados de atividade no dispositivo</string>
<string name="miband_fwinstaller_incompatible_version">Firmware incompatível</string>
<string name="fwinstaller_firmware_not_compatible_to_device">Este firmware não é compatível com seu dispositivo</string>
<string name="miband_prefs_reserve_alarm_calendar">Alarmes reservados para eventos próximos</string>
<string name="dateformat_time">Hora</string>
<string name="waiting_for_reconnect">aguarde para reconectar</string>
<string name="waiting_for_reconnect">aguarde para tornar a ligar</string>
<string name="activity_prefs_about_you">Sobre você</string>
<string name="activity_prefs_year_birth">Ano de anoversário</string>
<string name="activity_prefs_gender">Gênero</string>
<string name="activity_prefs_year_birth">Ano de nascimento</string>
<string name="activity_prefs_gender">Género</string>
<string name="activity_prefs_height_cm">Altura em cm</string>
<string name="activity_prefs_weight_kg">Peso em kg</string>
<string name="authenticating">autenticando</string>
<string name="authentication_required">autenticação requerida</string>
<string name="authenticating">a autenticar</string>
<string name="authentication_required">autenticação necessária</string>
<string name="add_widget">Adicionar widget</string>
<string name="activity_prefs_sleep_duration">Preferir duração de sono em horas</string>
<string name="updatefirmwareoperation_update_in_progress">Atualização de Firmware em progresso</string>
<string name="activity_prefs_sleep_duration">Preferir duração do sono em horas</string>
<string name="updatefirmwareoperation_update_in_progress">Atualização de Firmware em curso</string>
<string name="updatefirmwareoperation_firmware_not_sent">Firmware não enviado</string>
<string name="dbmanagementactivity_import_data_title">Importar dados?</string>
<string name="dbmanagementactivity_import_successful">Sucesso ao importar.</string>
<string name="dbmanagementactivity_overwrite">Sobrepor</string>
<string name="dbmanagementactivity_import_successful">Dados importados com sucesso.</string>
<string name="dbmanagementactivity_overwrite">Escrever por cima</string>
<string name="Cancel">Cancelar</string>
<string name="Delete">Apagar</string>
<!--Strings related to Vibration Activity-->
<string name="title_activity_vibration">Vibração</string>
<!--Strings related to Pebble Pairing Activity-->
<string name="title_activity_pebble_pairing">Pareando Pebble</string>
<string name="title_activity_pebble_pairing">A emparelhar Pebble</string>
<string name="unit_metric">Métrico</string>
<string name="unit_imperial">Imperial</string>
<string name="pref_screen_notification_profile_alarm_clock">Alarme</string>

View File

@ -1,9 +0,0 @@
<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

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="textColorPrimary" format="color" />
<attr name="textColorSecondary" format="color" />
<attr name="textColorTertiary" format="color" />
<attr name="chart_deep_sleep" format="color" />
<attr name="chart_light_sleep" format="color" />
<attr name="chart_activity" format="color" />

View File

@ -7,11 +7,14 @@
<color name="primarydark_dark" type="color">#f0f03000</color>
<color name="accent" type="color">#0091ea</color>
<color name="primarytext_light" type="color">#000000</color>
<color name="primarytext_dark" type="color">#ffffff</color>
<color name="secondarytext" type="color">#ff808080</color>
<color name="tertiarytext_light" type="color">#ffd0d0d0</color>
<color name="tertiarytext_dark" type="color">#ff606060</color>
<color name="divider" type="color">#1f000000</color>
<color name="chart_heartrate" type="color">#ffab40</color>

View File

@ -306,6 +306,8 @@
<string name="updatefirmwareoperation_update_complete_rebooting">Firmware installation complete, rebooting device…</string>
<string name="updatefirmwareoperation_write_failed">Firmware write failed</string>
<string name="chart_steps">Steps</string>
<string name="calories">Calories</string>
<string name="distance">Distance</string>
<string name="liveactivity_live_activity">Live Activity</string>
<string name="weeksteps_today_steps_description">Steps today, target: %1$s</string>
<string name="pref_title_dont_ack_transfer">Do not ack activity data transfer</string>
@ -370,10 +372,12 @@
<string name="dbmanagementactivvity_cannot_access_export_path">Cannot access export path. Please contact the developers.</string>
<string name="dbmanagementactivity_exported_to">Exported to: %1$s</string>
<string name="dbmanagementactivity_error_exporting_db">"Error exporting DB: %1$s"</string>
<string name="dbmanagementactivity_error_exporting_shared">"Error exporting preference: %1$s"</string>
<string name="dbmanagementactivity_import_data_title">Import Data?</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Really overwrite the current database? All your current activity data (if any) will be lost.</string>
<string name="dbmanagementactivity_import_successful">Import successful.</string>
<string name="dbmanagementactivity_error_importing_db">"Error importing DB: %1$s"</string>
<string name="dbmanagementactivity_error_importing_shared">"Error importing preference: %1$s"</string>
<string name="dbmanagementactivity_delete_activity_data_title">Delete Activity Data?</string>
<string name="dbmanagementactivity_really_delete_entire_db">Really delete the entire database? All your activity data and information about your devices will be lost.</string>
<string name="dbmanagementactivity_database_successfully_deleted">Data successfully deleted.</string>
@ -413,4 +417,13 @@
<string name="mi2_enable_text_notifications">Text notifications</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Needs firmware >= 1.0.1.28 and Mili_pro.ft* installed.]]></string>
<string name="off">off</string>
<string name="discovery_attempting_to_pair">Attempting to pair with %1$s</string>
<string name="discovery_bonding_failed_immediately">Bonding with %1$s failed immediately.</string>
<string name="discovery_trying_to_connect_to">Trying to connect to: %1$s</string>
<string name="discovery_enable_bluetooth">Enable Bluetooth to discover devices.</string>
<string name="discovery_successfully_bonded">Successfully bonded with %1$s.</string>
<string name="discovery_pair_title">Pair with %1$s?</string>
<string name="discovery_pair_question">Select Pair to pair your devices. If this fails, try again without pairing.</string>
<string name="discovery_yes_pair">Pair</string>
<string name="discovery_dont_pair">Don\'t Pair</string>
</resources>

View File

@ -1,11 +1,12 @@
<resources>
<style name="GadgetbridgeTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:textColorPrimary">@color/primarytext_light</item>
<item name="android:textColorSecondary">@color/secondarytext</item>
<item name="textColorPrimary">@color/primarytext_light</item>
<item name="textColorSecondary">@color/secondarytext</item>
<item name="textColorTertiary">@color/tertiarytext_light</item>
<item name="colorPrimary">@color/primary_light</item>
<item name="colorPrimaryDark">@color/primarydark_light</item>
<item name="android:textColorTertiary">@color/tertiarytext_light</item>
<item name="colorAccent">@color/accent</item>
<item name="chart_deep_sleep">@color/chart_deep_sleep_light</item>
@ -21,11 +22,12 @@
<!-- dark theme -->
<style name="GadgetbridgeThemeDark" parent="Theme.AppCompat">
<item name="android:textColorPrimary">@color/primarytext_dark</item>
<item name="android:textColorSecondary">@color/secondarytext</item>
<item name="textColorPrimary">@color/primarytext_dark</item>
<item name="textColorSecondary">@color/secondarytext</item>
<item name="textColorTertiary">@color/tertiarytext_dark</item>
<item name="colorPrimary">@color/primary_dark</item>
<item name="colorPrimaryDark">@color/primarydark_dark</item>
<item name="android:textColorTertiary">@color/tertiarytext_dark</item>
<item name="colorAccent">@color/accent</item>
<item name="chart_deep_sleep">@color/chart_deep_sleep_dark</item>

View File

@ -1,5 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog>
<release version="next">
<change>Applied some material design guidelines to Charts and (pebble) app management
</change>
<change>Pebble: improve compatiblity with watchapp configuration pages</change>
</release>
<release version="0.18.4" versioncode="91">
<change>Mi Band 2: Display realtime steps in Live Activity</change>
<change>Mi Band: Attempt to recognize Mi Band model with hwVersion = 8</change>
<change>Make Buttons in the main activity easier to hit</change>
<change>Alarms activity improvements and fixes</change>
</release>
<release version="0.18.3" versioncode="90">
<change>Fix bug that caused the same value in weekly charts for every day on Android 6 and older</change>
</release>
<release version="0.18.2" versioncode="89">
<change>Mi2: Fix crash on "chat" or "social network" text notification (#603)</change>
</release>
<release version="0.18.1" versioncode="88">
<change>Pebble: Fix Firmware insstallation on Pebble Time Round (broken since 0.16.0)</change>
<change>Start VibrationActivity when using "find device" button with Vibratissimo</change>
<change>Support material fork of K9</change>
</release>
<release version="0.18.0" versioncode="87">
<change>All new GUI for the control center</change>
<change>Add Portuguese pt_PT and pt_BR translations</change>

View File

@ -8,6 +8,7 @@ import java.util.GregorianCalendar;
import nodomain.freeyourgadget.gadgetbridge.Logging;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandDateConverter;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
/**

View File

@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.android.tools.build:gradle:2.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files