From: jackqdyulei Date: Thu, 19 Jul 2018 17:09:47 +0000 (-0700) Subject: Add functions for table action. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=6b09f54e062a63d40881ee1087df8923cc596ce3;p=android-x86%2Fpackages-apps-Settings.git Add functions for table action. 1. Insert/Update/Query/Delete 2. Update the action when app been restricted 3. Display restriction time in RestrictedAppDetails Bug: 111366678 Test: RunSettingsRoboTests Change-Id: I77a53f70e1ce4b612aabe28b7a1bb5df8f3ec9d5 --- diff --git a/res/values/strings.xml b/res/values/strings.xml index 2bef192f82..2acf28b8ed 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5091,6 +5091,9 @@ Limiting battery usage for %1$d apps + + Restricted %1$s + These apps have been using battery in the background. Restricted apps may not work properly and notifications may be delayed. diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 9e920c4797..3676761af7 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -38,11 +38,14 @@ import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.util.ArrayUtils; import com.android.settings.R; +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; import com.android.settings.fuelgauge.batterytip.AnomalyInfo; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.fuelgauge.batterytip.StatsManagerConfig; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.fuelgauge.PowerWhitelistBackend; import com.android.settingslib.utils.PowerUtil; +import com.android.settingslib.utils.ThreadUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -101,8 +104,8 @@ public class BatteryUtils { mContext = context; mPackageManager = context.getPackageManager(); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - mPowerUsageFeatureProvider = FeatureFactory.getFactory( - context).getPowerUsageFeatureProvider(context); + mPowerUsageFeatureProvider = FeatureFactory.getFactory(context) + .getPowerUsageFeatureProvider(context); } public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid, @@ -400,6 +403,18 @@ public class BatteryUtils { } // Control whether app could run jobs in the background mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode); + + ThreadUtils.postOnBackgroundThread(() -> { + final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager + .getInstance(mContext); + if (mode == AppOpsManager.MODE_IGNORED) { + batteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, + uid, packageName, System.currentTimeMillis()); + } else if (mode == AppOpsManager.MODE_ALLOWED) { + batteryDatabaseManager.deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, + uid, packageName); + } + }); } public boolean isForceAppStandbyEnabled(int uid, String packageName) { diff --git a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java index 4934bce700..b64a70775e 100644 --- a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java +++ b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java @@ -22,6 +22,8 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.os.UserHandle; import android.util.IconDrawableFactory; +import android.util.Log; +import android.util.SparseLongArray; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; @@ -29,7 +31,9 @@ import com.android.settings.Utils; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; import com.android.settings.fuelgauge.batterytip.AppInfo; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.fuelgauge.batterytip.BatteryTipDialogFragment; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; @@ -37,6 +41,7 @@ import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip; import com.android.settings.widget.AppCheckBoxPreference; import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.utils.StringUtil; import com.android.settingslib.widget.FooterPreferenceMixinCompat; import java.util.List; @@ -57,6 +62,7 @@ public class RestrictedAppDetails extends DashboardFragment implements @VisibleForTesting static final String EXTRA_APP_INFO_LIST = "app_info_list"; private static final String KEY_PREF_RESTRICTED_APP_LIST = "restrict_app_list"; + private static final long TIME_NULL = -1; @VisibleForTesting List mAppInfos; @@ -68,6 +74,8 @@ public class RestrictedAppDetails extends DashboardFragment implements BatteryUtils mBatteryUtils; @VisibleForTesting PackageManager mPackageManager; + @VisibleForTesting + BatteryDatabaseManager mBatteryDatabaseManager; private final FooterPreferenceMixinCompat mFooterPreferenceMixin = new FooterPreferenceMixinCompat(this, getSettingsLifecycle()); @@ -96,6 +104,7 @@ public class RestrictedAppDetails extends DashboardFragment implements mPackageManager = context.getPackageManager(); mIconDrawableFactory = IconDrawableFactory.newInstance(context); mBatteryUtils = BatteryUtils.getInstance(context); + mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context); refreshUi(); } @@ -135,6 +144,9 @@ public class RestrictedAppDetails extends DashboardFragment implements void refreshUi() { mRestrictedAppListGroup.removeAll(); final Context context = getPrefContext(); + final SparseLongArray timestampArray = mBatteryDatabaseManager + .queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION); + final long now = System.currentTimeMillis(); for (int i = 0, size = mAppInfos.size(); i < size; i++) { final CheckBoxPreference checkBoxPreference = new AppCheckBoxPreference(context); @@ -158,9 +170,16 @@ public class RestrictedAppDetails extends DashboardFragment implements return false; }); + + final long timestamp = timestampArray.get(appInfo.uid, TIME_NULL); + if (timestamp != TIME_NULL) { + checkBoxPreference.setSummary(getString(R.string.restricted_app_time_summary, + StringUtil.formatRelativeTime(context, now - timestamp, false))); + } + final CharSequence test = checkBoxPreference.getSummaryOn(); mRestrictedAppListGroup.addPreference(checkBoxPreference); } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); + Log.e(TAG, "Can't find package: " + appInfo.packageName); } } } diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java index 910b368096..513244e39d 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java @@ -17,6 +17,8 @@ package com.android.settings.fuelgauge.batterytip; import static android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE; +import static android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE; + import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns .ANOMALY_STATE; import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns @@ -26,6 +28,7 @@ import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.An import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns .TIME_STAMP_MS; import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns.UID; +import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.Tables.TABLE_ACTION; import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.Tables.TABLE_ANOMALY; import android.content.ContentValues; @@ -34,12 +37,15 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.SparseLongArray; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.ActionColumns; + import androidx.annotation.VisibleForTesting; /** @@ -158,4 +164,65 @@ public class BatteryDatabaseManager { } } } + + /** + * Query latest timestamps when an app has been performed action {@code type} + * + * @param type of action been performed + * @return {@link SparseLongArray} where key is uid and value is timestamp + */ + public synchronized SparseLongArray queryActionTime( + @AnomalyDatabaseHelper.ActionType int type) { + final SparseLongArray timeStamps = new SparseLongArray(); + try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) { + final String[] projection = {ActionColumns.UID, ActionColumns.TIME_STAMP_MS}; + final String selection = ActionColumns.ACTION_TYPE + " = ? "; + final String[] selectionArgs = new String[]{String.valueOf(type)}; + + try (Cursor cursor = db.query(TABLE_ACTION, projection, selection, selectionArgs, + null /* groupBy */, null /* having */, null /* orderBy */)) { + final int uidIndex = cursor.getColumnIndex(ActionColumns.UID); + final int timestampIndex = cursor.getColumnIndex(ActionColumns.TIME_STAMP_MS); + + while (cursor.moveToNext()) { + final int uid = cursor.getInt(uidIndex); + final long timeStamp = cursor.getLong(timestampIndex); + timeStamps.append(uid, timeStamp); + } + } + } + + return timeStamps; + } + + /** + * Insert an action, or update it if already existed + */ + public synchronized boolean insertAction(@AnomalyDatabaseHelper.ActionType int type, + int uid, String packageName, long timestampMs) { + try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) { + final ContentValues values = new ContentValues(); + values.put(ActionColumns.UID, uid); + values.put(ActionColumns.PACKAGE_NAME, packageName); + values.put(ActionColumns.ACTION_TYPE, type); + values.put(ActionColumns.TIME_STAMP_MS, timestampMs); + return db.insertWithOnConflict(TABLE_ACTION, null, values, CONFLICT_REPLACE) != -1; + } + } + + /** + * Remove an action + */ + public synchronized boolean deleteAction(@AnomalyDatabaseHelper.ActionType int type, + int uid, String packageName) { + try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) { + final String where = + ActionColumns.ACTION_TYPE + " = ? AND " + ActionColumns.UID + " = ? AND " + + ActionColumns.PACKAGE_NAME + " = ? "; + final String[] whereArgs = new String[]{String.valueOf(type), String.valueOf(uid), + String.valueOf(packageName)}; + + return db.delete(TABLE_ACTION, where, whereArgs) != 0; + } + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java index 58bfe0eabf..41e77e9a8b 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.text.format.DateUtils; +import android.util.SparseLongArray; import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; import com.android.settings.fuelgauge.batterytip.AppInfo; @@ -88,7 +89,7 @@ public class BatteryDatabaseManagerTest { } @Test - public void testAllFunctions() { + public void allAnomalyFunctions() { mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW, AnomalyDatabaseHelper.State.NEW, NOW); mBatteryDatabaseManager.insertAnomaly(UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD, @@ -113,7 +114,7 @@ public class BatteryDatabaseManagerTest { } @Test - public void testUpdateAnomalies_updateSuccessfully() { + public void updateAnomalies_updateSuccessfully() { mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW, AnomalyDatabaseHelper.State.NEW, NOW); mBatteryDatabaseManager.insertAnomaly(UID_OLD, PACKAGE_NAME_OLD, TYPE_OLD, @@ -138,7 +139,7 @@ public class BatteryDatabaseManagerTest { } @Test - public void testQueryAnomalies_removeDuplicateByUid() { + public void queryAnomalies_removeDuplicateByUid() { mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_NEW, AnomalyDatabaseHelper.State.NEW, NOW); mBatteryDatabaseManager.insertAnomaly(UID_NEW, PACKAGE_NAME_NEW, TYPE_OLD, @@ -149,4 +150,28 @@ public class BatteryDatabaseManagerTest { AnomalyDatabaseHelper.State.NEW); assertThat(newAppInfos).containsExactly(mCombinedAppInfo); } + + @Test + public void allActionFunctions() { + final long timestamp = System.currentTimeMillis(); + mBatteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_OLD, + PACKAGE_NAME_OLD, 0); + mBatteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_OLD, + PACKAGE_NAME_OLD, 1); + mBatteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_NEW, + PACKAGE_NAME_NEW, timestamp); + + final SparseLongArray timeArray = mBatteryDatabaseManager.queryActionTime( + AnomalyDatabaseHelper.ActionType.RESTRICTION); + assertThat(timeArray.size()).isEqualTo(2); + assertThat(timeArray.get(UID_OLD)).isEqualTo(1); + assertThat(timeArray.get(UID_NEW)).isEqualTo(timestamp); + + mBatteryDatabaseManager.deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, UID_NEW, + PACKAGE_NAME_NEW); + final SparseLongArray recentTimeArray = mBatteryDatabaseManager.queryActionTime( + AnomalyDatabaseHelper.ActionType.RESTRICTION); + assertThat(recentTimeArray.size()).isEqualTo(1); + assertThat(timeArray.get(UID_OLD)).isEqualTo(1); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index df34b785e6..b274492c75 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -51,9 +51,12 @@ import android.text.format.DateUtils; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; import com.android.settings.fuelgauge.batterytip.AnomalyInfo; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowThreadUtils; import com.android.settingslib.fuelgauge.PowerWhitelistBackend; import org.junit.Before; @@ -148,6 +151,8 @@ public class BatteryUtilsTest { private ApplicationInfo mLowApplicationInfo; @Mock private PowerWhitelistBackend mPowerWhitelistBackend; + @Mock + private BatteryDatabaseManager mBatteryDatabaseManager; private AnomalyInfo mAnomalyInfo; private BatteryUtils mBatteryUtils; private FakeFeatureFactory mFeatureFactory; @@ -225,6 +230,8 @@ public class BatteryUtilsTest { .thenReturn(TOTAL_BATTERY_USAGE + BATTERY_SCREEN_USAGE); when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())) .thenReturn(DISCHARGE_AMOUNT); + BatteryDatabaseManager.setUpForTest(mBatteryDatabaseManager); + ShadowThreadUtils.setIsMainThread(true); } @Test @@ -570,6 +577,23 @@ public class BatteryUtilsTest { } @Test + public void testSetForceAppStandby_restrictApp_recordTime() { + mBatteryUtils.setForceAppStandby(UID, HIGH_SDK_PACKAGE, AppOpsManager.MODE_IGNORED); + + verify(mBatteryDatabaseManager).insertAction( + eq(AnomalyDatabaseHelper.ActionType.RESTRICTION), eq(UID), + eq(HIGH_SDK_PACKAGE), anyLong()); + } + + @Test + public void testSetForceAppStandby_unrestrictApp_deleteTime() { + mBatteryUtils.setForceAppStandby(UID, HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED); + + verify(mBatteryDatabaseManager).deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION, + UID, HIGH_SDK_PACKAGE); + } + + @Test public void testIsForceAppStandbyEnabled_enabled_returnTrue() { when(mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID, PACKAGE_NAME)).thenReturn(AppOpsManager.MODE_IGNORED); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java index b9ed509811..7219f183b6 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java @@ -28,10 +28,13 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.os.UserHandle; import android.util.IconDrawableFactory; +import android.util.SparseLongArray; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; import com.android.settings.fuelgauge.batterytip.AppInfo; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.fuelgauge.batterytip.BatteryTipDialogFragment; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; @@ -52,6 +55,7 @@ import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import androidx.appcompat.app.AlertDialog; import androidx.preference.CheckBoxPreference; @@ -76,6 +80,8 @@ public class RestrictedAppDetailsTest { private IconDrawableFactory mIconDrawableFactory; @Mock private InstrumentedPreferenceFragment mFragment; + @Mock + private BatteryDatabaseManager mBatteryDatabaseManager; private PreferenceManager mPreferenceManager; private RestrictedAppDetails mRestrictedAppDetails; private Context mContext; @@ -98,12 +104,14 @@ public class RestrictedAppDetailsTest { doReturn(mPreferenceManager).when(mRestrictedAppDetails).getPreferenceManager(); doReturn(mContext).when(mFragment).getContext(); + doReturn(mContext).when(mRestrictedAppDetails).getContext(); mRestrictedAppDetails.mPackageManager = mPackageManager; mRestrictedAppDetails.mIconDrawableFactory = mIconDrawableFactory; mRestrictedAppDetails.mAppInfos = new ArrayList<>(); mRestrictedAppDetails.mAppInfos.add(mAppInfo); mRestrictedAppDetails.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext)); mRestrictedAppDetails.mBatteryUtils = spy(new BatteryUtils(mContext)); + mRestrictedAppDetails.mBatteryDatabaseManager = mBatteryDatabaseManager; doReturn(mPreferenceManager).when( mRestrictedAppDetails.mRestrictedAppListGroup).getPreferenceManager(); @@ -118,6 +126,10 @@ public class RestrictedAppDetailsTest { doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo); doReturn(true).when(mRestrictedAppDetails.mBatteryUtils).isForceAppStandbyEnabled(UID, PACKAGE_NAME); + final SparseLongArray timestampArray = new SparseLongArray(); + timestampArray.put(UID, System.currentTimeMillis() - TimeUnit.HOURS.toMillis(5)); + doReturn(timestampArray).when(mBatteryDatabaseManager) + .queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION); mRestrictedAppDetails.refreshUi(); @@ -126,6 +138,7 @@ public class RestrictedAppDetailsTest { (CheckBoxPreference) mRestrictedAppDetails.mRestrictedAppListGroup.getPreference(0); assertThat(preference.getTitle()).isEqualTo(APP_NAME); assertThat(preference.isChecked()).isTrue(); + assertThat(preference.getSummary()).isEqualTo("Restricted 5 hours ago"); } @Test