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:theme="@style/Theme.SpaLib.Dialog">
|
||||
</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
|
||||
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