-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Settings: Make google's battery widget work
Change-Id: I763a3bdb7bc0385fce04fe2635f06e601f9557ab Signed-off-by: Jis G Jacob <[email protected]>
- Loading branch information
1 parent
5f5c963
commit 8dd0e70
Showing
4 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
src/com/android/settings/fuelgauge/batterydata/BatteryDataBroadcastReceiver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// | ||
// Copyright (C) 2022 The Project Mia | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
package com.android.settings.fuelgauge.batterydata; | ||
|
||
import android.content.BroadcastReceiver; | ||
import android.content.Context; | ||
import android.content.Intent; | ||
import android.util.Log; | ||
|
||
public final class BatteryDataBroadcastReceiver extends BroadcastReceiver { | ||
|
||
private static final String TAG = "BatteryDataBroadcastReceiver"; | ||
|
||
public boolean mFetchBatteryUsageData; | ||
|
||
@Override | ||
public void onReceive(Context context, Intent intent) { | ||
String batteryData = intent.getAction(); | ||
switch (batteryData) { | ||
// Fetch device usage data | ||
case "settings.intelligence.battery.action.FETCH_BATTERY_USAGE_DATA": | ||
mFetchBatteryUsageData = true; | ||
BatteryDataFetchService.enqueueWork(context); | ||
break; | ||
// Fetch bluetooth device usage data | ||
case "settings.intelligence.battery.action.FETCH_BLUETOOTH_BATTERY_DATA": | ||
try { | ||
BluetoothBatteryDataFetch.returnBluetoothDevices(context, intent); | ||
} catch (Exception e) { | ||
Log.e(TAG, "returnBluetoothDevices() error: ", e); | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/com/android/settings/fuelgauge/batterydata/BatteryDataFetchService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// | ||
// Copyright (C) 2022 The Project Mia | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
package com.android.settings.fuelgauge.batterydata; | ||
|
||
import android.content.Context; | ||
import android.content.Intent; | ||
import android.os.AsyncTask; | ||
import android.os.BatteryStatsManager; | ||
import android.os.BatteryUsageStats; | ||
import android.os.BatteryUsageStatsQuery; | ||
import android.util.Log; | ||
|
||
import androidx.annotation.NonNull; | ||
import androidx.core.app.JobIntentService; | ||
|
||
import java.util.List; | ||
|
||
public class BatteryDataFetchService extends JobIntentService { | ||
|
||
private static final String TAG = "BatteryDataFetchService"; | ||
private static final Intent JOB_INTENT = new Intent("action.LOAD_BATTERY_USAGE_DATA"); | ||
|
||
public static void enqueueWork(final Context context) { | ||
AsyncTask.execute(() -> { | ||
loadUsageDataSafely(context); | ||
}); | ||
} | ||
|
||
@Override | ||
protected void onHandleWork(@NonNull Intent intent) { | ||
loadUsageDataSafely(this); | ||
} | ||
|
||
private static void loadUsageDataSafely(Context context) { | ||
try { | ||
loadUsageData(context); | ||
} catch (RuntimeException e) { | ||
Log.e(TAG, "Fail load usage data:" + e); | ||
} | ||
} | ||
|
||
private static void loadUsageData(Context context) { | ||
BatteryUsageStats batteryUsageStats = context | ||
.getSystemService(BatteryStatsManager.class) | ||
.getBatteryUsageStats(new BatteryUsageStatsQuery.Builder() | ||
.includeBatteryHistory() | ||
.build()); | ||
} | ||
} |
171 changes: 171 additions & 0 deletions
171
src/com/android/settings/fuelgauge/batterydata/BluetoothBatteryDataFetch.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
// | ||
// Copyright (C) 2022 The Project Mia | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
package com.android.settings.fuelgauge.batterydata; | ||
|
||
import android.bluetooth.BluetoothAdapter; | ||
import android.bluetooth.BluetoothClass; | ||
import android.bluetooth.BluetoothDevice; | ||
import android.bluetooth.BluetoothManager; | ||
import android.content.ContentValues; | ||
import android.content.Context; | ||
import android.content.Intent; | ||
import android.os.AsyncTask; | ||
import android.os.Bundle; | ||
import android.os.Parcel; | ||
import android.os.Parcelable; | ||
import android.os.ResultReceiver; | ||
import android.util.Log; | ||
|
||
import com.android.internal.annotations.VisibleForTesting; | ||
import com.android.settingslib.bluetooth.CachedBluetoothDevice; | ||
import com.android.settingslib.bluetooth.LocalBluetoothManager; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
import java.util.function.Consumer; | ||
import java.util.stream.Collectors; | ||
|
||
public final class BluetoothBatteryDataFetch { | ||
|
||
private static final String TAG = "BluetoothBatteryDataFetch"; | ||
|
||
@VisibleForTesting | ||
public static LocalBluetoothManager mLocalBluetoothManager; | ||
private static Context context; | ||
private static Intent intent; | ||
|
||
private static String emptyIfNull(String value) { | ||
return value == null ? "" : value; | ||
} | ||
|
||
public static ContentValues wrapBluetoothData( | ||
Context context, CachedBluetoothDevice cachedBluetoothDevice, | ||
boolean nonbuds) { | ||
BluetoothDevice device = cachedBluetoothDevice.getDevice(); | ||
|
||
ContentValues contentValues = new ContentValues(); | ||
contentValues.put("type", device.getType()); | ||
contentValues.put("name", emptyIfNull(device.getName())); | ||
contentValues.put("alias", emptyIfNull(device.getAlias())); | ||
contentValues.put("address", emptyIfNull(device.getAddress())); | ||
contentValues.put("batteryLevel", device.getBatteryLevel()); | ||
|
||
putStringMetadata(contentValues, "hardwareVersion", device.getMetadata( | ||
BluetoothDevice.METADATA_HARDWARE_VERSION)); | ||
putStringMetadata(contentValues, "batteryLevelRight", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)); | ||
putStringMetadata(contentValues, "batteryLevelLeft", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)); | ||
putStringMetadata(contentValues, "batteryLevelCase", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY)); | ||
putStringMetadata(contentValues, "batteryChargingRight", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING)); | ||
putStringMetadata(contentValues, "batteryChargingLeft", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_LEFT_CHARGING)); | ||
putStringMetadata(contentValues, "batteryChargingCase", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING)); | ||
putStringMetadata(contentValues, "batteryChargingMain", device.getMetadata( | ||
BluetoothDevice.METADATA_MAIN_CHARGING)); | ||
if (nonbuds) { | ||
putStringMetadata(contentValues, "deviceIconMain", device.getMetadata( | ||
BluetoothDevice.METADATA_MAIN_ICON)); | ||
putStringMetadata(contentValues, "deviceIconCase", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_CASE_ICON)); | ||
putStringMetadata(contentValues, "deviceIconLeft", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON)); | ||
putStringMetadata(contentValues, "deviceIconRight", device.getMetadata( | ||
BluetoothDevice.METADATA_UNTETHERED_RIGHT_ICON)); | ||
} | ||
BluetoothClass bluetoothClass = device.getBluetoothClass(); | ||
if (bluetoothClass != null) { | ||
contentValues.put("bluetoothClass", marshall(bluetoothClass)); | ||
} | ||
return contentValues; | ||
} | ||
|
||
private static byte[] marshall(Parcelable parcelable) { | ||
Parcel obtain = Parcel.obtain(); | ||
parcelable.writeToParcel(obtain, 0); | ||
byte[] marshall = obtain.marshall(); | ||
obtain.recycle(); | ||
return marshall; | ||
} | ||
|
||
private static void putStringMetadata( | ||
ContentValues contentValues, String key, byte[] value) { | ||
if (value == null || value.length == 0) { | ||
return; | ||
} | ||
contentValues.put(key, new String(value)); | ||
} | ||
|
||
public static void returnBluetoothDevices(Context context, Intent intent) { | ||
AsyncTask.execute(() -> returnBluetoothDevicesInner(context, intent)); | ||
} | ||
|
||
public static void returnBluetoothDevicesInner(Context context, Intent intent) { | ||
ResultReceiver resultReceiver = intent.getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER); | ||
if (resultReceiver == null) { | ||
Log.w(TAG, "No result receiver found from intent"); | ||
return; | ||
} | ||
if (mLocalBluetoothManager == null) { | ||
mLocalBluetoothManager = LocalBluetoothManager.getInstance(context, null); | ||
} | ||
BluetoothAdapter adapter = context.getSystemService(BluetoothManager.class).getAdapter(); | ||
if (adapter == null || !adapter.isEnabled() || mLocalBluetoothManager == null) { | ||
Log.w(TAG, "BluetoothAdapter not present or not enabled"); | ||
resultReceiver.send(1, null); | ||
return; | ||
} | ||
sendAndFilterBluetoothData(context, resultReceiver, mLocalBluetoothManager, | ||
intent.getBooleanExtra("extra_fetch_icon", false)); | ||
} | ||
|
||
public static void sendAndFilterBluetoothData(Context context, | ||
ResultReceiver resultReceiver, | ||
LocalBluetoothManager localBluetoothManager, | ||
boolean cache) { | ||
long start = System.currentTimeMillis(); | ||
Collection<CachedBluetoothDevice> cachedDevicesCopy = | ||
localBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy(); | ||
Log.d(TAG, "cachedDevices:" + cachedDevicesCopy); | ||
if (cachedDevicesCopy == null || cachedDevicesCopy.isEmpty()) { | ||
resultReceiver.send(0, Bundle.EMPTY); | ||
return; | ||
} | ||
List<CachedBluetoothDevice> connectedDevices = cachedDevicesCopy.stream() | ||
.filter(CachedBluetoothDevice::isConnected) | ||
.collect(Collectors.toList()); | ||
Log.d(TAG, "Connected devices:" + connectedDevices); | ||
if (connectedDevices.isEmpty()) { | ||
resultReceiver.send(0, Bundle.EMPTY); | ||
return; | ||
} | ||
ArrayList<ContentValues> bluetoothWrapDataListKey = new ArrayList<>(); | ||
ArrayList<BluetoothDevice> bluetoothParcelableList = new ArrayList<>(); | ||
connectedDevices.forEach(cachedBluetoothDevice -> { | ||
BluetoothDevice device = cachedBluetoothDevice.getDevice(); | ||
bluetoothParcelableList.add(device); | ||
try { | ||
bluetoothWrapDataListKey.add( | ||
wrapBluetoothData(context, cachedBluetoothDevice, cache)); | ||
} catch (Exception e) { | ||
Log.e(TAG, "Wrap bluetooth data failed: " + device, e); | ||
} | ||
}); | ||
Bundle bundle = new Bundle(); | ||
bundle.putParcelableArrayList("bluetoothParcelableListKey", bluetoothParcelableList); | ||
if (!bluetoothWrapDataListKey.isEmpty()) { | ||
bundle.putParcelableArrayList("bluetoothWrapDataListKey", bluetoothWrapDataListKey); | ||
} | ||
resultReceiver.send(0, bundle); | ||
Log.d(TAG, String.format("Send and filter bluetooth data size=%d in %d/ms", | ||
bluetoothWrapDataListKey.size(), (System.currentTimeMillis() - start))); | ||
} | ||
} |