diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 14b45c49194..0fec1f94307 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5547,6 +5547,21 @@ android:permission="android.permission.NETWORK_SETTINGS" android:theme="@style/Theme.SpaLib.Dialog"> + + + + + + + + + { + 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()); + } +} diff --git a/src/com/android/settings/fuelgauge/batterydata/BluetoothBatteryDataFetch.java b/src/com/android/settings/fuelgauge/batterydata/BluetoothBatteryDataFetch.java new file mode 100644 index 00000000000..d437cf5fd80 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterydata/BluetoothBatteryDataFetch.java @@ -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 cachedDevicesCopy = + localBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy(); + Log.d(TAG, "cachedDevices:" + cachedDevicesCopy); + if (cachedDevicesCopy == null || cachedDevicesCopy.isEmpty()) { + resultReceiver.send(0, Bundle.EMPTY); + return; + } + List 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 bluetoothWrapDataListKey = new ArrayList<>(); + ArrayList 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))); + } +}