Settings: Make google's battery widget work
Change-Id: I763a3bdb7bc0385fce04fe2635f06e601f9557ab Signed-off-by: aswin7469 <aswinas@pixysos.com>
This commit is contained in:
@@ -5547,6 +5547,21 @@
|
|||||||
android:permission="android.permission.NETWORK_SETTINGS"
|
android:permission="android.permission.NETWORK_SETTINGS"
|
||||||
android:theme="@style/Theme.SpaLib.Dialog">
|
android:theme="@style/Theme.SpaLib.Dialog">
|
||||||
</activity>
|
</activity>
|
||||||
|
<!-- Phone and bluetooth device battery data -->
|
||||||
|
<service
|
||||||
|
android:name="com.android.settings.fuelgauge.batterydata.BatteryDataFetchService"
|
||||||
|
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||||
|
android:exported="false"
|
||||||
|
android:process=":usage_data_loader"/>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name="com.android.settings.fuelgauge.batterydata.BatteryDataBroadcastReceiver"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="settings.intelligence.battery.action.FETCH_BATTERY_USAGE_DATA"/>
|
||||||
|
<action android:name="settings.intelligence.battery.action.FETCH_BLUETOOTH_BATTERY_DATA"/>
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.android.settings.network.SatelliteWarningDialogActivity"
|
android:name="com.android.settings.network.SatelliteWarningDialogActivity"
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user