Merge "Add non-app power consumers to the PowerStatsViewer"
diff --git a/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml b/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml
index 378d035..28ea05f 100644
--- a/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml
+++ b/core/tests/powertests/PowerStatsViewer/AndroidManifest.xml
@@ -35,8 +35,7 @@
</intent-filter>
</activity>
- <activity android:name=".AppPickerActivity"
- android:label="Power Stats - Select an App"/>
-
+ <activity android:name=".PowerConsumerPickerActivity"
+ android:label="Select a power consumer"/>
</application>
</manifest>
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/app_info_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_info_layout.xml
similarity index 98%
rename from core/tests/powertests/PowerStatsViewer/res/layout/app_info_layout.xml
rename to core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_info_layout.xml
index fe6fe2d..fbd0ebd 100644
--- a/core/tests/powertests/PowerStatsViewer/res/layout/app_info_layout.xml
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_info_layout.xml
@@ -52,7 +52,7 @@
android:textAppearance="?android:attr/textAppearanceListItem"/>
<TextView
- android:id="@+id/uid"
+ android:id="@+id/details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_activity_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_activity_layout.xml
new file mode 100644
index 0000000..ecc89f0
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_activity_layout.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tab_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <androidx.viewpager.widget.ViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+</LinearLayout>
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/app_picker_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_layout.xml
similarity index 96%
rename from core/tests/powertests/PowerStatsViewer/res/layout/app_picker_layout.xml
rename to core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_layout.xml
index 6f28999..bea38c1 100644
--- a/core/tests/powertests/PowerStatsViewer/res/layout/app_picker_layout.xml
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/power_consumer_picker_layout.xml
@@ -20,7 +20,7 @@
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
- android:id="@+id/app_list_view"
+ android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
diff --git a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml b/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml
index 9949418..238e238 100644
--- a/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml
+++ b/core/tests/powertests/PowerStatsViewer/res/layout/power_stats_viewer_layout.xml
@@ -42,7 +42,7 @@
android:paddingStart="10dp"
android:paddingEnd="10dp">
- <include layout="@layout/app_info_layout"/>
+ <include layout="@layout/power_consumer_info_layout"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppInfoHelper.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppInfoHelper.java
deleted file mode 100644
index 8526561..0000000
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppInfoHelper.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.frameworks.core.powerstatsviewer;
-
-import android.annotation.Nullable;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Process;
-
-import com.android.internal.os.BatterySipper;
-
-class AppInfoHelper {
-
- private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
-
- public static class AppInfo {
- public int uid;
- public CharSequence label;
- public double powerMah;
- public ApplicationInfo iconInfo;
- public CharSequence packages;
- }
-
- @Nullable
- public static AppInfo makeApplicationInfo(PackageManager packageManager, int uid,
- @Nullable BatterySipper sipper) {
- if (sipper != null && sipper.drainType != BatterySipper.DrainType.APP) {
- return null;
- }
-
- String packageWithHighestDrain = null;
-
- AppInfo info = new AppInfo();
- info.uid = uid;
- if (sipper != null) {
- sipper.sumPower();
- info.powerMah = sipper.totalSmearedPowerMah;
- packageWithHighestDrain = sipper.packageWithHighestDrain;
- }
- if (info.uid == Process.ROOT_UID) {
- info.label = "<root>";
- } else {
- String[] packages = packageManager.getPackagesForUid(info.uid);
- String primaryPackageName = null;
- if (info.uid == Process.SYSTEM_UID) {
- primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
- } else if (packages != null) {
- for (String name : packages) {
- primaryPackageName = name;
- if (name.equals(packageWithHighestDrain)) {
- break;
- }
- }
- }
-
- if (primaryPackageName != null) {
- try {
- ApplicationInfo applicationInfo =
- packageManager.getApplicationInfo(primaryPackageName, 0);
- info.label = applicationInfo.loadLabel(packageManager);
- info.iconInfo = applicationInfo;
- } catch (PackageManager.NameNotFoundException e) {
- info.label = primaryPackageName;
- }
- } else if (packageWithHighestDrain != null) {
- info.label = packageWithHighestDrain;
- }
-
- if (packages != null && packages.length > 0) {
- StringBuilder sb = new StringBuilder();
- if (primaryPackageName != null) {
- sb.append(primaryPackageName);
- }
- for (String packageName : packages) {
- if (packageName.equals(primaryPackageName)) {
- continue;
- }
-
- if (sb.length() != 0) {
- sb.append(", ");
- }
- sb.append(packageName);
- }
-
- info.packages = sb;
- }
- }
-
- // Default the app icon to System Server. This includes root, dex2oat and other UIDs.
- if (info.iconInfo == null) {
- try {
- info.iconInfo =
- packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0);
- } catch (PackageManager.NameNotFoundException nameNotFoundException) {
- // Won't happen
- }
- }
- return info;
- }
-}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppPickerActivity.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppPickerActivity.java
deleted file mode 100644
index b4fc73c..0000000
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/AppPickerActivity.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.frameworks.core.powerstatsviewer;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.BatteryStats;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.UserManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.activity.ComponentActivity;
-import androidx.activity.result.contract.ActivityResultContract;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.loader.app.LoaderManager;
-import androidx.loader.content.Loader;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.frameworks.core.powerstatsviewer.AppInfoHelper.AppInfo;
-import com.android.internal.os.BatterySipper;
-import com.android.internal.os.BatteryStatsHelper;
-import com.android.settingslib.utils.AsyncLoaderCompat;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Picker, showing a sorted list of applications consuming power. Returns the selected
- * application UID or Process.INVALID_UID.
- */
-public class AppPickerActivity extends ComponentActivity {
- private static final String TAG = "AppPicker";
-
- public static final ActivityResultContract<Void, Integer> CONTRACT =
- new ActivityResultContract<Void, Integer>() {
- @NonNull
- @Override
- public Intent createIntent(@NonNull Context context, Void aVoid) {
- return new Intent(context, AppPickerActivity.class);
- }
-
- @Override
- public Integer parseResult(int resultCode, @Nullable Intent intent) {
- if (resultCode != RESULT_OK || intent == null) {
- return Process.INVALID_UID;
- }
- return intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
- }
- };
-
- private AppListAdapter mAppListAdapter;
- private RecyclerView mAppList;
- private View mLoadingView;
-
- private interface OnAppSelectedListener {
- void onAppSelected(int uid);
- }
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- getActionBar().setDisplayHomeAsUpEnabled(true);
-
- setContentView(R.layout.app_picker_layout);
-
- mLoadingView = findViewById(R.id.loading_view);
-
- mAppList = findViewById(R.id.app_list_view);
- mAppList.setLayoutManager(new LinearLayoutManager(this));
- mAppListAdapter = new AppListAdapter(AppPickerActivity.this::setSelectedUid);
- mAppList.setAdapter(mAppListAdapter);
-
- LoaderManager.getInstance(this).initLoader(0, null,
- new AppListLoaderCallbacks());
- }
-
- protected void setSelectedUid(int uid) {
- Intent intent = new Intent();
- intent.putExtra(Intent.EXTRA_UID, uid);
- setResult(RESULT_OK, intent);
- finish();
- }
-
- @Override
- public boolean onNavigateUp() {
- onBackPressed();
- return true;
- }
-
- private static class AppListLoader extends AsyncLoaderCompat<List<AppInfo>> {
- private final BatteryStatsHelper mStatsHelper;
- private final UserManager mUserManager;
- private final PackageManager mPackageManager;
-
- AppListLoader(Context context) {
- super(context);
- mUserManager = context.getSystemService(UserManager.class);
- mStatsHelper = new BatteryStatsHelper(context, false /* collectBatteryBroadcast */);
- mStatsHelper.create((Bundle) null);
- mStatsHelper.clearStats();
- mPackageManager = context.getPackageManager();
- }
-
- @Override
- public List<AppInfo> loadInBackground() {
- List<AppInfo> applicationList = new ArrayList<>();
-
- mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
- mUserManager.getUserProfiles());
-
- final List<BatterySipper> usageList = mStatsHelper.getUsageList();
- for (BatterySipper sipper : usageList) {
- AppInfo info =
- AppInfoHelper.makeApplicationInfo(mPackageManager, sipper.getUid(), sipper);
- if (info != null) {
- applicationList.add(info);
- }
- }
-
- applicationList.sort(
- Comparator.comparing((AppInfo a) -> a.powerMah).reversed());
- return applicationList;
- }
-
- @Override
- protected void onDiscardResult(List<AppInfo> result) {
- }
- }
-
- private class AppListLoaderCallbacks implements
- LoaderManager.LoaderCallbacks<List<AppInfo>> {
-
- @NonNull
- @Override
- public Loader<List<AppInfo>> onCreateLoader(int id, Bundle args) {
- return new AppListLoader(AppPickerActivity.this);
- }
-
- @Override
- public void onLoadFinished(@NonNull Loader<List<AppInfo>> loader,
- List<AppInfo> applicationList) {
- mAppListAdapter.setApplicationList(applicationList);
- mAppList.setVisibility(View.VISIBLE);
- mLoadingView.setVisibility(View.GONE);
- }
-
- @Override
- public void onLoaderReset(@NonNull Loader<List<AppInfo>> loader) {
- }
- }
-
- public class AppListAdapter extends RecyclerView.Adapter<AppViewHolder> {
- private final OnAppSelectedListener mListener;
- private List<AppInfo> mApplicationList;
-
- public AppListAdapter(OnAppSelectedListener listener) {
- mListener = listener;
- }
-
- void setApplicationList(List<AppInfo> applicationList) {
- mApplicationList = applicationList;
- notifyDataSetChanged();
- }
-
- @Override
- public int getItemCount() {
- return mApplicationList.size();
- }
-
- @NonNull
- @Override
- public AppViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
- LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
- View view = layoutInflater.inflate(R.layout.app_info_layout, viewGroup, false);
- return new AppViewHolder(view, mListener);
- }
-
- @Override
- public void onBindViewHolder(@NonNull AppViewHolder appViewHolder, int position) {
- AppInfo item = mApplicationList.get(position);
- appViewHolder.uid = item.uid;
- appViewHolder.titleView.setText(item.label);
- appViewHolder.uidView.setText(
- String.format(Locale.getDefault(), "UID: %d", item.uid));
- appViewHolder.powerView.setText(
- String.format(Locale.getDefault(), "%.1f mAh", item.powerMah));
- appViewHolder.iconView.setImageDrawable(
- item.iconInfo.loadIcon(getPackageManager()));
- if (item.packages != null) {
- appViewHolder.packagesView.setText(item.packages);
- appViewHolder.packagesView.setVisibility(View.VISIBLE);
- } else {
- appViewHolder.packagesView.setVisibility(View.GONE);
- }
- }
- }
-
- // View Holder used when displaying apps
- public static class AppViewHolder extends RecyclerView.ViewHolder
- implements View.OnClickListener {
- private final OnAppSelectedListener mListener;
-
- public int uid;
- public TextView titleView;
- public TextView uidView;
- public ImageView iconView;
- public TextView packagesView;
- public TextView powerView;
-
- AppViewHolder(View view, OnAppSelectedListener listener) {
- super(view);
- mListener = listener;
- view.setOnClickListener(this);
- titleView = view.findViewById(android.R.id.title);
- uidView = view.findViewById(R.id.uid);
- iconView = view.findViewById(android.R.id.icon);
- packagesView = view.findViewById(R.id.packages);
- powerView = view.findViewById(R.id.power_mah);
- powerView.setVisibility(View.VISIBLE);
- }
-
- @Override
- public void onClick(View v) {
- mListener.onAppSelected(uid);
- }
- }
-}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerInfoHelper.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerInfoHelper.java
new file mode 100644
index 0000000..6fec240
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerInfoHelper.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.core.powerstatsviewer;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Process;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.os.BatterySipper;
+
+import java.util.Locale;
+
+class PowerConsumerInfoHelper {
+
+ private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
+
+ public static class PowerConsumerInfo {
+ public String id;
+ public CharSequence label;
+ public double powerMah;
+ public ApplicationInfo iconInfo;
+ public CharSequence packages;
+ public CharSequence details;
+ }
+
+ @NonNull
+ public static PowerConsumerInfo makePowerConsumerInfo(PackageManager packageManager,
+ @NonNull BatterySipper sipper) {
+ PowerConsumerInfo info = new PowerConsumerInfo();
+ info.id = PowerStatsData.powerConsumerId(sipper);
+ sipper.sumPower();
+ info.powerMah = sipper.totalSmearedPowerMah;
+ switch (sipper.drainType) {
+ case APP: {
+ int uid = sipper.getUid();
+ info.details = String.format("UID: %d", uid);
+ String packageWithHighestDrain = sipper.packageWithHighestDrain;
+ if (uid == Process.ROOT_UID) {
+ info.label = "<root>";
+ } else {
+ String[] packages = packageManager.getPackagesForUid(uid);
+ String primaryPackageName = null;
+ if (uid == Process.SYSTEM_UID) {
+ primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
+ } else if (packages != null) {
+ for (String name : packages) {
+ primaryPackageName = name;
+ if (name.equals(packageWithHighestDrain)) {
+ break;
+ }
+ }
+ }
+
+ if (primaryPackageName != null) {
+ try {
+ ApplicationInfo applicationInfo =
+ packageManager.getApplicationInfo(primaryPackageName, 0);
+ info.label = applicationInfo.loadLabel(packageManager);
+ info.iconInfo = applicationInfo;
+ } catch (PackageManager.NameNotFoundException e) {
+ info.label = primaryPackageName;
+ }
+ } else if (packageWithHighestDrain != null) {
+ info.label = packageWithHighestDrain;
+ }
+
+ if (packages != null && packages.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ if (primaryPackageName != null) {
+ sb.append(primaryPackageName);
+ }
+ for (String packageName : packages) {
+ if (packageName.equals(primaryPackageName)) {
+ continue;
+ }
+
+ if (sb.length() != 0) {
+ sb.append(", ");
+ }
+ sb.append(packageName);
+ }
+
+ info.packages = sb;
+ }
+ }
+ break;
+ }
+ case USER:
+ info.label = "User";
+ info.details = String.format(Locale.getDefault(), "User ID: %d", sipper.userId);
+ break;
+ case AMBIENT_DISPLAY:
+ info.label = "Ambient display";
+ break;
+ case BLUETOOTH:
+ info.label = "Bluetooth";
+ break;
+ case CAMERA:
+ info.label = "Camera";
+ break;
+ case CELL:
+ info.label = "Cell";
+ break;
+ case FLASHLIGHT:
+ info.label = "Flashlight";
+ break;
+ case IDLE:
+ info.label = "Idle";
+ break;
+ case MEMORY:
+ info.label = "Memory";
+ break;
+ case OVERCOUNTED:
+ info.label = "Overcounted";
+ break;
+ case PHONE:
+ info.label = "Phone";
+ break;
+ case SCREEN:
+ info.label = "Screen";
+ break;
+ case UNACCOUNTED:
+ info.label = "Unaccounted";
+ break;
+ case WIFI:
+ info.label = "WiFi";
+ break;
+ }
+ // Default the app icon to System Server. This includes root, dex2oat and other UIDs.
+ if (info.iconInfo == null) {
+ try {
+ info.iconInfo =
+ packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0);
+ } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+ // Won't happen
+ }
+ }
+ return info;
+ }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerActivity.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerActivity.java
new file mode 100644
index 0000000..f56d113
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerActivity.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.core.powerstatsviewer;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.activity.result.contract.ActivityResultContract;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.material.tabs.TabLayout;
+
+/**
+ * Picker, showing a sorted lists of applications and other types of entities consuming power.
+ * Returns the selected entity ID or null.
+ */
+public class PowerConsumerPickerActivity extends FragmentActivity {
+
+ public static final ActivityResultContract<Void, String> CONTRACT =
+ new ActivityResultContract<Void, String>() {
+ @NonNull
+ @Override
+ public Intent createIntent(@NonNull Context context, Void aVoid) {
+ return new Intent(context, PowerConsumerPickerActivity.class);
+ }
+
+ @Override
+ public String parseResult(int resultCode, @Nullable Intent intent) {
+ if (resultCode != RESULT_OK || intent == null) {
+ return null;
+ }
+ return intent.getStringExtra(Intent.EXTRA_RETURN_RESULT);
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+
+ setContentView(R.layout.power_consumer_picker_activity_layout);
+
+ ViewPager viewPager = findViewById(R.id.pager);
+
+ FragmentStatePagerAdapter adapter = new FragmentStatePagerAdapter(
+ getSupportFragmentManager()) {
+
+ @Override
+ public int getCount() {
+ return 2;
+ }
+
+ @NonNull
+ @Override
+ public Fragment getItem(int position) {
+ switch (position) {
+ case 0:
+ return new PowerConsumerPickerFragment(
+ PowerConsumerPickerFragment.PICKER_TYPE_APP);
+ case 1:
+ default:
+ return new PowerConsumerPickerFragment(
+ PowerConsumerPickerFragment.PICKER_TYPE_DRAIN);
+ }
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ switch (position) {
+ case 0:
+ return "Apps";
+ case 1:
+ return "Drains";
+ }
+ return null;
+ }
+ };
+
+ viewPager.setAdapter(adapter);
+ TabLayout tabLayout = findViewById(R.id.tab_layout);
+ tabLayout.setupWithViewPager(viewPager);
+ }
+
+ public void setSelectedPowerConsumer(String id) {
+ Intent intent = new Intent();
+ intent.putExtra(Intent.EXTRA_RETURN_RESULT, id);
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ public boolean onNavigateUp() {
+ onBackPressed();
+ return true;
+ }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerFragment.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerFragment.java
new file mode 100644
index 0000000..25225b8
--- /dev/null
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerConsumerPickerFragment.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworks.core.powerstatsviewer;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.loader.app.LoaderManager;
+import androidx.loader.content.Loader;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.frameworks.core.powerstatsviewer.PowerConsumerInfoHelper.PowerConsumerInfo;
+import com.android.internal.os.BatterySipper;
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settingslib.utils.AsyncLoaderCompat;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Picker, showing a sorted lists of applications or other types of entities consuming power.
+ * Returns the selected entity ID or null.
+ */
+public class PowerConsumerPickerFragment extends Fragment {
+ private static final String TAG = "AppPicker";
+
+ public static final String PICKER_TYPE = "pickertype";
+
+ public static final int PICKER_TYPE_APP = 0;
+ public static final int PICKER_TYPE_DRAIN = 1;
+
+ private PowerConsumerListAdapter mPowerConsumerListAdapter;
+ private RecyclerView mAppList;
+ private View mLoadingView;
+
+ private interface OnPowerConsumerSelectedListener {
+ void onPowerConsumerSelected(String uid);
+ }
+
+ public PowerConsumerPickerFragment(int pickerType) {
+ Bundle args = new Bundle();
+ args.putInt(PICKER_TYPE, pickerType);
+ setArguments(args);
+ }
+
+ public PowerConsumerPickerFragment() {
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.power_consumer_picker_layout, container, false);
+ mLoadingView = view.findViewById(R.id.loading_view);
+
+ mAppList = view.findViewById(R.id.list_view);
+ mAppList.setLayoutManager(new LinearLayoutManager(getContext()));
+ mPowerConsumerListAdapter = new PowerConsumerListAdapter(
+ PowerConsumerPickerFragment.this::setSelectedPowerConsumer);
+ mAppList.setAdapter(mPowerConsumerListAdapter);
+
+ LoaderManager.getInstance(this).initLoader(0, getArguments(),
+ new PowerConsumerListLoaderCallbacks());
+ return view;
+ }
+
+ public void setSelectedPowerConsumer(String id) {
+ ((PowerConsumerPickerActivity) getActivity()).setSelectedPowerConsumer(id);
+ }
+
+ private static class PowerConsumerListLoader extends
+ AsyncLoaderCompat<List<PowerConsumerInfo>> {
+ private final BatteryStatsHelper mStatsHelper;
+ private final int mPickerType;
+ private final UserManager mUserManager;
+ private final PackageManager mPackageManager;
+
+ PowerConsumerListLoader(Context context, int pickerType) {
+ super(context);
+ mUserManager = context.getSystemService(UserManager.class);
+ mStatsHelper = new BatteryStatsHelper(context, false /* collectBatteryBroadcast */);
+ mPickerType = pickerType;
+ mStatsHelper.create((Bundle) null);
+ mStatsHelper.clearStats();
+ mPackageManager = context.getPackageManager();
+ }
+
+ @Override
+ public List<PowerConsumerInfo> loadInBackground() {
+ List<PowerConsumerInfoHelper.PowerConsumerInfo> powerConsumerList = new ArrayList<>();
+
+ mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.myUserId());
+
+ final List<BatterySipper> usageList = mStatsHelper.getUsageList();
+ for (BatterySipper sipper : usageList) {
+ switch (mPickerType) {
+ case PICKER_TYPE_APP:
+ if (sipper.drainType != BatterySipper.DrainType.APP) {
+ continue;
+ }
+ break;
+ case PICKER_TYPE_DRAIN:
+ default:
+ if (sipper.drainType == BatterySipper.DrainType.APP) {
+ continue;
+ }
+ }
+
+ powerConsumerList.add(
+ PowerConsumerInfoHelper.makePowerConsumerInfo(mPackageManager, sipper));
+ }
+
+ powerConsumerList.sort(
+ Comparator.comparing((PowerConsumerInfo a) -> a.powerMah).reversed());
+ return powerConsumerList;
+ }
+
+ @Override
+ protected void onDiscardResult(List<PowerConsumerInfo> result) {
+ }
+ }
+
+ private class PowerConsumerListLoaderCallbacks implements
+ LoaderManager.LoaderCallbacks<List<PowerConsumerInfo>> {
+
+ @NonNull
+ @Override
+ public Loader<List<PowerConsumerInfo>> onCreateLoader(int id, Bundle args) {
+ return new PowerConsumerListLoader(getContext(), args.getInt(PICKER_TYPE));
+ }
+
+ @Override
+ public void onLoadFinished(@NonNull Loader<List<PowerConsumerInfo>> loader,
+ List<PowerConsumerInfoHelper.PowerConsumerInfo> powerConsumerList) {
+ mPowerConsumerListAdapter.setPowerConsumerList(powerConsumerList);
+ mAppList.setVisibility(View.VISIBLE);
+ mLoadingView.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onLoaderReset(
+ @NonNull Loader<List<PowerConsumerInfoHelper.PowerConsumerInfo>> loader) {
+ }
+ }
+
+ public class PowerConsumerListAdapter extends RecyclerView.Adapter<PowerConsumerViewHolder> {
+ private final OnPowerConsumerSelectedListener mListener;
+ private List<PowerConsumerInfo> mPowerConsumerList;
+
+ public PowerConsumerListAdapter(OnPowerConsumerSelectedListener listener) {
+ mListener = listener;
+ }
+
+ void setPowerConsumerList(List<PowerConsumerInfo> powerConsumerList) {
+ mPowerConsumerList = powerConsumerList;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mPowerConsumerList.size();
+ }
+
+ @NonNull
+ @Override
+ public PowerConsumerViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
+ int position) {
+ LayoutInflater layoutInflater = LayoutInflater.from(viewGroup.getContext());
+ View view = layoutInflater.inflate(R.layout.power_consumer_info_layout, viewGroup,
+ false);
+ return new PowerConsumerViewHolder(view, mListener);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull PowerConsumerViewHolder viewHolder, int position) {
+ PowerConsumerInfoHelper.PowerConsumerInfo item = mPowerConsumerList.get(position);
+ viewHolder.id = item.id;
+ viewHolder.titleView.setText(item.label);
+ if (item.details != null) {
+ viewHolder.detailsView.setText(item.details);
+ viewHolder.detailsView.setVisibility(View.VISIBLE);
+ } else {
+ viewHolder.detailsView.setVisibility(View.GONE);
+ }
+ viewHolder.powerView.setText(
+ String.format(Locale.getDefault(), "%.1f mAh", item.powerMah));
+ viewHolder.iconView.setImageDrawable(
+ item.iconInfo.loadIcon(getContext().getPackageManager()));
+ if (item.packages != null) {
+ viewHolder.packagesView.setText(item.packages);
+ viewHolder.packagesView.setVisibility(View.VISIBLE);
+ } else {
+ viewHolder.packagesView.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ // View Holder used when displaying apps
+ public static class PowerConsumerViewHolder extends RecyclerView.ViewHolder
+ implements View.OnClickListener {
+ private final OnPowerConsumerSelectedListener mListener;
+
+ public String id;
+ public TextView titleView;
+ public TextView detailsView;
+ public ImageView iconView;
+ public TextView packagesView;
+ public TextView powerView;
+
+ PowerConsumerViewHolder(View view, OnPowerConsumerSelectedListener listener) {
+ super(view);
+ mListener = listener;
+ view.setOnClickListener(this);
+ titleView = view.findViewById(android.R.id.title);
+ detailsView = view.findViewById(R.id.details);
+ iconView = view.findViewById(android.R.id.icon);
+ packagesView = view.findViewById(R.id.packages);
+ powerView = view.findViewById(R.id.power_mah);
+ powerView.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void onClick(View v) {
+ mListener.onPowerConsumerSelected(id);
+ }
+ }
+}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
index 09f20ba..099ee22 100644
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsData.java
@@ -44,11 +44,11 @@
public double total;
}
- private final AppInfoHelper.AppInfo mAppInfo;
+ private final PowerConsumerInfoHelper.PowerConsumerInfo mPowerConsumerInfo;
private final List<Entry> mEntries = new ArrayList<>();
public PowerStatsData(Context context, BatteryStatsHelper batteryStatsHelper,
- int uid) {
+ String powerConsumerId) {
List<BatterySipper> usageList = batteryStatsHelper.getUsageList();
double totalPowerMah = 0;
@@ -81,18 +81,14 @@
long totalAudioTimeMs = 0;
long totalVideoTimeMs = 0;
- BatterySipper uidSipper = null;
+ BatterySipper requestedPowerConsumer = null;
for (BatterySipper sipper : usageList) {
if (sipper.drainType == BatterySipper.DrainType.SCREEN) {
totalScreenPower = sipper.sumPower();
}
- if (isHiddenDrainType(sipper.drainType)) {
- continue;
- }
-
- if (sipper.drainType == BatterySipper.DrainType.APP && sipper.getUid() == uid) {
- uidSipper = sipper;
+ if (powerConsumerId(sipper).equals(powerConsumerId)) {
+ requestedPowerConsumer = sipper;
}
totalPowerMah += sipper.sumPower();
@@ -129,79 +125,71 @@
totalVideoTimeMs += sipper.videoTimeMs;
}
- mAppInfo = AppInfoHelper.makeApplicationInfo(context.getPackageManager(), uid, uidSipper);
-
- if (uidSipper == null) {
+ if (requestedPowerConsumer == null) {
+ mPowerConsumerInfo = null;
return;
}
+ mPowerConsumerInfo = PowerConsumerInfoHelper.makePowerConsumerInfo(
+ context.getPackageManager(), requestedPowerConsumer);
+
addEntry("Total power", EntryType.POWER,
- uidSipper.totalSmearedPowerMah, totalSmearedPowerMah);
+ requestedPowerConsumer.totalSmearedPowerMah, totalSmearedPowerMah);
addEntry("... excluding system", EntryType.POWER,
- uidSipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
+ requestedPowerConsumer.totalSmearedPowerMah, totalPowerExcludeSystemMah);
addEntry("Screen, smeared", EntryType.POWER,
- uidSipper.screenPowerMah, totalScreenPower);
+ requestedPowerConsumer.screenPowerMah, totalScreenPower);
addEntry("Other, smeared", EntryType.POWER,
- uidSipper.proportionalSmearMah, totalProportionalSmearMah);
+ requestedPowerConsumer.proportionalSmearMah, totalProportionalSmearMah);
addEntry("Excluding smeared", EntryType.POWER,
- uidSipper.totalPowerMah, totalPowerMah);
+ requestedPowerConsumer.totalPowerMah, totalPowerMah);
addEntry("CPU", EntryType.POWER,
- uidSipper.cpuPowerMah, totalCpuPowerMah);
+ requestedPowerConsumer.cpuPowerMah, totalCpuPowerMah);
addEntry("System services", EntryType.POWER,
- uidSipper.systemServiceCpuPowerMah, totalSystemServiceCpuPowerMah);
- addEntry("RAM", EntryType.POWER,
- uidSipper.usagePowerMah, totalUsagePowerMah);
+ requestedPowerConsumer.systemServiceCpuPowerMah, totalSystemServiceCpuPowerMah);
+ addEntry("Usage", EntryType.POWER,
+ requestedPowerConsumer.usagePowerMah, totalUsagePowerMah);
addEntry("Wake lock", EntryType.POWER,
- uidSipper.wakeLockPowerMah, totalWakeLockPowerMah);
+ requestedPowerConsumer.wakeLockPowerMah, totalWakeLockPowerMah);
addEntry("Mobile radio", EntryType.POWER,
- uidSipper.mobileRadioPowerMah, totalMobileRadioPowerMah);
+ requestedPowerConsumer.mobileRadioPowerMah, totalMobileRadioPowerMah);
addEntry("WiFi", EntryType.POWER,
- uidSipper.wifiPowerMah, totalWifiPowerMah);
+ requestedPowerConsumer.wifiPowerMah, totalWifiPowerMah);
addEntry("Bluetooth", EntryType.POWER,
- uidSipper.bluetoothPowerMah, totalBluetoothPowerMah);
+ requestedPowerConsumer.bluetoothPowerMah, totalBluetoothPowerMah);
addEntry("GPS", EntryType.POWER,
- uidSipper.gpsPowerMah, totalGpsPowerMah);
+ requestedPowerConsumer.gpsPowerMah, totalGpsPowerMah);
addEntry("Camera", EntryType.POWER,
- uidSipper.cameraPowerMah, totalCameraPowerMah);
+ requestedPowerConsumer.cameraPowerMah, totalCameraPowerMah);
addEntry("Flashlight", EntryType.POWER,
- uidSipper.flashlightPowerMah, totalFlashlightPowerMah);
+ requestedPowerConsumer.flashlightPowerMah, totalFlashlightPowerMah);
addEntry("Sensors", EntryType.POWER,
- uidSipper.sensorPowerMah, totalSensorPowerMah);
+ requestedPowerConsumer.sensorPowerMah, totalSensorPowerMah);
addEntry("Audio", EntryType.POWER,
- uidSipper.audioPowerMah, totalAudioPowerMah);
+ requestedPowerConsumer.audioPowerMah, totalAudioPowerMah);
addEntry("Video", EntryType.POWER,
- uidSipper.videoPowerMah, totalVideoPowerMah);
+ requestedPowerConsumer.videoPowerMah, totalVideoPowerMah);
addEntry("CPU time", EntryType.DURATION,
- uidSipper.cpuTimeMs, totalCpuTimeMs);
+ requestedPowerConsumer.cpuTimeMs, totalCpuTimeMs);
addEntry("CPU foreground time", EntryType.DURATION,
- uidSipper.cpuFgTimeMs, totalCpuFgTimeMs);
+ requestedPowerConsumer.cpuFgTimeMs, totalCpuFgTimeMs);
addEntry("Wake lock time", EntryType.DURATION,
- uidSipper.wakeLockTimeMs, totalWakeLockTimeMs);
+ requestedPowerConsumer.wakeLockTimeMs, totalWakeLockTimeMs);
addEntry("WiFi running time", EntryType.DURATION,
- uidSipper.wifiRunningTimeMs, totalWifiRunningTimeMs);
+ requestedPowerConsumer.wifiRunningTimeMs, totalWifiRunningTimeMs);
addEntry("Bluetooth time", EntryType.DURATION,
- uidSipper.bluetoothRunningTimeMs, totalBluetoothRunningTimeMs);
+ requestedPowerConsumer.bluetoothRunningTimeMs, totalBluetoothRunningTimeMs);
addEntry("GPS time", EntryType.DURATION,
- uidSipper.gpsTimeMs, totalGpsTimeMs);
+ requestedPowerConsumer.gpsTimeMs, totalGpsTimeMs);
addEntry("Camera time", EntryType.DURATION,
- uidSipper.cameraTimeMs, totalCameraTimeMs);
+ requestedPowerConsumer.cameraTimeMs, totalCameraTimeMs);
addEntry("Flashlight time", EntryType.DURATION,
- uidSipper.flashlightTimeMs, totalFlashlightTimeMs);
+ requestedPowerConsumer.flashlightTimeMs, totalFlashlightTimeMs);
addEntry("Audio time", EntryType.DURATION,
- uidSipper.audioTimeMs, totalAudioTimeMs);
+ requestedPowerConsumer.audioTimeMs, totalAudioTimeMs);
addEntry("Video time", EntryType.DURATION,
- uidSipper.videoTimeMs, totalVideoTimeMs);
- }
-
- protected boolean isHiddenDrainType(BatterySipper.DrainType drainType) {
- return drainType == BatterySipper.DrainType.IDLE
- || drainType == BatterySipper.DrainType.CELL
- || drainType == BatterySipper.DrainType.SCREEN
- || drainType == BatterySipper.DrainType.UNACCOUNTED
- || drainType == BatterySipper.DrainType.OVERCOUNTED
- || drainType == BatterySipper.DrainType.BLUETOOTH
- || drainType == BatterySipper.DrainType.WIFI;
+ requestedPowerConsumer.videoTimeMs, totalVideoTimeMs);
}
private boolean isSystemSipper(BatterySipper sipper) {
@@ -230,11 +218,15 @@
mEntries.add(entry);
}
- public AppInfoHelper.AppInfo getAppInfo() {
- return mAppInfo;
+ public PowerConsumerInfoHelper.PowerConsumerInfo getPowerConsumerInfo() {
+ return mPowerConsumerInfo;
}
public List<Entry> getEntries() {
return mEntries;
}
+
+ public static String powerConsumerId(BatterySipper sipper) {
+ return sipper.drainType + "|" + sipper.userId + "|" + sipper.getUid();
+ }
}
diff --git a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
index 1605e9c..78f2b91 100644
--- a/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
+++ b/core/tests/powertests/PowerStatsViewer/src/com/android/frameworks/core/powerstatsviewer/PowerStatsViewerActivity.java
@@ -20,7 +20,7 @@
import android.content.SharedPreferences;
import android.os.BatteryStats;
import android.os.Bundle;
-import android.os.Process;
+import android.os.UserHandle;
import android.os.UserManager;
import android.view.LayoutInflater;
import android.view.View;
@@ -46,15 +46,15 @@
public class PowerStatsViewerActivity extends ComponentActivity {
private static final int POWER_STATS_REFRESH_RATE_MILLIS = 60 * 1000;
- public static final String PREF_SELECTED_UID = "selectedUid";
- private static final String LOADER_ARG_UID = "uid";
+ public static final String PREF_SELECTED_POWER_CONSUMER = "powerConsumerId";
+ private static final String LOADER_ARG_POWER_CONSUMER_ID = "powerConsumerId";
private PowerStatsDataAdapter mPowerStatsDataAdapter;
private Runnable mPowerStatsRefresh = this::periodicPowerStatsRefresh;
private SharedPreferences mSharedPref;
- private int mUid = Process.INVALID_UID;
+ private String mPowerConsumerId;
private TextView mTitleView;
- private TextView mUidView;
+ private TextView mDetailsView;
private ImageView mIconView;
private TextView mPackagesView;
private RecyclerView mPowerStatsDataView;
@@ -73,7 +73,7 @@
appCard.setOnClickListener((e) -> startAppPicker());
mTitleView = findViewById(android.R.id.title);
- mUidView = findViewById(R.id.uid);
+ mDetailsView = findViewById(R.id.details);
mIconView = findViewById(android.R.id.icon);
mPackagesView = findViewById(R.id.packages);
@@ -85,9 +85,9 @@
mLoadingView = findViewById(R.id.loading_view);
mEmptyView = findViewById(R.id.empty_view);
- mUid = mSharedPref.getInt(PREF_SELECTED_UID, Process.INVALID_UID);
+ mPowerConsumerId = mSharedPref.getString(PREF_SELECTED_POWER_CONSUMER, null);
loadPowerStats();
- if (mUid == Process.INVALID_UID) {
+ if (mPowerConsumerId == null) {
startAppPicker();
}
}
@@ -105,18 +105,18 @@
}
private void startAppPicker() {
- registerForActivityResult(AppPickerActivity.CONTRACT, this::onApplicationSelected)
+ registerForActivityResult(PowerConsumerPickerActivity.CONTRACT, this::onApplicationSelected)
.launch(null);
}
- private void onApplicationSelected(int uid) {
- if (uid == -1) {
- if (mUid == Process.INVALID_UID) {
+ private void onApplicationSelected(String powerConsumerId) {
+ if (powerConsumerId == null) {
+ if (mPowerConsumerId == null) {
finish();
}
} else {
- mUid = uid;
- mSharedPref.edit().putInt(PREF_SELECTED_UID, mUid).apply();
+ mPowerConsumerId = powerConsumerId;
+ mSharedPref.edit().putString(PREF_SELECTED_POWER_CONSUMER, mPowerConsumerId).apply();
mLoadingView.setVisibility(View.VISIBLE);
loadPowerStats();
}
@@ -129,18 +129,18 @@
private void loadPowerStats() {
Bundle args = new Bundle();
- args.putInt(LOADER_ARG_UID, mUid);
+ args.putString(LOADER_ARG_POWER_CONSUMER_ID, mPowerConsumerId);
LoaderManager.getInstance(this).restartLoader(0, args, new PowerStatsDataLoaderCallbacks());
}
private static class PowerStatsDataLoader extends AsyncLoaderCompat<PowerStatsData> {
- private final int mUid;
+ private final String mPowerConsumerId;
private final BatteryStatsHelper mBatteryStatsHelper;
private final UserManager mUserManager;
- PowerStatsDataLoader(Context context, int uid) {
+ PowerStatsDataLoader(Context context, String powerConsumerId) {
super(context);
- mUid = uid;
+ mPowerConsumerId = powerConsumerId;
mUserManager = context.getSystemService(UserManager.class);
mBatteryStatsHelper = new BatteryStatsHelper(context,
false /* collectBatteryBroadcast */);
@@ -151,8 +151,8 @@
@Override
public PowerStatsData loadInBackground() {
mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
- mUserManager.getUserProfiles());
- return new PowerStatsData(getContext(), mBatteryStatsHelper, mUid);
+ UserHandle.myUserId());
+ return new PowerStatsData(getContext(), mBatteryStatsHelper, mPowerConsumerId);
}
@Override
@@ -165,27 +165,38 @@
@Override
public Loader<PowerStatsData> onCreateLoader(int id, Bundle args) {
return new PowerStatsDataLoader(PowerStatsViewerActivity.this,
- args.getInt(LOADER_ARG_UID, Process.INVALID_UID));
+ args.getString(LOADER_ARG_POWER_CONSUMER_ID));
}
@Override
public void onLoadFinished(@NonNull Loader<PowerStatsData> loader,
PowerStatsData powerStatsData) {
- AppInfoHelper.AppInfo appInfo = powerStatsData.getAppInfo();
- mTitleView.setText(appInfo.label);
- mUidView.setText(String.format(Locale.getDefault(), "UID: %d", appInfo.uid));
- mIconView.setImageDrawable(appInfo.iconInfo.loadIcon(getPackageManager()));
-
- if (appInfo.packages != null) {
- mPackagesView.setText(appInfo.packages);
- mPackagesView.setVisibility(View.VISIBLE);
- } else {
+ PowerConsumerInfoHelper.PowerConsumerInfo
+ powerConsumerInfo = powerStatsData.getPowerConsumerInfo();
+ if (powerConsumerInfo == null) {
+ mTitleView.setText("Power consumer not found");
mPackagesView.setVisibility(View.GONE);
+ } else {
+ mTitleView.setText(powerConsumerInfo.label);
+ if (powerConsumerInfo.details != null) {
+ mDetailsView.setText(powerConsumerInfo.details);
+ mDetailsView.setVisibility(View.VISIBLE);
+ } else {
+ mDetailsView.setVisibility(View.GONE);
+ }
+ mIconView.setImageDrawable(
+ powerConsumerInfo.iconInfo.loadIcon(getPackageManager()));
+
+ if (powerConsumerInfo.packages != null) {
+ mPackagesView.setText(powerConsumerInfo.packages);
+ mPackagesView.setVisibility(View.VISIBLE);
+ } else {
+ mPackagesView.setVisibility(View.GONE);
+ }
}
mPowerStatsDataAdapter.setEntries(powerStatsData.getEntries());
-
if (powerStatsData.getEntries().isEmpty()) {
mEmptyView.setVisibility(View.VISIBLE);
mPowerStatsDataView.setVisibility(View.GONE);