Merge "Add dynamic coloring documentation to FORMAT.md"
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index 4053bdd..8c8d2bf 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -285,7 +285,7 @@
/** @hide */
public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT = 0;
/** @hide */
- public static final double DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING = 0.01;
+ public static final float DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING = 0.01f;
/** @hide */
public static final int DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX = 500;
/** @hide */
@@ -372,7 +372,7 @@
/** @hide */
public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT = 0;
/** @hide */
- public static final double DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING = 0.5;
+ public static final float DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING = 0.5f;
/** @hide */
public static final int DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX = 15000;
/** @hide */
diff --git a/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java b/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java
index b0b9abc..fc27a79 100644
--- a/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java
+++ b/apex/jobscheduler/framework/java/com/android/server/AppStateTracker.java
@@ -25,19 +25,25 @@
String TAG = "AppStateTracker";
/**
- * Register a {@link ServiceStateListener} to listen for forced-app-standby changes that should
- * affect services.
+ * Register a {@link BackgroundRestrictedAppListener} to listen for background restricted mode
+ * changes that should affect services etc.
*/
- void addServiceStateListener(@NonNull ServiceStateListener listener);
+ void addBackgroundRestrictedAppListener(@NonNull BackgroundRestrictedAppListener listener);
/**
- * A listener to listen to forced-app-standby changes that should affect services.
+ * @return {code true} if the given UID/package has been in background restricted mode,
+ * it does NOT include the case where the "force app background restricted" is enabled.
*/
- interface ServiceStateListener {
+ boolean isAppBackgroundRestricted(int uid, @NonNull String packageName);
+
+ /**
+ * A listener to listen to background restricted mode changes that should affect services etc.
+ */
+ interface BackgroundRestrictedAppListener {
/**
- * Called when an app goes into forced app standby and its foreground
- * services need to be removed from that state.
+ * Called when an app goes in/out of background restricted mode.
*/
- void stopForegroundServicesForUidPackage(int uid, String packageName);
+ void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+ boolean restricted);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
index c332a59..d0a155d 100644
--- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
+++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java
@@ -60,8 +60,10 @@
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Class to keep track of the information related to "force app standby", which includes:
@@ -160,16 +162,34 @@
@GuardedBy("mLock")
boolean mForcedAppStandbyEnabled;
+ /**
+ * A lock-free set of (uid, packageName) pairs in background restricted mode.
+ *
+ * <p>
+ * It's bascially shadowing the {@link #mRunAnyRestrictedPackages} together with
+ * the {@link #mForcedAppStandbyEnabled} - mutations on them would result in copy-on-write.
+ * </p>
+ */
+ volatile Set<Pair<Integer, String>> mBackgroundRestrictedUidPackages = Collections.emptySet();
+
@Override
- public void addServiceStateListener(@NonNull ServiceStateListener listener) {
+ public void addBackgroundRestrictedAppListener(
+ @NonNull BackgroundRestrictedAppListener listener) {
addListener(new Listener() {
@Override
- public void stopForegroundServicesForUidPackage(int uid, String packageName) {
- listener.stopForegroundServicesForUidPackage(uid, packageName);
+ public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+ boolean restricted) {
+ listener.updateBackgroundRestrictedForUidPackage(uid, packageName, restricted);
}
});
}
+ @Override
+ public boolean isAppBackgroundRestricted(int uid, @NonNull String packageName) {
+ final Set<Pair<Integer, String>> bgRestrictedUidPkgs = mBackgroundRestrictedUidPackages;
+ return bgRestrictedUidPkgs.contains(Pair.create(uid, packageName));
+ }
+
interface Stats {
int UID_FG_STATE_CHANGED = 0;
int UID_ACTIVE_STATE_CHANGED = 1;
@@ -233,6 +253,7 @@
return;
}
mForcedAppStandbyEnabled = enabled;
+ updateBackgroundRestrictedUidPackagesLocked();
if (DEBUG) {
Slog.d(TAG, "Forced app standby feature flag changed: "
+ mForcedAppStandbyEnabled);
@@ -277,7 +298,11 @@
if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
Slog.v(TAG, "Package " + packageName + "/" + uid
+ " toggled into fg service restriction");
- stopForegroundServicesForUidPackage(uid, packageName);
+ updateBackgroundRestrictedForUidPackage(uid, packageName, true);
+ } else {
+ Slog.v(TAG, "Package " + packageName + "/" + uid
+ + " toggled out of fg service restriction");
+ updateBackgroundRestrictedForUidPackage(uid, packageName, false);
}
}
@@ -366,10 +391,10 @@
}
/**
- * Called when an app goes into forced app standby and its foreground
- * services need to be removed from that state.
+ * Called when an app goes in/out of background restricted mode.
*/
- public void stopForegroundServicesForUidPackage(int uid, String packageName) {
+ public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+ boolean restricted) {
}
/**
@@ -438,9 +463,12 @@
final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
// No need to notify for state change as all the alarms and jobs should be
// removed too.
- mExemptedBucketPackages.remove(userId, pkgName);
- mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
- mActiveUids.delete(uid);
+ synchronized (mLock) {
+ mExemptedBucketPackages.remove(userId, pkgName);
+ mRunAnyRestrictedPackages.remove(Pair.create(uid, pkgName));
+ updateBackgroundRestrictedUidPackagesLocked();
+ mActiveUids.delete(uid);
+ }
}
break;
}
@@ -580,6 +608,28 @@
}
}
}
+ updateBackgroundRestrictedUidPackagesLocked();
+ }
+
+ /**
+ * Update the {@link #mBackgroundRestrictedUidPackages} upon mutations on
+ * {@link #mRunAnyRestrictedPackages} or {@link #mForcedAppStandbyEnabled}.
+ */
+ @GuardedBy("mLock")
+ private void updateBackgroundRestrictedUidPackagesLocked() {
+ if (!mForcedAppStandbyEnabled) {
+ mBackgroundRestrictedUidPackages = Collections.emptySet();
+ return;
+ }
+ if (mForceAllAppsStandby) {
+ mBackgroundRestrictedUidPackages = null;
+ return;
+ }
+ Set<Pair<Integer, String>> fasUidPkgs = new ArraySet<>();
+ for (int i = 0, size = mRunAnyRestrictedPackages.size(); i < size; i++) {
+ fasUidPkgs.add(mRunAnyRestrictedPackages.valueAt(i));
+ }
+ mBackgroundRestrictedUidPackages = Collections.unmodifiableSet(fasUidPkgs);
}
private void updateForceAllAppStandbyState() {
@@ -645,6 +695,7 @@
} else {
mRunAnyRestrictedPackages.removeAt(index);
}
+ updateBackgroundRestrictedUidPackagesLocked();
return true;
}
@@ -966,6 +1017,7 @@
mRunAnyRestrictedPackages.removeAt(i);
}
}
+ updateBackgroundRestrictedUidPackagesLocked();
cleanUpArrayForUser(mActiveUids, removedUserId);
mExemptedBucketPackages.remove(removedUserId);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index acdf689..6ef9456 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -16,6 +16,79 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
+import static android.app.tare.EconomyManager.KEY_AM_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.KEY_AM_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS;
+
import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
@@ -24,6 +97,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
import android.util.SparseArray;
/**
@@ -31,6 +111,8 @@
* AlarmManager.
*/
public class AlarmManagerEconomicPolicy extends EconomicPolicy {
+ private static final String TAG = "TARE- " + AlarmManagerEconomicPolicy.class.getSimpleName();
+
public static final int ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE =
TYPE_ACTION | POLICY_AM | 0;
public static final int ACTION_ALARM_WAKEUP_EXACT =
@@ -57,30 +139,50 @@
COST_MODIFIER_PROCESS_STATE
};
+ private long mMinSatiatedBalance;
+ private long mMaxSatiatedBalance;
+ private long mMaxSatiatedCirculation;
+
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+ private final SettingsObserver mSettingsObserver;
+ private final InternalResourceService mInternalResourceService;
+
private final SparseArray<Action> mActions = new SparseArray<>();
private final SparseArray<Reward> mRewards = new SparseArray<>();
AlarmManagerEconomicPolicy(InternalResourceService irs) {
super(irs);
- loadActions();
- loadRewards();
+ mInternalResourceService = irs;
+ mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
+ loadConstants("");
+ }
+
+ @Override
+ void setup() {
+ super.setup();
+ ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
+ resolver.registerContentObserver(
+ Settings.Global.getUriFor(TARE_ALARM_MANAGER_CONSTANTS),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_ALARM_MANAGER_CONSTANTS));
}
@Override
long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
// TODO: take exemption into account
- return arcToNarc(160);
+ return mMinSatiatedBalance;
}
@Override
long getMaxSatiatedBalance() {
- return arcToNarc(1440);
+ return mMaxSatiatedBalance;
}
-
@Override
long getMaxSatiatedCirculation() {
- return arcToNarc(52000);
+ return mMaxSatiatedCirculation;
}
@NonNull
@@ -101,43 +203,162 @@
return mRewards.get(rewardId);
}
- private void loadActions() {
+ private void loadConstants(String policyValuesString) {
+ mActions.clear();
+ mRewards.clear();
+
+ try {
+ mParser.setString(policyValuesString);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Global setting key incorrect: ", e);
+ }
+
+ mMinSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP,
+ DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP));
+ mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_AM_MAX_SATIATED_BALANCE,
+ DEFAULT_AM_MAX_SATIATED_BALANCE));
+ mMaxSatiatedCirculation = arcToNarc(mParser.getInt(KEY_AM_MAX_CIRCULATION,
+ DEFAULT_AM_MAX_CIRCULATION));
+
+ final long exactAllowWhileIdleWakeupBasePrice = arcToNarc(
+ mParser.getInt(KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
- new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE, arcToNarc(3), arcToNarc(5)));
+ new Action(ACTION_ALARM_WAKEUP_EXACT_ALLOW_WHILE_IDLE,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_CTP)),
+ exactAllowWhileIdleWakeupBasePrice));
mActions.put(ACTION_ALARM_WAKEUP_EXACT,
- new Action(ACTION_ALARM_WAKEUP_EXACT, arcToNarc(3), arcToNarc(4)));
+ new Action(ACTION_ALARM_WAKEUP_EXACT,
+ arcToNarc(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_CTP)),
+ arcToNarc(mParser.getInt(KEY_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_EXACT_WAKEUP_BASE_PRICE))));
+
+ final long inexactAllowWhileIdleWakeupBasePrice =
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_WAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- arcToNarc(3), arcToNarc(4)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_WAKEUP_CTP)),
+ inexactAllowWhileIdleWakeupBasePrice));
mActions.put(ACTION_ALARM_WAKEUP_INEXACT,
- new Action(ACTION_ALARM_WAKEUP_INEXACT, arcToNarc(3), arcToNarc(3)));
+ new Action(ACTION_ALARM_WAKEUP_INEXACT,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE))));
+
+ final long exactAllowWhileIdleNonWakeupBasePrice =
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_NONWAKEUP_EXACT_ALLOW_WHILE_IDLE,
- arcToNarc(1), arcToNarc(3)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_NONWAKEUP_CTP)),
+ exactAllowWhileIdleNonWakeupBasePrice));
mActions.put(ACTION_ALARM_NONWAKEUP_EXACT,
- new Action(ACTION_ALARM_NONWAKEUP_EXACT, arcToNarc(1), arcToNarc(2)));
+ new Action(ACTION_ALARM_NONWAKEUP_EXACT,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_EXACT_NONWAKEUP_BASE_PRICE))));
+
+ final long inexactAllowWhileIdleNonWakeupBasePrice =
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_BASE_PRICE));
+
mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
new Action(ACTION_ALARM_NONWAKEUP_INEXACT_ALLOW_WHILE_IDLE,
- arcToNarc(1), arcToNarc(2)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_INEXACT_NONWAKEUP_CTP)),
+ inexactAllowWhileIdleNonWakeupBasePrice));
mActions.put(ACTION_ALARM_NONWAKEUP_INEXACT,
- new Action(ACTION_ALARM_NONWAKEUP_INEXACT, arcToNarc(1), arcToNarc(1)));
+ new Action(ACTION_ALARM_NONWAKEUP_INEXACT,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_BASE_PRICE))));
mActions.put(ACTION_ALARM_CLOCK,
- new Action(ACTION_ALARM_CLOCK, arcToNarc(5), arcToNarc(10)));
- }
+ new Action(ACTION_ALARM_CLOCK,
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALARMCLOCK_CTP,
+ DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_CTP)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE,
+ DEFAULT_AM_ACTION_ALARM_ALARMCLOCK_BASE_PRICE))));
- private void loadRewards() {
- mRewards.put(REWARD_TOP_ACTIVITY,
- new Reward(REWARD_TOP_ACTIVITY,
- arcToNarc(0), /* .01 arcs */ arcToNarc(1) / 100, arcToNarc(500)));
- mRewards.put(REWARD_NOTIFICATION_SEEN,
- new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(3), arcToNarc(0), arcToNarc(60)));
+ mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_INSTANT,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT)),
+ (long) (arcToNarc(1) * mParser.getFloat(KEY_AM_REWARD_TOP_ACTIVITY_ONGOING,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_TOP_ACTIVITY_MAX,
+ DEFAULT_AM_REWARD_TOP_ACTIVITY_MAX))));
+ mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_INSTANT,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_ONGOING,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_NOTIFICATION_SEEN_MAX,
+ DEFAULT_AM_REWARD_NOTIFICATION_SEEN_MAX))));
mRewards.put(REWARD_NOTIFICATION_INTERACTION,
new Reward(REWARD_NOTIFICATION_INTERACTION,
- arcToNarc(5), arcToNarc(0), arcToNarc(500)));
- mRewards.put(REWARD_WIDGET_INTERACTION,
- new Reward(REWARD_WIDGET_INTERACTION, arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING,
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_NOTIFICATION_INTERACTION_MAX,
+ DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_MAX))));
+ mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_ONGOING,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_WIDGET_INTERACTION_MAX,
+ DEFAULT_AM_REWARD_WIDGET_INTERACTION_MAX))));
mRewards.put(REWARD_OTHER_USER_INTERACTION,
new Reward(REWARD_OTHER_USER_INTERACTION,
- arcToNarc(10), arcToNarc(0), arcToNarc(500)));
+ arcToNarc(mParser.getInt(KEY_AM_REWARD_OTHER_USER_INTERACTION_INSTANT,
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_OTHER_USER_INTERACTION_ONGOING,
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_AM_REWARD_OTHER_USER_INTERACTION_MAX,
+ DEFAULT_AM_REWARD_OTHER_USER_INTERACTION_MAX))));
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_ALARM_MANAGER_CONSTANTS));
+ }
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index 8c56c61..f05e5c9 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -67,6 +67,14 @@
}
@Override
+ void setup() {
+ super.setup();
+ for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
+ mEnabledEconomicPolicies.valueAt(i).setup();
+ }
+ }
+
+ @Override
public long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
long min = 0;
for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index ff008a2..e339650 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -16,6 +16,88 @@
package com.android.server.tare;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_HIGH_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MAX_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_DEFAULT_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_HIGH_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_LOW_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MAX_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_RUNNING_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
+import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
+import static android.app.tare.EconomyManager.KEY_JS_MAX_CIRCULATION;
+import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_TOP_ACTIVITY_ONGOING;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_MAX;
+import static android.app.tare.EconomyManager.KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING;
+import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS;
+
import static com.android.server.tare.Modifier.COST_MODIFIER_CHARGING;
import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
@@ -24,6 +106,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
import android.util.SparseArray;
/**
@@ -31,6 +120,8 @@
* JobScheduler.
*/
public class JobSchedulerEconomicPolicy extends EconomicPolicy {
+ private static final String TAG = "TARE- " + JobSchedulerEconomicPolicy.class.getSimpleName();
+
public static final int ACTION_JOB_MAX_START = TYPE_ACTION | POLICY_JS | 0;
public static final int ACTION_JOB_MAX_RUNNING = TYPE_ACTION | POLICY_JS | 1;
public static final int ACTION_JOB_HIGH_START = TYPE_ACTION | POLICY_JS | 2;
@@ -50,29 +141,50 @@
COST_MODIFIER_PROCESS_STATE
};
+ private long mMinSatiatedBalance;
+ private long mMaxSatiatedBalance;
+ private long mMaxSatiatedCirculation;
+
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+ private final SettingsObserver mSettingsObserver;
+ private final InternalResourceService mInternalResourceService;
+
private final SparseArray<Action> mActions = new SparseArray<>();
private final SparseArray<Reward> mRewards = new SparseArray<>();
JobSchedulerEconomicPolicy(InternalResourceService irs) {
super(irs);
- loadActions();
- loadRewards();
+ mInternalResourceService = irs;
+ mSettingsObserver = new SettingsObserver(TareHandlerThread.getHandler());
+ loadConstants("");
+ }
+
+ @Override
+ void setup() {
+ super.setup();
+ ContentResolver resolver = mInternalResourceService.getContext().getContentResolver();
+ resolver.registerContentObserver(
+ Settings.Global.getUriFor(TARE_JOB_SCHEDULER_CONSTANTS),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_JOB_SCHEDULER_CONSTANTS));
}
@Override
long getMinSatiatedBalance(final int userId, @NonNull final String pkgName) {
// TODO: incorporate time since usage
- return arcToNarc(2000);
+ return mMinSatiatedBalance;
}
@Override
long getMaxSatiatedBalance() {
- return arcToNarc(60000);
+ return mMaxSatiatedBalance;
}
@Override
long getMaxSatiatedCirculation() {
- return arcToNarc(691200);
+ return mMaxSatiatedCirculation;
}
@NonNull
@@ -93,45 +205,134 @@
return mRewards.get(rewardId);
}
- private void loadActions() {
- mActions.put(ACTION_JOB_MAX_START,
- new Action(ACTION_JOB_MAX_START, arcToNarc(3), arcToNarc(10)));
- mActions.put(ACTION_JOB_MAX_RUNNING,
- new Action(ACTION_JOB_MAX_RUNNING, arcToNarc(2), arcToNarc(5)));
- mActions.put(ACTION_JOB_HIGH_START,
- new Action(ACTION_JOB_HIGH_START, arcToNarc(3), arcToNarc(8)));
- mActions.put(ACTION_JOB_HIGH_RUNNING,
- new Action(ACTION_JOB_HIGH_RUNNING, arcToNarc(2), arcToNarc(4)));
- mActions.put(ACTION_JOB_DEFAULT_START,
- new Action(ACTION_JOB_DEFAULT_START, arcToNarc(3), arcToNarc(6)));
- mActions.put(ACTION_JOB_DEFAULT_RUNNING,
- new Action(ACTION_JOB_DEFAULT_RUNNING, arcToNarc(2), arcToNarc(3)));
- mActions.put(ACTION_JOB_LOW_START,
- new Action(ACTION_JOB_LOW_START, arcToNarc(3), arcToNarc(4)));
- mActions.put(ACTION_JOB_LOW_RUNNING,
- new Action(ACTION_JOB_LOW_RUNNING, arcToNarc(2), arcToNarc(2)));
- mActions.put(ACTION_JOB_MIN_START,
- new Action(ACTION_JOB_MIN_START, arcToNarc(3), arcToNarc(2)));
- mActions.put(ACTION_JOB_MIN_RUNNING,
- new Action(ACTION_JOB_MIN_RUNNING, arcToNarc(2), arcToNarc(1)));
- mActions.put(ACTION_JOB_TIMEOUT,
- new Action(ACTION_JOB_TIMEOUT, arcToNarc(30), arcToNarc(60)));
- }
+ private void loadConstants(String policyValuesString) {
+ mActions.clear();
+ mRewards.clear();
- private void loadRewards() {
- mRewards.put(REWARD_TOP_ACTIVITY,
- new Reward(REWARD_TOP_ACTIVITY,
- arcToNarc(0), /* .5 arcs */ arcToNarc(5) / 10, arcToNarc(15000)));
- mRewards.put(REWARD_NOTIFICATION_SEEN,
- new Reward(REWARD_NOTIFICATION_SEEN, arcToNarc(1), arcToNarc(0), arcToNarc(10)));
+ try {
+ mParser.setString(policyValuesString);
+ } catch (IllegalArgumentException e) {
+ Slog.e(TAG, "Global setting key incorrect: ", e);
+ }
+
+ mMinSatiatedBalance = arcToNarc(
+ mParser.getInt(KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP,
+ DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP));
+ mMaxSatiatedBalance = arcToNarc(mParser.getInt(KEY_JS_MAX_SATIATED_BALANCE,
+ DEFAULT_JS_MAX_SATIATED_BALANCE));
+ mMaxSatiatedCirculation = arcToNarc(mParser.getInt(KEY_JS_MAX_CIRCULATION,
+ DEFAULT_JS_MAX_CIRCULATION));
+
+ mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_CTP,
+ DEFAULT_JS_ACTION_JOB_MAX_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MAX_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_MAX_RUNNING, new Action(ACTION_JOB_MAX_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_MAX_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MAX_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_HIGH_START, new Action(ACTION_JOB_HIGH_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_CTP,
+ DEFAULT_JS_ACTION_JOB_HIGH_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_HIGH_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_HIGH_RUNNING, new Action(ACTION_JOB_HIGH_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_HIGH_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_DEFAULT_START, new Action(ACTION_JOB_DEFAULT_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_CTP,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_DEFAULT_RUNNING, new Action(ACTION_JOB_DEFAULT_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_DEFAULT_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_LOW_START, new Action(ACTION_JOB_LOW_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_CTP,
+ DEFAULT_JS_ACTION_JOB_LOW_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_LOW_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_LOW_RUNNING, new Action(ACTION_JOB_LOW_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_LOW_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_MIN_START, new Action(ACTION_JOB_MIN_START,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_CTP,
+ DEFAULT_JS_ACTION_JOB_MIN_START_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MIN_START_BASE_PRICE))));
+ mActions.put(ACTION_JOB_MIN_RUNNING, new Action(ACTION_JOB_MIN_RUNNING,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_CTP,
+ DEFAULT_JS_ACTION_JOB_MIN_RUNNING_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_MIN_RUNNING_BASE_PRICE))));
+ mActions.put(ACTION_JOB_TIMEOUT, new Action(ACTION_JOB_TIMEOUT,
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP,
+ DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP)),
+ arcToNarc(mParser.getInt(KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE,
+ DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE))));
+
+ mRewards.put(REWARD_TOP_ACTIVITY, new Reward(REWARD_TOP_ACTIVITY,
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_INSTANT,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_INSTANT)),
+ (long) (arcToNarc(1) * mParser.getFloat(KEY_JS_REWARD_TOP_ACTIVITY_ONGOING,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_TOP_ACTIVITY_MAX,
+ DEFAULT_JS_REWARD_TOP_ACTIVITY_MAX))));
+ mRewards.put(REWARD_NOTIFICATION_SEEN, new Reward(REWARD_NOTIFICATION_SEEN,
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_INSTANT,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_ONGOING,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_NOTIFICATION_SEEN_MAX,
+ DEFAULT_JS_REWARD_NOTIFICATION_SEEN_MAX))));
mRewards.put(REWARD_NOTIFICATION_INTERACTION,
new Reward(REWARD_NOTIFICATION_INTERACTION,
- arcToNarc(5), arcToNarc(0), arcToNarc(5000)));
- mRewards.put(REWARD_WIDGET_INTERACTION,
- new Reward(REWARD_WIDGET_INTERACTION,
- arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING,
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_NOTIFICATION_INTERACTION_MAX,
+ DEFAULT_JS_REWARD_NOTIFICATION_INTERACTION_MAX))));
+ mRewards.put(REWARD_WIDGET_INTERACTION, new Reward(REWARD_WIDGET_INTERACTION,
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_ONGOING,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_WIDGET_INTERACTION_MAX,
+ DEFAULT_JS_REWARD_WIDGET_INTERACTION_MAX))));
mRewards.put(REWARD_OTHER_USER_INTERACTION,
new Reward(REWARD_OTHER_USER_INTERACTION,
- arcToNarc(10), arcToNarc(0), arcToNarc(5000)));
+ arcToNarc(mParser.getInt(KEY_JS_REWARD_OTHER_USER_INTERACTION_INSTANT,
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_INSTANT)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_OTHER_USER_INTERACTION_ONGOING,
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_ONGOING)),
+ arcToNarc(mParser.getInt(
+ KEY_JS_REWARD_OTHER_USER_INTERACTION_MAX,
+ DEFAULT_JS_REWARD_OTHER_USER_INTERACTION_MAX))));
+ }
+
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ loadConstants(Settings.Global.getString(
+ mInternalResourceService.getContext().getContentResolver(),
+ TARE_JOB_SCHEDULER_CONSTANTS));
+ }
}
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 6e27aff..929e63e 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -107,9 +107,13 @@
static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays";
static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1;
static constexpr size_t TEXT_POS_LEN_MAX = 16;
+static const int DYNAMIC_COLOR_COUNT = 4;
static const char U_TEXTURE[] = "uTexture";
static const char U_FADE[] = "uFade";
static const char U_CROP_AREA[] = "uCropArea";
+static const char U_START_COLOR_PREFIX[] = "uStartColor";
+static const char U_END_COLOR_PREFIX[] = "uEndColor";
+static const char U_COLOR_PROGRESS[] = "uColorProgress";
static const char A_UV[] = "aUv";
static const char A_POSITION[] = "aPosition";
static const char VERTEX_SHADER_SOURCE[] = R"(
@@ -121,6 +125,28 @@
gl_Position = aPosition;
vUv = aUv;
})";
+static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
+ precision mediump float;
+ uniform sampler2D uTexture;
+ uniform float uFade;
+ uniform float uColorProgress;
+ uniform vec4 uStartColor0;
+ uniform vec4 uStartColor1;
+ uniform vec4 uStartColor2;
+ uniform vec4 uStartColor3;
+ uniform vec4 uEndColor0;
+ uniform vec4 uEndColor1;
+ uniform vec4 uEndColor2;
+ uniform vec4 uEndColor3;
+ varying highp vec2 vUv;
+ void main() {
+ vec4 mask = texture2D(uTexture, vUv);
+ vec4 color = mask.r * mix(uStartColor0, uEndColor0, uColorProgress)
+ + mask.g * mix(uStartColor1, uEndColor1, uColorProgress)
+ + mask.b * mix(uStartColor2, uEndColor2, uColorProgress)
+ + mask.a * mix(uStartColor3, uEndColor3, uColorProgress);
+ gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
+ })";
static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
uniform sampler2D uTexture;
@@ -128,7 +154,7 @@
varying highp vec2 vUv;
void main() {
vec4 color = texture2D(uTexture, vUv);
- gl_FragColor = vec4(color.x, color.y, color.z, 1.0 - uFade);
+ gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
})";
static const char TEXT_FRAG_SHADER_SOURCE[] = R"(
precision mediump float;
@@ -226,6 +252,10 @@
outInfo->stride = AImageDecoder_getMinimumStride(decoder);
outInfo->flags = 0;
+ // Set decoding option to alpha unpremultiplied so that the R, G, B channels
+ // of transparent pixels are preserved.
+ AImageDecoder_setUnpremultipliedRequired(decoder, true);
+
const size_t size = outInfo->stride * outInfo->height;
void* pixels = malloc(size);
int result = AImageDecoder_decodeImage(decoder, pixels, outInfo->stride, size);
@@ -675,9 +705,12 @@
}
void BootAnimation::initShaders() {
+ bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled;
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
GLuint imageFragmentShader =
- compileShader(GL_FRAGMENT_SHADER, (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
+ compileShader(GL_FRAGMENT_SHADER, dynamicColoringEnabled
+ ? (const GLchar *)IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE
+ : (const GLchar *)IMAGE_FRAG_SHADER_SOURCE);
GLuint textFragmentShader =
compileShader(GL_FRAGMENT_SHADER, (const GLchar *)TEXT_FRAG_SHADER_SOURCE);
@@ -692,6 +725,22 @@
glVertexAttribPointer(uvLocation, 2, GL_FLOAT, GL_FALSE, 0, quadUVs);
glEnableVertexAttribArray(uvLocation);
+ if (dynamicColoringEnabled) {
+ glUseProgram(mImageShader);
+ SLOGI("[BootAnimation] Dynamically coloring boot animation.");
+ for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+ float *startColor = mAnimation->startColors[i];
+ float *endColor = mAnimation->endColors[i];
+ glUniform4f(glGetUniformLocation(mImageShader,
+ (U_START_COLOR_PREFIX + std::to_string(i)).c_str()),
+ startColor[0], startColor[1], startColor[2], 1 /* alpha */);
+ glUniform4f(glGetUniformLocation(mImageShader,
+ (U_END_COLOR_PREFIX + std::to_string(i)).c_str()),
+ endColor[0], endColor[1], endColor[2], 1 /* alpha */);
+ }
+ mImageColorProgressLocation = glGetUniformLocation(mImageShader, U_COLOR_PROGRESS);
+ }
+
// Initialize text shader.
mTextShader = linkShader(vertexShader, textFragmentShader);
positionLocation = glGetAttribLocation(mTextShader, A_POSITION);
@@ -869,6 +918,20 @@
return true;
}
+// Parse a color represented as a signed decimal int string.
+// E.g. "-2757722" (whose hex 2's complement is 0xFFD5EBA6).
+// If the input color string is empty, set color with values in defaultColor.
+static void parseColorDecimalString(const std::string& colorString,
+ float color[3], float defaultColor[3]) {
+ if (colorString == "") {
+ memcpy(color, defaultColor, sizeof(float) * 3);
+ return;
+ }
+ int colorInt = atoi(colorString.c_str());
+ color[0] = ((float)((colorInt >> 16) & 0xFF)) / 0xFF; // r
+ color[1] = ((float)((colorInt >> 8) & 0xFF)) / 0xFF; // g
+ color[2] = ((float)(colorInt & 0xFF)) / 0xFF; // b
+}
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
ZipEntryRO entry = zip->findEntryByName(name);
@@ -1010,6 +1073,8 @@
return false;
}
char const* s = desString.string();
+ std::string dynamicColoringPartName = "";
+ bool postDynamicColoring = false;
// Parse the description file
for (;;) {
@@ -1028,7 +1093,13 @@
char color[7] = "000000"; // default to black if unspecified
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
+ char dynamicColoringPartNameBuffer[ANIM_ENTRY_NAME_MAX];
char pathType;
+ // start colors default to black if unspecified
+ char start_color_0[7] = "000000";
+ char start_color_1[7] = "000000";
+ char start_color_2[7] = "000000";
+ char start_color_3[7] = "000000";
int nextReadPos;
@@ -1043,6 +1114,15 @@
} else {
animation.progressEnabled = false;
}
+ } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s",
+ dynamicColoringPartNameBuffer,
+ start_color_0, start_color_1, start_color_2, start_color_3)) {
+ animation.dynamicColoringEnabled = true;
+ parseColor(start_color_0, animation.startColors[0]);
+ parseColor(start_color_1, animation.startColors[1]);
+ parseColor(start_color_2, animation.startColors[2]);
+ parseColor(start_color_3, animation.startColors[3]);
+ dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
} else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
&pathType, &count, &pause, path, &nextReadPos) >= 4) {
if (pathType == 'f') {
@@ -1055,6 +1135,16 @@
// "clockPos1=%s, clockPos2=%s",
// pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
Animation::Part part;
+ if (path == dynamicColoringPartName) {
+ // Part is specified to use dynamic coloring.
+ part.useDynamicColoring = true;
+ part.postDynamicColoring = false;
+ postDynamicColoring = true;
+ } else {
+ // Part does not use dynamic coloring.
+ part.useDynamicColoring = false;
+ part.postDynamicColoring = postDynamicColoring;
+ }
part.playUntilComplete = pathType == 'c';
part.framesToFadeCount = framesToFadeCount;
part.count = count;
@@ -1086,6 +1176,12 @@
s = ++endl;
}
+ for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
+ parseColorDecimalString(
+ android::base::GetProperty("persist.bootanim.color" + std::to_string(i + 1), ""),
+ animation.endColors[i], animation.startColors[i]);
+ }
+
return true;
}
@@ -1357,6 +1453,14 @@
for (size_t j=0 ; j<fcount ; j++) {
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
+ // Color progress is
+ // - the normalized animation progress between [0, 1] for the dynamic coloring part,
+ // - 0 for parts that come before,
+ // - 1 for parts that come after.
+ float colorProgress = part.useDynamicColoring
+ ? (float)j / fcount
+ : (part.postDynamicColoring ? 1 : 0);
+
processDisplayEvents();
const int animationX = (mWidth - animation.width) / 2;
@@ -1376,19 +1480,7 @@
const int xc = animationX + frame.trimX;
const int yc = animationY + frame.trimY;
- Region clearReg(Rect(mWidth, mHeight));
- clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
- if (!clearReg.isEmpty()) {
- Region::const_iterator head(clearReg.begin());
- Region::const_iterator tail(clearReg.end());
- glEnable(GL_SCISSOR_TEST);
- while (head != tail) {
- const Rect& r2(*head++);
- glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
- glClear(GL_COLOR_BUFFER_BIT);
- }
- glDisable(GL_SCISSOR_TEST);
- }
+ glClear(GL_COLOR_BUFFER_BIT);
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
// which is equivalent to mHeight - (yc + frame.trimHeight)
const int frameDrawY = mHeight - (yc + frame.trimHeight);
@@ -1404,6 +1496,9 @@
glUseProgram(mImageShader);
glUniform1i(mImageTextureLocation, 0);
glUniform1f(mImageFadeLocation, fade);
+ if (animation.dynamicColoringEnabled) {
+ glUniform1f(mImageColorProgressLocation, colorProgress);
+ }
glEnable(GL_BLEND);
drawTexturedQuad(xc, frameDrawY, frame.trimWidth, frame.trimHeight);
glDisable(GL_BLEND);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 7b616d9..2c861eb 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -90,6 +90,10 @@
uint8_t* audioData;
int audioLength;
Animation* animation;
+ // Controls if dynamic coloring is enabled for this part.
+ bool useDynamicColoring = false;
+ // Defines if this part is played after the dynamic coloring part.
+ bool postDynamicColoring = false;
bool hasFadingPhase() const {
return !playUntilComplete && framesToFadeCount > 0;
@@ -105,6 +109,10 @@
ZipFileRO* zip;
Font clockFont;
Font progressFont;
+ // Controls if dynamic coloring is enabled for the whole animation.
+ bool dynamicColoringEnabled = false;
+ float startColors[4][3]; // Start colors of dynamic color transition.
+ float endColors[4][3]; // End colors of dynamic color transition.
};
// All callbacks will be called from this class's internal thread.
@@ -226,6 +234,7 @@
GLuint mImageTextureLocation;
GLuint mTextCropAreaLocation;
GLuint mTextTextureLocation;
+ GLuint mImageColorProgressLocation;
};
// ---------------------------------------------------------------------------
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ae812ec..bff1e57 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1105,18 +1105,17 @@
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
- CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
+ CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges,
SharedMemory serializedSystemFontMap) {
if (services != null) {
if (false) {
// Test code to make sure the app could see the passed-in services.
- for (Object oname : services.keySet()) {
- if (services.get(oname) == null) {
+ for (String name : services.keySet()) {
+ if (services.get(name) == null) {
continue; // AM just passed in a null service.
}
- String name = (String) oname;
// See b/79378449 about the following exemption.
switch (name) {
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index d6ff6d3..2afd98e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -77,7 +77,7 @@
IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
int debugMode, boolean enableBinderTracking, boolean trackAllocation,
boolean restrictedBackupMode, boolean persistent, in Configuration config,
- in CompatibilityInfo compatInfo, in Map services,
+ in CompatibilityInfo compatInfo, in Map<String, IBinder> services,
in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
in ContentCaptureOptions contentCaptureOptions, in long[] disabledCompatChanges,
in SharedMemory serializedSystemFontMap);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4b401a5..7102314 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3270,22 +3270,6 @@
}
/**
- * Returns true if the Profile Challenge is available to use for the given profile user.
- *
- * @hide
- */
- public boolean isSeparateProfileChallengeAllowed(int userHandle) {
- if (mService != null) {
- try {
- return mService.isSeparateProfileChallengeAllowed(userHandle);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- return false;
- }
-
- /**
* Constant for {@link #setPasswordQuality}: the policy has no requirements
* for the password. Note that quality constants are ordered so that higher
* values are more restrictive.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b6c48a1..8cf1f80 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -373,8 +373,6 @@
CharSequence getShortSupportMessageForUser(in ComponentName admin, int userHandle);
CharSequence getLongSupportMessageForUser(in ComponentName admin, int userHandle);
- boolean isSeparateProfileChallengeAllowed(int userHandle);
-
void setOrganizationColor(in ComponentName admin, in int color);
void setOrganizationColorForUser(in int color, in int userId);
int getOrganizationColor(in ComponentName admin);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 2ed26a9f..2b28c11 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -64,6 +64,8 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -78,6 +80,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
+import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -715,10 +718,21 @@
private final IBluetoothManager mManagerService;
private final AttributionSource mAttributionSource;
+ // Yeah, keeping both mService and sService isn't pretty, but it's too late
+ // in the current release for a major refactoring, so we leave them both
+ // intact until this can be cleaned up in a future release
+
@UnsupportedAppUsage
+ @GuardedBy("mServiceLock")
private IBluetooth mService;
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("sServiceLock")
+ private static boolean sServiceRegistered;
+ @GuardedBy("sServiceLock")
+ private static IBluetooth sService;
+ private static final Object sServiceLock = new Object();
+
private final Object mLock = new Object();
private final Map<LeScanCallback, ScanCallback> mLeScanClients;
private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
@@ -792,19 +806,11 @@
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
*/
BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
- if (managerService == null) {
- throw new IllegalArgumentException("bluetooth manager service is null");
- }
- try {
- mServiceLock.writeLock().lock();
- mService = managerService.registerAdapter(mManagerCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.writeLock().unlock();
- }
mManagerService = Objects.requireNonNull(managerService);
mAttributionSource = Objects.requireNonNull(attributionSource);
+ synchronized (mServiceLock.writeLock()) {
+ mService = getBluetoothService(mManagerCallback);
+ }
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
mToken = new Binder(DESCRIPTOR);
}
@@ -3162,21 +3168,16 @@
}
}
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothManagerCallback mManagerCallback =
+ private static final IBluetoothManagerCallback sManagerCallback =
new IBluetoothManagerCallback.Stub() {
- @SuppressLint("AndroidFrameworkRequiresPermission")
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
if (DBG) {
Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
}
- mServiceLock.writeLock().lock();
- mService = bluetoothService;
- mServiceLock.writeLock().unlock();
-
- synchronized (mProxyServiceStateCallbacks) {
- for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
+ synchronized (sServiceLock) {
+ sService = bluetoothService;
+ for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
try {
if (cb != null) {
cb.onBluetoothServiceUp(bluetoothService);
@@ -3188,6 +3189,56 @@
}
}
}
+ }
+
+ public void onBluetoothServiceDown() {
+ if (DBG) {
+ Log.d(TAG, "onBluetoothServiceDown");
+ }
+
+ synchronized (sServiceLock) {
+ sService = null;
+ for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
+ try {
+ if (cb != null) {
+ cb.onBluetoothServiceDown();
+ } else {
+ Log.d(TAG, "onBluetoothServiceDown: cb is null!");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+ }
+
+ public void onBrEdrDown() {
+ if (VDBG) {
+ Log.i(TAG, "onBrEdrDown");
+ }
+
+ synchronized (sServiceLock) {
+ for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
+ try {
+ if (cb != null) {
+ cb.onBrEdrDown();
+ } else {
+ Log.d(TAG, "onBrEdrDown: cb is null!");
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+ }
+ };
+
+ private final IBluetoothManagerCallback mManagerCallback =
+ new IBluetoothManagerCallback.Stub() {
+ public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+ synchronized (mServiceLock.writeLock()) {
+ mService = bluetoothService;
+ }
synchronized (mMetadataListeners) {
mMetadataListeners.forEach((device, pair) -> {
try {
@@ -3212,12 +3263,7 @@
}
public void onBluetoothServiceDown() {
- if (DBG) {
- Log.d(TAG, "onBluetoothServiceDown: " + mService);
- }
-
- try {
- mServiceLock.writeLock().lock();
+ synchronized (mServiceLock.writeLock()) {
mService = null;
if (mLeScanClients != null) {
mLeScanClients.clear();
@@ -3228,29 +3274,10 @@
if (mBluetoothLeScanner != null) {
mBluetoothLeScanner.cleanup();
}
- } finally {
- mServiceLock.writeLock().unlock();
- }
-
- synchronized (mProxyServiceStateCallbacks) {
- for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
- try {
- if (cb != null) {
- cb.onBluetoothServiceDown();
- } else {
- Log.d(TAG, "onBluetoothServiceDown: cb is null!");
- }
- } catch (Exception e) {
- Log.e(TAG, "", e);
- }
- }
}
}
public void onBrEdrDown() {
- if (VDBG) {
- Log.i(TAG, "onBrEdrDown: " + mService);
- }
}
};
@@ -3485,15 +3512,12 @@
protected void finalize() throws Throwable {
try {
- mManagerService.unregisterAdapter(mManagerCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
+ removeServiceStateCallback(mManagerCallback);
} finally {
super.finalize();
}
}
-
/**
* Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
* <p>Alphabetic characters must be uppercase to be valid.
@@ -3557,24 +3581,64 @@
return mAttributionSource;
}
- private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks =
- new ArrayList<IBluetoothManagerCallback>();
+ @GuardedBy("sServiceLock")
+ private static final WeakHashMap<IBluetoothManagerCallback, Void> sProxyServiceStateCallbacks =
+ new WeakHashMap<>();
+
+ /*package*/ IBluetooth getBluetoothService() {
+ synchronized (sServiceLock) {
+ if (sProxyServiceStateCallbacks.isEmpty()) {
+ throw new IllegalStateException(
+ "Anonymous service access requires at least one lifecycle in process");
+ }
+ return sService;
+ }
+ }
@UnsupportedAppUsage
/*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
- synchronized (mProxyServiceStateCallbacks) {
- if (cb == null) {
- Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
- } else if (!mProxyServiceStateCallbacks.contains(cb)) {
- mProxyServiceStateCallbacks.add(cb);
- }
+ Objects.requireNonNull(cb);
+ synchronized (sServiceLock) {
+ sProxyServiceStateCallbacks.put(cb, null);
+ registerOrUnregisterAdapterLocked();
+ return sService;
}
- return mService;
}
/*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
- synchronized (mProxyServiceStateCallbacks) {
- mProxyServiceStateCallbacks.remove(cb);
+ Objects.requireNonNull(cb);
+ synchronized (sServiceLock) {
+ sProxyServiceStateCallbacks.remove(cb);
+ registerOrUnregisterAdapterLocked();
+ }
+ }
+
+ /**
+ * Handle registering (or unregistering) a single process-wide
+ * {@link IBluetoothManagerCallback} based on the presence of local
+ * {@link #sProxyServiceStateCallbacks} clients.
+ */
+ @GuardedBy("sServiceLock")
+ private void registerOrUnregisterAdapterLocked() {
+ final boolean isRegistered = sServiceRegistered;
+ final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty();
+
+ if (isRegistered != wantRegistered) {
+ if (wantRegistered) {
+ try {
+ sService = mManagerService.registerAdapter(sManagerCallback);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ try {
+ mManagerService.unregisterAdapter(sManagerCallback);
+ sService = null;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ sServiceRegistered = wantRegistered;
}
}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index bb409d5..1655b62 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -399,7 +399,7 @@
try {
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
IBluetooth bluetoothProxy =
- BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ BluetoothAdapter.getDefaultAdapter().getBluetoothService();
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
mUuid, mPort, getSecurityFlags());
@@ -438,7 +438,7 @@
/*package*/ int bindListen() {
int ret;
if (mSocketState == SocketState.CLOSED) return EBADFD;
- IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
if (bluetoothProxy == null) {
Log.e(TAG, "bindListen fail, reason: bluetooth is off");
return -1;
@@ -706,7 +706,7 @@
throw new IOException("socket closed");
}
IBluetooth bluetoothProxy =
- BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
+ BluetoothAdapter.getDefaultAdapter().getBluetoothService();
if (bluetoothProxy == null) {
throw new IOException("Bluetooth is off");
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a5cd331..19db0ba 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1077,8 +1077,7 @@
public static final int ROLLBACK_DATA_POLICY_WIPE = 1;
/**
- * User data won't be backed up during install and won't be restored during rollback.
- * TODO: Not implemented yet.
+ * User data won't be backed up during install and will remain unchanged during rollback.
*
* @hide
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4b6b876..57fd736 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16910,6 +16910,14 @@
* @hide
*/
public static final String COMBINED_LOCATION_ENABLED = "combined_location_enable";
+
+ /**
+ * The wrist orientation mode of the device
+ * Valid values - LEFT_WRIST_ROTATION_0 = "0" (default), LEFT_WRIST_ROTATION_180 = "1",
+ * RIGHT_WRIST_ROTATION_0 = "2", RIGHT_WRIST_ROTATION_180 = "3"
+ * @hide
+ */
+ public static final String WRIST_ORIENTATION_MODE = "wear_wrist_orientation_mode";
}
}
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index c16ee42..7d2cb50 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -789,6 +789,9 @@
} else {
mDisplayResolveInfo.setDisplayIcon(d);
mHolder.bindIcon(mDisplayResolveInfo);
+ // Notify in case view is already bound to resolve the race conditions on
+ // low end devices
+ notifyDataSetChanged();
}
}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 10750b6..0c56c67 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -64,8 +64,7 @@
public static final String LIB_DIR_NAME = "lib";
public static final String LIB64_DIR_NAME = "lib64";
- // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate
- // that the cpuAbiOverride must be clear.
+ // Special value for indicating that the cpuAbiOverride must be clear.
public static final String CLEAR_ABI_OVERRIDE = "-";
/**
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 498505c..dbf4528 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -846,14 +846,6 @@
return isManagedProfile(userHandle) && !hasSeparateChallenge(userHandle);
}
- /**
- * Retrieves whether the current DPM allows use of the Profile Challenge.
- */
- public boolean isSeparateProfileChallengeAllowed(int userHandle) {
- return isManagedProfile(userHandle)
- && getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
- }
-
private boolean hasSeparateChallenge(int userHandle) {
try {
return getLockSettings().getSeparateProfileChallengeEnabled(userHandle);
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index d1c4b34..a90a38b 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -641,7 +641,7 @@
if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0) {
sp<MediaEvent> mediaEventSp =
- new MediaEvent(mFilterClient, makeFromAidl(mediaEvent.avMemory),
+ new MediaEvent(mFilterClient, dupFromAidl(mediaEvent.avMemory),
mediaEvent.avDataId, dataLength + offset, obj);
mediaEventSp->mAvHandleRefCnt++;
env->SetLongField(obj, eventContext, (jlong)mediaEventSp.get());
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index eea27ea..d4d8837 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -160,7 +160,7 @@
Result FilterClient::releaseAvHandle(native_handle_t* handle, uint64_t avDataId) {
if (mTunerFilter != nullptr) {
- Status s = mTunerFilter->releaseAvHandle(makeToAidl(handle), avDataId);
+ Status s = mTunerFilter->releaseAvHandle(dupToAidl(handle), avDataId);
return ClientHelper::getServiceSpecificErrorCode(s);
}
@@ -308,7 +308,7 @@
NativeHandle avMemory;
Status s = mTunerFilter->getAvSharedHandle(&avMemory, &size);
if (s.isOk()) {
- mAvSharedHandle = native_handle_clone(makeFromAidl(avMemory));
+ mAvSharedHandle = dupFromAidl(avMemory);
mAvSharedMemSize = size;
}
}
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index 99efbde..b1cba1a 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -138,15 +138,15 @@
<item msgid="1333279807604675720">"స్టీరియో"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
- <item msgid="1241278021345116816">"ఆడియో నాణ్యత (990kbps/909kbps) కోసం అనుకూలీకరించబడింది"</item>
- <item msgid="3523665555859696539">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత (660kbps/606kbps)"</item>
- <item msgid="886408010459747589">"కనెక్షన్ నాణ్యత (330kbps/303kbps) కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="1241278021345116816">"ఆడియో క్వాలిటీ (990kbps/909kbps) కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="3523665555859696539">"సమతుల్య ఆడియో మరియు కనెక్షన్ క్వాలిటీ (660kbps/606kbps)"</item>
+ <item msgid="886408010459747589">"కనెక్షన్ క్వాలిటీ (330kbps/303kbps) కోసం అనుకూలీకరించబడింది"</item>
<item msgid="3808414041654351577">"ఉత్తమ కృషి (అనుకూల బిట్ రేట్)"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
- <item msgid="804499336721569838">"ఆడియో నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
- <item msgid="7451422070435297462">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత"</item>
- <item msgid="6173114545795428901">"కనెక్షన్ నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="804499336721569838">"ఆడియో క్వాలిటీ కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="7451422070435297462">"సమతుల్య ఆడియో మరియు కనెక్షన్ క్వాలిటీ"</item>
+ <item msgid="6173114545795428901">"కనెక్షన్ క్వాలిటీ కోసం అనుకూలీకరించబడింది"</item>
<item msgid="4349908264188040530">"ఉత్తమ కృషి (అనుకూల బిట్ రేట్)"</item>
</string-array>
<string-array name="bluetooth_audio_active_device_summaries">
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 7ee8353..54e8fc8 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -90,7 +90,7 @@
<string name="bluetooth_profile_pbap" msgid="7064307749579335765">"కాంటాక్ట్ షేరింగ్"</string>
<string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"పరిచయ భాగస్వామ్యం కోసం ఉపయోగించు"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ భాగస్వామ్యం"</string>
- <string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన సందేశాలు"</string>
+ <string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన మెసేజ్లు"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM యాక్సెస్"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ఆడియో: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ఆడియో"</string>
@@ -116,7 +116,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"జత చేయి"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"జత చేయి"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"రద్దు చేయి"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"జత చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ పరిచయాలకు మరియు కాల్ చరిత్రకు ప్రాప్యతను మంజూరు చేస్తుంది."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"జత చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ పరిచయాలకు మరియు కాల్ చరిత్రకు యాక్సెస్ను మంజూరు చేస్తుంది."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో జత చేయడం సాధ్యపడలేదు."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"పిన్ లేదా పాస్కీ చెల్లని కారణంగా <xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో పెయిర్ చేయడం సాధ్యపడలేదు."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో కమ్యూనికేట్ చేయడం సాధ్యపడదు."</string>
@@ -199,7 +199,7 @@
<string name="category_work" msgid="4014193632325996115">"ఆఫీస్"</string>
<string name="development_settings_title" msgid="140296922921597393">"డెవలపర్ ఆప్షన్లు"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"డెవలపర్ ఎంపికలను ప్రారంభించండి"</string>
- <string name="development_settings_summary" msgid="8718917813868735095">"అనువర్తన అభివృద్ధి కోసం ఎంపికలను సెట్ చేయండి"</string>
+ <string name="development_settings_summary" msgid="8718917813868735095">"యాప్ అభివృద్ధి కోసం ఎంపికలను సెట్ చేయండి"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"ఈ వినియోగదారు కోసం డెవలపర్ ఎంపికలు అందుబాటులో లేవు"</string>
<string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN సెట్టింగ్లు ఈ వినియోగదారుకి అందుబాటులో లేవు"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"టీథరింగ్ సెట్టింగ్లు ఈ వినియోగదారుకి అందుబాటులో లేవు"</string>
@@ -227,12 +227,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi పెయిరింగ్ కోడ్"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"పెయిరింగ్ విఫలమైంది"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"పరికరం అదే నెట్వర్క్కు కనెక్ట్ చేయబడి ఉందని నిర్ధారించుకోండి."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR కోడ్ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చెయ్యండి"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR కోడ్ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"పరికరం పెయిర్ చేయబడుతోంది…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"పరికరాన్ని పెయిర్ చేయడం విఫలమైంది. QR కోడ్ తప్పుగా ఉండడం గాని, లేదా పరికరం అదే నెట్వర్క్కు కనెక్ట్ అయి లేకపోవడం గాని జరిగింది."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP అడ్రస్ & పోర్ట్"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR కోడ్ను స్కాన్ చేయండి"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR కోడ్ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చెయ్యండి"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR కోడ్ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"దయచేసి Wi-Fi నెట్వర్క్కు కనెక్ట్ చేయండి"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, డీబగ్, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"బగ్ రిపోర్ట్ షార్ట్కట్"</string>
@@ -271,8 +271,8 @@
<string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"బ్లూటూత్ ఆడియో కోడెక్ని సక్రియం చేయండి\nఎంపిక: ఒక్కో నమూనాలో బిట్లు"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"బ్లూటూత్ ఆడియో ఛానెల్ మోడ్"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="2076949781460359589">"బ్లూటూత్ ఆడియో కోడెక్ని సక్రియం చేయండి\nఎంపిక: ఛానెల్ మోడ్"</string>
- <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"బ్లూటూత్ ఆడియో LDAC కోడెక్: ప్లేబ్యాక్ నాణ్యత"</string>
- <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"బ్లూటూత్ ఆడియో LDAC యాక్టివ్ చేయండి\nకోడెక్ ఎంపిక: ప్లేబ్యాక్ నాణ్యత"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"బ్లూటూత్ ఆడియో LDAC కోడెక్: ప్లేబ్యాక్ క్వాలిటీ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"బ్లూటూత్ ఆడియో LDAC యాక్టివ్ చేయండి\nకోడెక్ ఎంపిక: ప్లేబ్యాక్ క్వాలిటీ"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"ప్రసారం చేస్తోంది: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="7887550926056143018">"ప్రైవేట్ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"ప్రైవేట్ DNS మోడ్ను ఎంచుకోండి"</string>
@@ -304,7 +304,7 @@
<string name="adb_warning_message" msgid="8145270656419669221">"USB డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్ మరియు మీ పరికరం మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్లను ఇన్స్టాల్ చేయడానికి మరియు లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"వైర్లెస్ డీబగ్గింగ్ను అనుమతించాలా?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"వైర్లెస్ డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్, పరికరాల మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్లను ఇన్స్టాల్ చేయడానికి, లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
- <string name="adb_keys_warning_message" msgid="2968555274488101220">"మీరు గతంలో ప్రామాణీకరించిన అన్ని కంప్యూటర్ల నుండి USB డీబగ్గింగ్కు ప్రాప్యతను ఉపసంహరించాలా?"</string>
+ <string name="adb_keys_warning_message" msgid="2968555274488101220">"మీరు గతంలో ప్రామాణీకరించిన అన్ని కంప్యూటర్ల నుండి USB డీబగ్గింగ్కు యాక్సెస్ను ఉపసంహరించాలా?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"అభివృద్ధి సెట్టింగ్లను అనుమతించాలా?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"ఈ సెట్టింగ్లు అభివృద్ధి వినియోగం కోసం మాత్రమే ఉద్దేశించబడినవి. వీటి వలన మీ పరికరం మరియు దీనిలోని యాప్లు విచ్ఛిన్నం కావచ్చు లేదా తప్పుగా ప్రవర్తించవచ్చు."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ద్వారా యాప్లను వెరిఫై చేయి"</string>
@@ -314,7 +314,7 @@
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"బ్లూటూత్ Gabeldorsche ఫీచర్ స్ట్యాక్ను ఎనేబుల్ చేస్తుంది."</string>
<string name="enhanced_connectivity_summary" msgid="1576414159820676330">"మెరుగైన కనెక్టివిటీ ఫీచర్ను ఎనేబుల్ చేస్తుంది."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"స్థానిక టెర్మినల్"</string>
- <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ ప్రాప్యతను అందించే టెర్మినల్ యాప్ను ప్రారంభించు"</string>
+ <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ యాక్సెస్ను అందించే టెర్మినల్ యాప్ను ప్రారంభించు"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP చెకింగ్"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP తనిఖీ ప్రవర్తనను సెట్ చేయండి"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"డీబగ్గింగ్"</string>
@@ -383,7 +383,7 @@
<string name="local_backup_password_title" msgid="4631017948933578709">"డెస్క్టాప్ బ్యాకప్ పాస్వర్డ్"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"డెస్క్టాప్ పూర్తి బ్యాకప్లు ప్రస్తుతం రక్షించబడలేదు"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"డెస్క్టాప్ పూర్తి బ్యాకప్ల కోసం పాస్వర్డ్ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
- <string name="local_backup_password_toast_success" msgid="4891666204428091604">"కొత్త బ్యాకప్ పాస్వర్డ్ను సెట్ చేసారు"</string>
+ <string name="local_backup_password_toast_success" msgid="4891666204428091604">"కొత్త బ్యాకప్ పాస్వర్డ్ను సెట్ చేశారు"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="2994718182129097733">"కొత్త పాస్వర్డ్ మరియు నిర్ధారణ సరిపోలడం లేదు"</string>
<string name="local_backup_password_toast_validation_failure" msgid="714669442363647122">"బ్యాకప్ పాస్వర్డ్ను సెట్ చేయడంలో వైఫల్యం"</string>
<string name="loading_injected_setting_summary" msgid="8394446285689070348">"లోడ్ చేస్తోంది…"</string>
@@ -408,7 +408,7 @@
<string name="transcode_notification" msgid="5560515979793436168">"ట్రాన్స్కోడింగ్ నోటిఫికేషన్లను చూపండి"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ట్రాన్స్కోడింగ్ కాష్ను డిజేబుల్ చేయండి"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సర్వీస్లు"</string>
- <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సర్వీస్లను వీక్షించండి, కంట్రోల్ చేయండి"</string>
+ <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సర్వీస్లను చూడండి, కంట్రోల్ చేయండి"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
<string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
<string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ఈ ఎంపిక ఇప్పుడు లేదు. మళ్లీ ప్రయత్నించండి."</string>
@@ -529,7 +529,7 @@
<string name="help_label" msgid="3528360748637781274">"సహాయం & ఫీడ్బ్యాక్"</string>
<string name="storage_category" msgid="2287342585424631813">"స్టోరేజ్"</string>
<string name="shared_data_title" msgid="1017034836800864953">"షేర్ చేసిన డేటా"</string>
- <string name="shared_data_summary" msgid="5516326713822885652">"షేర్ చేసిన డేటాను చూసి, సవరించండి"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"షేర్ చేసిన డేటాను చూసి, ఎడిట్ చేయండి"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ఈ యూజర్ కోసం షేర్ చేసిన డేటా ఏదీ లేదు."</string>
<string name="shared_data_query_failure_text" msgid="3489828881998773687">"షేర్ చేసిన డేటా పొందడంలో ఎర్రర్ ఏర్పడింది. మళ్లీ ట్రై చేయండి."</string>
<string name="blob_id_text" msgid="8680078988996308061">"షేర్ చేసిన డేటా ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
@@ -542,7 +542,7 @@
<string name="delete_blob_text" msgid="2819192607255625697">"షేర్ చేసిన డేటాను తొలగించు"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"మీరు ఖచ్చితంగా ఈ షేర్ చేసిన డేటాను తొలగించాలనుకుంటున్నారా?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"వినియోగదారులు వారి స్వంత యాప్లను మరియు కంటెంట్ను కలిగి ఉన్నారు"</string>
- <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి యాప్లకు మరియు కంటెంట్కు ప్రాప్యతను పరిమితం చేయవచ్చు"</string>
+ <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి యాప్లకు మరియు కంటెంట్కు యాక్సెస్ను పరిమితం చేయవచ్చు"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"యూజర్"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"పరిమితం చేయబడిన ప్రొఫైల్"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"కొత్త వినియోగదారుని జోడించాలా?"</string>
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index fe48575..3ff1e48 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -317,6 +317,8 @@
NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Global.Wearable.BURN_IN_PROTECTION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Global.Wearable.COMBINED_LOCATION_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Global.Wearable.WRIST_ORIENTATION_MODE,
+ new DiscreteValueValidator(new String[] {"0", "1", "2", "3"}));
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 61df530..4f27de1 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -666,7 +666,8 @@
Settings.Global.Wearable.MASTER_GESTURES_ENABLED,
Settings.Global.Wearable.UNGAZE_ENABLED,
Settings.Global.Wearable.WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS,
- Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED);
+ Settings.Global.Wearable.BURN_IN_PROTECTION_ENABLED,
+ Settings.Global.Wearable.WRIST_ORIENTATION_MODE);
private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
newHashSet(
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index ea769c6..871b1c4 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -62,8 +62,8 @@
<item name="android:src">@drawable/ic_backspace_24dp</item>
</style>
<style name="NumPadKey.Enter">
- <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
- <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
+ <item name="android:colorControlNormal">?android:attr/textColorSecondary</item>
+ <item name="android:src">@drawable/ic_keyboard_tab_36dp</item>
</style>
<style name="Widget.TextView.NumPadKey.Klondike"
parent="@android:style/Widget.DeviceDefault.TextView">
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 5b58fe8..3aa2e5a 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -191,6 +191,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
+ android:id="@+id/wifi_toggle_title"
android:text="@string/turn_on_wifi"
android:textDirection="locale"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a4c1d94..38af659 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -69,6 +69,9 @@
<!-- Shadows under the clock, date and other keyguard text fields -->
<color name="keyguard_shadow_color">#B2000000</color>
+ <!-- Color for the images in keyguard number pad buttons -->
+ <color name="keyguard_keypad_image_color">@android:color/background_light</color>
+
<!-- Color for rounded background for activated user in keyguard user switcher -->
<color name="kg_user_switcher_activated_background_color">#26000000</color>
<!-- Icon color for user avatars in keyguard user switcher -->
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 99f9558..c659bf7 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -26,7 +26,7 @@
import androidx.annotation.Nullable;
-import com.android.settingslib.Utils;
+import com.android.systemui.R;
/**
* Similar to the {@link NumPadKey}, but displays an image.
@@ -92,8 +92,7 @@
public void reloadColors() {
if (mAnimator != null) mAnimator.reloadColors(getContext());
- int textColor = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.colorBackground);
- ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(textColor));
+ int imageColor = getContext().getColor(R.color.keyguard_keypad_image_color);
+ ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index bfa4780..5b327bd 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -34,7 +34,7 @@
* See [DumpHandler] for more information on how and when this information is dumped.
*/
@SysUISingleton
-class DumpManager @Inject constructor() {
+open class DumpManager @Inject constructor() {
private val dumpables: MutableMap<String, RegisteredDumpable<Dumpable>> = ArrayMap()
private val buffers: MutableMap<String, RegisteredDumpable<LogBuffer>> = ArrayMap()
diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
index 28f63b0..6561bd5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
@@ -25,8 +25,12 @@
* Proxy to make {@link SystemProperties} easily testable.
*/
@SysUISingleton
-class SystemPropertiesHelper @Inject constructor() {
+open class SystemPropertiesHelper @Inject constructor() {
fun getBoolean(name: String, default: Boolean): Boolean {
return SystemProperties.getBoolean(name, default)
}
+
+ fun set(name: String, value: Int) {
+ SystemProperties.set(name, value.toString())
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index d0a4b62..cc9e748 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -122,8 +122,9 @@
@Override
protected void handleClick(@Nullable View view) {
- boolean canConfigMobileData = mAccessPointController.canConfigMobileData();
- mHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
+ mHandler.post(() -> mInternetDialogFactory.create(true,
+ mAccessPointController.canConfigMobileData(),
+ mAccessPointController.canConfigWifi()));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index e1e0ba7..7d3734e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -51,7 +51,6 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
-import android.widget.Space;
import android.widget.Switch;
import android.widget.TextView;
@@ -93,6 +92,8 @@
protected View mDialogView;
@VisibleForTesting
protected WifiEntry mConnectedWifiEntry;
+ @VisibleForTesting
+ protected boolean mCanConfigWifi;
private InternetDialogFactory mInternetDialogFactory;
private SubscriptionManager mSubscriptionManager;
@@ -111,6 +112,7 @@
private LinearLayout mMobileNetworkLayout;
private LinearLayout mMobileNetworkList;
private LinearLayout mTurnWifiOnLayout;
+ private TextView mWifiToggleTitleText;
private LinearLayout mSeeAllLayout;
private RecyclerView mWifiRecyclerView;
private ImageView mConnectedWifiIcon;
@@ -151,7 +153,8 @@
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
InternetDialogController internetDialogController, boolean canConfigMobileData,
- boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
+ boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
+ @Main Handler handler) {
super(context, R.style.Theme_SystemUI_Dialog_Internet);
if (DEBUG) {
Log.d(TAG, "Init InternetDialog");
@@ -165,6 +168,7 @@
mTelephonyManager = mInternetDialogController.getTelephonyManager();
mWifiManager = mInternetDialogController.getWifiManager();
mCanConfigMobileData = canConfigMobileData;
+ mCanConfigWifi = canConfigWifi;
mLayoutManager = new LinearLayoutManager(mContext) {
@Override
@@ -215,6 +219,7 @@
mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list);
mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+ mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list);
mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
@@ -247,7 +252,19 @@
if (DEBUG) {
Log.d(TAG, "onStart");
}
- mInternetDialogController.onStart(this);
+ mInternetDialogController.onStart(this, mCanConfigWifi);
+ if (!mCanConfigWifi) {
+ hideWifiViews();
+ }
+ }
+
+ @VisibleForTesting
+ void hideWifiViews() {
+ setProgressBarVisible(false);
+ mTurnWifiOnLayout.setVisibility(View.GONE);
+ mConnectedWifListLayout.setVisibility(View.GONE);
+ mWifiRecyclerView.setVisibility(View.GONE);
+ mSeeAllLayout.setVisibility(View.GONE);
}
@Override
@@ -286,9 +303,13 @@
} else {
mInternetDialogSubTitle.setText(getSubtitleText());
}
- showProgressBar();
setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular());
+ if (!mCanConfigWifi) {
+ return;
+ }
+
+ showProgressBar();
final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
updateWifiToggle(isWifiEnabled, isDeviceLocked);
@@ -368,6 +389,12 @@
private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
mWiFiToggle.setChecked(isWifiEnabled);
+ if (isDeviceLocked && mInternetDialogController.isNightMode()) {
+ int titleColor = mConnectedWifiEntry != null ? mContext.getColor(
+ R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+ mContext, android.R.attr.textColorPrimary);
+ mWifiToggleTitleText.setTextColor(titleColor);
+ }
mTurnWifiOnLayout.setBackground(
(isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
}
@@ -379,8 +406,8 @@
return;
}
mConnectedWifListLayout.setVisibility(View.VISIBLE);
- mConnectedWifiTitleText.setText(mInternetDialogController.getInternetWifiTitle());
- mConnectedWifiSummaryText.setText(mInternetDialogController.getInternetWifiSummary());
+ mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle());
+ mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false));
mConnectedWifiIcon.setImageDrawable(
mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
if (mInternetDialogController.isNightMode()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index ed32730..8838e6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -139,6 +139,8 @@
protected InternetTelephonyCallback mInternetTelephonyCallback;
@VisibleForTesting
protected WifiUtils.InternetIconInjector mWifiIconInjector;
+ @VisibleForTesting
+ protected boolean mCanConfigWifi;
@VisibleForTesting
KeyguardStateController mKeyguardStateController;
@@ -193,7 +195,7 @@
mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext);
}
- void onStart(@NonNull InternetDialogCallback callback) {
+ void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
if (DEBUG) {
Log.d(TAG, "onStart");
}
@@ -217,6 +219,7 @@
mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build(), new DataConnectivityListener(), mHandler);
+ mCanConfigWifi = canConfigWifi;
scanWifiAccessPoints();
}
@@ -270,7 +273,7 @@
return null;
}
- if (!mWifiManager.isWifiEnabled()) {
+ if (mCanConfigWifi && !mWifiManager.isWifiEnabled()) {
// When the airplane mode is off and Wi-Fi is disabled.
// Sub-Title: Wi-Fi is off
if (DEBUG) {
@@ -290,10 +293,10 @@
final List<ScanResult> wifiList = mWifiManager.getScanResults();
if (wifiList != null && wifiList.size() != 0) {
- return mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT);
+ return mCanConfigWifi ? mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT) : null;
}
- if (isProgressBarVisible) {
+ if (mCanConfigWifi && isProgressBarVisible) {
// When the Wi-Fi scan result callback is received
// Sub-Title: Searching for networks...
return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS);
@@ -317,7 +320,7 @@
return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
}
- if (!isMobileDataEnabled()) {
+ if (mCanConfigWifi && !isMobileDataEnabled()) {
if (DEBUG) {
Log.d(TAG, "Mobile data off");
}
@@ -331,7 +334,10 @@
return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
}
- return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+ if (mCanConfigWifi) {
+ return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+ }
+ return null;
}
Drawable getInternetWifiDrawable(@NonNull WifiEntry wifiEntry) {
@@ -549,26 +555,6 @@
return summary;
}
- String getInternetWifiTitle() {
- if (getInternetWifiEntry() == null) {
- if (DEBUG) {
- Log.d(TAG, "connected entry is null");
- }
- return "";
- }
- return getInternetWifiEntry().getTitle();
- }
-
- String getInternetWifiSummary() {
- if (getInternetWifiEntry() == null) {
- if (DEBUG) {
- Log.d(TAG, "connected entry is null");
- }
- return "";
- }
- return getInternetWifiEntry().getSummary(false);
- }
-
void launchNetworkSetting() {
mCallback.dismissDialog();
mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0);
@@ -780,12 +766,14 @@
}
void scanWifiAccessPoints() {
- mAccessPointController.scanForAccessPoints();
+ if (mCanConfigWifi) {
+ mAccessPointController.scanForAccessPoints();
+ }
}
@Override
public void onAccessPointsChanged(List<WifiEntry> accessPoints) {
- if (accessPoints == null) {
+ if (accessPoints == null || !mCanConfigWifi) {
return;
}
@@ -869,8 +857,8 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)
- || action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ if (mCanConfigWifi && (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)
+ || action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))) {
mCallback.onWifiStateReceived(context, intent);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
index e82e89ef1..11c6980 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -31,17 +31,17 @@
*/
@SysUISingleton
class InternetDialogFactory @Inject constructor(
- @Main private val handler: Handler,
- private val internetDialogController: InternetDialogController,
- private val context: Context,
- private val uiEventLogger: UiEventLogger
+ @Main private val handler: Handler,
+ private val internetDialogController: InternetDialogController,
+ private val context: Context,
+ private val uiEventLogger: UiEventLogger
) {
companion object {
var internetDialog: InternetDialog? = null
}
/** Creates a [InternetDialog]. */
- fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean) {
+ fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean, canConfigWifi: Boolean) {
if (internetDialog != null) {
if (DEBUG) {
Log.d(TAG, "InternetDialog is showing, do not create it twice.")
@@ -49,7 +49,7 @@
return
} else {
internetDialog = InternetDialog(context, this, internetDialogController,
- canConfigMobileData, aboveStatusBar, uiEventLogger, handler)
+ canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler)
internetDialog?.show()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 9bba7ef..1cc1dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -280,7 +280,8 @@
@VisibleForTesting
fun launchSettings(sender: View) {
- onSettingsClickListener?.onClick(sender, null, appUid!!)
+ val channel = if (providedChannels.size == 1) providedChannels[0] else null
+ onSettingsClickListener?.onClick(sender, channel, appUid!!)
}
private fun initDialog() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d6ac6d1..65e691f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -793,8 +793,8 @@
mReceiverHandler.post(this::handleConfigurationChanged);
break;
case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
- boolean canConfigMobileData = mAccessPoints.canConfigMobileData();
- mMainHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
+ mMainHandler.post(() -> mInternetDialogFactory.create(true,
+ mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi()));
break;
default:
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index cfd82f5..377a7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -535,6 +535,10 @@
mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
managedProfiles);
}
+ onOverlaysApplied();
+ }
+
+ protected void onOverlaysApplied() {
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 830fe5a..a57d439 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -10,6 +10,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -100,6 +101,7 @@
when(mKeyguardStateController.isUnlocked()).thenReturn(true);
when(mConnectedEntry.isDefaultNetwork()).thenReturn(true);
when(mConnectedEntry.hasInternetAccess()).thenReturn(true);
+ when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID});
mInternetDialogController = new MockInternetDialogController(mContext,
mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
@@ -109,7 +111,7 @@
mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
mInternetDialogController.mOnSubscriptionsChangedListener);
mInternetDialogController.onStart(
- mock(InternetDialogController.InternetDialogCallback.class));
+ mock(InternetDialogController.InternetDialogCallback.class), true);
mInternetDialogController.mActivityStarter = mActivityStarter;
mInternetDialogController.mConnectedEntry = mConnectedEntry;
mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
@@ -143,8 +145,14 @@
mInternetDialogController.setAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(false);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
- getResourcesString("wifi_is_off")));
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isEqualTo(getResourcesString("wifi_is_off"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isNotEqualTo(getResourcesString("wifi_is_off"));
}
@Test
@@ -155,8 +163,14 @@
doReturn(0).when(wifiScanResults).size();
when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(true),
- getResourcesString("wifi_empty_list_wifi_on")));
+ assertThat(mInternetDialogController.getSubtitleText(true))
+ .isEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(true))
+ .isNotEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
}
@Test
@@ -167,8 +181,14 @@
doReturn(1).when(wifiScanResults).size();
when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
- getResourcesString("tap_a_network_to_connect")));
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isEqualTo(getResourcesString("tap_a_network_to_connect"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isNotEqualTo(getResourcesString("tap_a_network_to_connect"));
}
@Test
@@ -188,8 +208,6 @@
List<ScanResult> wifiScanResults = new ArrayList<>();
doReturn(wifiScanResults).when(mWifiManager).getScanResults();
when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
- when(mSubscriptionManager.getActiveSubscriptionIdList())
- .thenReturn(new int[] {SUB_ID});
doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState();
doReturn(mServiceState).when(mTelephonyManager).getServiceState();
@@ -206,16 +224,20 @@
List<ScanResult> wifiScanResults = new ArrayList<>();
doReturn(wifiScanResults).when(mWifiManager).getScanResults();
when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
- when(mSubscriptionManager.getActiveSubscriptionIdList())
- .thenReturn(new int[] {SUB_ID});
doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
doReturn(mServiceState).when(mTelephonyManager).getServiceState();
when(mTelephonyManager.isDataEnabled()).thenReturn(false);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
- getResourcesString("non_carrier_network_unavailable")));
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isEqualTo(getResourcesString("non_carrier_network_unavailable"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isNotEqualTo(getResourcesString("non_carrier_network_unavailable"));
}
@Test
@@ -248,36 +270,6 @@
}
@Test
- public void getInternetWifiTitle_withNoConnectedWifiEntry_returnEmpty() {
- mInternetDialogController.mConnectedEntry = null;
-
- assertThat(mInternetDialogController.getInternetWifiTitle()).isEmpty();
- }
-
- @Test
- public void getInternetWifiTitle_withInternetWifi_returnTitle() {
- // The preconditions have been set in setUp().
- // - The connected Wi-Fi entry have both default network and internet access conditions.
- when(mConnectedEntry.getTitle()).thenReturn(CONNECTED_TITLE);
-
- assertThat(mInternetDialogController.getInternetWifiTitle()).isEqualTo(CONNECTED_TITLE);
- }
-
- @Test
- public void getInternetWifiSummary_withNoConnectedWifiEntry_returnEmpty() {
- mInternetDialogController.mConnectedEntry = null;
-
- assertThat(mInternetDialogController.getInternetWifiSummary()).isEmpty();
- }
-
- @Test
- public void getInternetWifiSummary_withInternetWifi_returnSummary() {
- when(mConnectedEntry.getSummary(false)).thenReturn(CONNECTED_SUMMARY);
-
- assertThat(mInternetDialogController.getInternetWifiSummary()).isEqualTo(CONNECTED_SUMMARY);
- }
-
- @Test
public void getWifiDetailsSettingsIntent_withNoConnectedEntry_returnNull() {
mInternetDialogController.mConnectedEntry = null;
@@ -342,6 +334,16 @@
assertThat(mInternetDialogController.isDeviceLocked()).isTrue();
}
+ @Test
+ public void scanWifiAccessPoints_cannotConfigWifi_doNothing() {
+ reset(mAccessPointController);
+ mInternetDialogController.mCanConfigWifi = false;
+
+ mInternetDialogController.scanWifiAccessPoints();
+
+ verify(mAccessPointController, never()).scanForAccessPoints();
+ }
+
private String getResourcesString(String name) {
return mContext.getResources().getString(getResourcesId(name));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index 5a018f4..87e81e40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -20,7 +20,6 @@
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
-import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.filters.SmallTest;
@@ -69,6 +68,9 @@
private InternetDialogController mInternetDialogController;
private InternetDialog mInternetDialog;
+ private View mDialogView;
+ private View mSubTitle;
+ private LinearLayout mMobileDataToggle;
private LinearLayout mWifiToggle;
private LinearLayout mConnectedWifi;
private RecyclerView mWifiList;
@@ -94,15 +96,18 @@
when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
- mInternetDialogController, true, true, mock(UiEventLogger.class), mHandler);
+ mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler);
mInternetDialog.mAdapter = mInternetAdapter;
mInternetDialog.mConnectedWifiEntry = mInternetWifiEntry;
mInternetDialog.show();
- mWifiToggle = mInternetDialog.mDialogView.requireViewById(R.id.turn_on_wifi_layout);
- mConnectedWifi = mInternetDialog.mDialogView.requireViewById(R.id.wifi_connected_layout);
- mWifiList = mInternetDialog.mDialogView.requireViewById(R.id.wifi_list_layout);
- mSeeAll = mInternetDialog.mDialogView.requireViewById(R.id.see_all_layout);
+ mDialogView = mInternetDialog.mDialogView;
+ mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+ mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_network_layout);
+ mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+ mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
+ mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
+ mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
}
@After
@@ -111,33 +116,41 @@
}
@Test
+ public void hideWifiViews_WifiViewsGone() {
+ mInternetDialog.hideWifiViews();
+
+ assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+ assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
public void updateDialog_withApmOn_internetDialogSubTitleGone() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- mInternetDialog.updateDialog();
- final TextView view = mInternetDialog.mDialogView.requireViewById(
- R.id.internet_dialog_subtitle);
- assertThat(view.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialog.updateDialog();
+
+ assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
- mInternetDialog.updateDialog();
- final TextView view = mInternetDialog.mDialogView.requireViewById(
- R.id.internet_dialog_subtitle);
- assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialog.updateDialog();
+
+ assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void updateDialog_withApmOn_mobileDataLayoutGone() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- mInternetDialog.updateDialog();
- final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
- R.id.mobile_network_layout);
- assertThat(linearLayout.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialog.updateDialog();
+
+ assertThat(mMobileDataToggle.getVisibility()).isEqualTo(View.GONE);
}
@Test
diff --git a/services/core/java/com/android/server/PermissionThread.java b/services/core/java/com/android/server/PermissionThread.java
deleted file mode 100644
index cf444fa..0000000
--- a/services/core/java/com/android/server/PermissionThread.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2021 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.server;
-
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.Looper;
-import android.os.Trace;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.ServiceThread;
-
-import java.util.concurrent.Executor;
-
-/**
- * Shared singleton thread for the system. This is a thread for handling
- * calls to and from the PermissionController and handling synchronization
- * between permissions and appops states.
- */
-public final class PermissionThread extends ServiceThread {
- private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
- private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
-
- private static final Object sLock = new Object();
-
- @GuardedBy("sLock")
- private static PermissionThread sInstance;
- private static Handler sHandler;
- private static HandlerExecutor sHandlerExecutor;
-
- private PermissionThread() {
- super("android.perm", android.os.Process.THREAD_PRIORITY_DEFAULT, /* allowIo= */ true);
- }
-
- private static void ensureThreadLocked() {
- if (sInstance != null) {
- return;
- }
-
- sInstance = new PermissionThread();
- sInstance.start();
- final Looper looper = sInstance.getLooper();
- looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
- looper.setSlowLogThresholdMs(
- SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
- sHandler = new Handler(sInstance.getLooper());
- sHandlerExecutor = new HandlerExecutor(sHandler);
- }
-
- public static PermissionThread get() {
- synchronized (sLock) {
- ensureThreadLocked();
- return sInstance;
- }
- }
-
- public static Handler getHandler() {
- synchronized (sLock) {
- ensureThreadLocked();
- return sHandler;
- }
- }
-
- public static Executor getExecutor() {
- synchronized (sLock) {
- ensureThreadLocked();
- return sHandlerExecutor;
- }
- }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 317775f2..e4c0765 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -329,16 +329,25 @@
};
/**
- * Watch for apps being put into forced app standby, so we can step their fg
+ * Reference to the AppStateTracker service. No lock is needed as we'll assign with the same
+ * instance to it always.
+ */
+ AppStateTracker mAppStateTracker;
+
+ /**
+ * Watch for apps being put into background restricted, so we can step their fg
* services down.
*/
- class ForcedStandbyListener implements AppStateTracker.ServiceStateListener {
+ class BackgroundRestrictedListener implements AppStateTracker.BackgroundRestrictedAppListener {
@Override
- public void stopForegroundServicesForUidPackage(final int uid, final String packageName) {
+ public void updateBackgroundRestrictedForUidPackage(int uid, String packageName,
+ boolean restricted) {
synchronized (mAm) {
if (!isForegroundServiceAllowedInBackgroundRestricted(uid, packageName)) {
stopAllForegroundServicesLocked(uid, packageName);
}
+ mAm.mProcessList.updateBackgroundRestrictedForUidPackageLocked(
+ uid, packageName, restricted);
}
}
}
@@ -523,12 +532,18 @@
}
void systemServicesReady() {
- AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
- ast.addServiceStateListener(new ForcedStandbyListener());
+ getAppStateTracker().addBackgroundRestrictedAppListener(new BackgroundRestrictedListener());
mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
setAllowListWhileInUsePermissionInFgs();
}
+ private AppStateTracker getAppStateTracker() {
+ if (mAppStateTracker == null) {
+ mAppStateTracker = LocalServices.getService(AppStateTracker.class);
+ }
+ return mAppStateTracker;
+ }
+
private void setAllowListWhileInUsePermissionInFgs() {
final String attentionServicePackageName =
mAm.mContext.getPackageManager().getAttentionServicePackageName();
@@ -607,9 +622,11 @@
}
private boolean appRestrictedAnyInBackground(final int uid, final String packageName) {
- final int mode = mAm.getAppOpsManager().checkOpNoThrow(
- AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName);
- return (mode != AppOpsManager.MODE_ALLOWED);
+ final AppStateTracker appStateTracker = getAppStateTracker();
+ if (appStateTracker != null) {
+ return appStateTracker.isAppBackgroundRestricted(uid, packageName);
+ }
+ return false;
}
void updateAppRestrictedAnyInBackgroundLocked(final int uid, final String packageName) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 9a755da..048a787 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -56,7 +56,8 @@
private static final String TAG = "ActivityManagerConstants";
// Key names stored in the settings value.
- private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
+ static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
+
private static final String KEY_FGSERVICE_MIN_SHOWN_TIME
= "fgservice_min_shown_time";
private static final String KEY_FGSERVICE_MIN_REPORT_TIME
@@ -119,9 +120,11 @@
"extra_delay_svc_restart_mem_pressure";
static final String KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE =
"enable_extra_delay_svc_restart_mem_pressure";
+ static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
+ static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
+ "kill_bg_restricted_cached_idle_settle_time";
private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
- private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000;
@@ -164,6 +167,11 @@
private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
private static final float DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE = 1; // 100%
+
+ static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
+ static final long DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS = 60 * 1000;
+ static final boolean DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE = true;
+
/**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
@@ -541,6 +549,19 @@
volatile float mFgsStartDeniedLogSampleRate = DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE;
/**
+ * Whether or not to kill apps in background restricted mode and it's cached, its UID state is
+ * idle.
+ */
+ volatile boolean mKillBgRestrictedAndCachedIdle = DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE;
+
+ /**
+ * The amount of time we allow an app in background restricted mode to settle after it goes
+ * into the cached & UID idle, before we decide to kill it.
+ */
+ volatile long mKillBgRestrictedAndCachedIdleSettleTimeMs =
+ DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS;
+
+ /**
* Whether to allow "opt-out" from the foreground service restrictions.
* (https://developer.android.com/about/versions/12/foreground-services)
*/
@@ -776,6 +797,12 @@
case KEY_FGS_START_DENIED_LOG_SAMPLE_RATE:
updateFgsStartDeniedLogSamplePercent();
break;
+ case KEY_KILL_BG_RESTRICTED_CACHED_IDLE:
+ updateKillBgRestrictedCachedIdle();
+ break;
+ case KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME:
+ updateKillBgRestrictedCachedIdleSettleTime();
+ break;
case KEY_FGS_ALLOW_OPT_OUT:
updateFgsAllowOptOut();
break;
@@ -1142,6 +1169,28 @@
DEFAULT_FGS_START_DENIED_LOG_SAMPLE_RATE);
}
+ private void updateKillBgRestrictedCachedIdle() {
+ mKillBgRestrictedAndCachedIdle = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_KILL_BG_RESTRICTED_CACHED_IDLE,
+ DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE);
+ }
+
+ private void updateKillBgRestrictedCachedIdleSettleTime() {
+ final long currentSettleTime = mKillBgRestrictedAndCachedIdleSettleTimeMs;
+ mKillBgRestrictedAndCachedIdleSettleTimeMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME,
+ DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS);
+ if (mKillBgRestrictedAndCachedIdleSettleTimeMs != currentSettleTime) {
+ mService.mHandler.removeMessages(
+ ActivityManagerService.IDLE_UIDS_MSG);
+ mService.mHandler.sendEmptyMessageDelayed(
+ ActivityManagerService.IDLE_UIDS_MSG,
+ mKillBgRestrictedAndCachedIdleSettleTimeMs);
+ }
+ }
+
private void updateFgsAllowOptOut() {
mFgsAllowOptOut = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70ceb92..7fc35d4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1832,18 +1832,6 @@
}
});
- mAppOpsService.startWatchingMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, null,
- new IAppOpsCallback.Stub() {
- @Override public void opChanged(int op, int uid, String packageName) {
- if (op == AppOpsManager.OP_RUN_ANY_IN_BACKGROUND && packageName != null) {
- synchronized (ActivityManagerService.this) {
- mServices.updateAppRestrictedAnyInBackgroundLocked(
- uid, packageName);
- }
- }
- }
- });
-
final int[] cameraOp = {AppOpsManager.OP_CAMERA};
mAppOpsService.startWatchingActive(cameraOp, new IAppOpsActiveCallback.Stub() {
@Override
@@ -9495,6 +9483,15 @@
TimeUtils.dumpTimeWithDelta(pw, expirationInCurrentTime, currentTimeNow);
pw.println();
});
+
+ if (!mProcessList.mAppsInBackgroundRestricted.isEmpty()) {
+ pw.println(" Processes that are in background restricted:");
+ for (int i = 0, size = mProcessList.mAppsInBackgroundRestricted.size();
+ i < size; i++) {
+ pw.println(String.format("%s #%2d: %s", " ", i,
+ mProcessList.mAppsInBackgroundRestricted.valueAt(i).toString()));
+ }
+ }
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
@@ -14441,6 +14438,10 @@
final int capability = uidRec != null ? uidRec.getSetCapability() : 0;
final boolean ephemeral = uidRec != null ? uidRec.isEphemeral() : isEphemeralLocked(uid);
+ if (uidRec != null && uidRec.isIdle() && (change & UidRecord.CHANGE_IDLE) != 0) {
+ mProcessList.killAppIfBgRestrictedAndCachedIdleLocked(uidRec);
+ }
+
if (uidRec != null && !uidRec.isIdle() && (change & UidRecord.CHANGE_GONE) != 0) {
// If this uid is going away, and we haven't yet reported it is gone,
// then do so now.
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 27d8119..e94276c 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1564,6 +1564,7 @@
state.resetAllowStartFgsState();
if (!cycleReEval) {
// Don't reset this flag when doing cycles re-evaluation.
+ state.setNoKillOnBgRestrictedAndIdle(false);
app.mOptRecord.setShouldNotFreeze(false);
}
@@ -2900,6 +2901,23 @@
+ " target=" + state.getAdjTarget() + " capability=" + item.capability);
}
+ if (state.isCached() && !state.shouldNotKillOnBgRestrictedAndIdle()) {
+ // It's eligible to get killed when in UID idle and bg restricted mode,
+ // check if these states are just flipped.
+ if (!state.isSetCached() || state.isSetNoKillOnBgRestrictedAndIdle()) {
+ // Take the timestamp, we'd hold the killing for the background settle time
+ // (for states debouncing to avoid from thrashing).
+ state.setLastCanKillOnBgRestrictedAndIdleTime(nowElapsed);
+ // Kick off the delayed checkup message if needed.
+ if (!mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+ mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+ mConstants.mKillBgRestrictedAndCachedIdleSettleTimeMs);
+ }
+ }
+ }
+ state.setSetCached(state.isCached());
+ state.setSetNoKillOnBgRestrictedAndIdle(state.shouldNotKillOnBgRestrictedAndIdle());
+
return success;
}
@@ -3048,6 +3066,20 @@
if (mLocalPowerManager != null) {
mLocalPowerManager.finishUidChanges();
}
+ // Also check if there are any apps in cached and background restricted mode,
+ // if so, kill it if it's been there long enough, or kick off a msg to check
+ // it later.
+ if (mService.mConstants.mKillBgRestrictedAndCachedIdle) {
+ final ArraySet<ProcessRecord> apps = mProcessList.mAppsInBackgroundRestricted;
+ for (int i = 0, size = apps.size(); i < size; i++) {
+ // Check to see if needs to be killed.
+ final long bgTime = mProcessList.killAppIfBgRestrictedAndCachedIdleLocked(
+ apps.valueAt(i), nowElapsed) - mConstants.BACKGROUND_SETTLE_TIME;
+ if (bgTime > 0 && (nextTime == 0 || nextTime > bgTime)) {
+ nextTime = bgTime;
+ }
+ }
+ }
if (nextTime > 0) {
mService.mHandler.removeMessages(IDLE_UIDS_MSG);
mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a97738f..07d9cb2 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -42,6 +42,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESS_DIED_UI_MSG;
+import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_DELAY_MS;
import static com.android.server.am.ActivityManagerService.KILL_APP_ZYGOTE_MSG;
import static com.android.server.am.ActivityManagerService.PERSISTENT_MASK;
@@ -126,6 +127,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.MemInfoReader;
+import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
@@ -544,6 +546,12 @@
final ArrayMap<AppZygote, ArrayList<ProcessRecord>> mAppZygoteProcesses =
new ArrayMap<AppZygote, ArrayList<ProcessRecord>>();
+ /**
+ * The list of apps in background restricted mode.
+ */
+ @GuardedBy("mService")
+ final ArraySet<ProcessRecord> mAppsInBackgroundRestricted = new ArraySet<>();
+
private PlatformCompat mPlatformCompat = null;
/**
@@ -2370,6 +2378,16 @@
allowlistedAppDataInfoMap = null;
}
+ AppStateTracker ast = mService.mServices.mAppStateTracker;
+ if (ast != null) {
+ final boolean inBgRestricted = ast.isAppBackgroundRestricted(
+ app.info.uid, app.info.packageName);
+ if (inBgRestricted) {
+ mAppsInBackgroundRestricted.add(app);
+ }
+ app.mState.setBackgroundRestricted(inBgRestricted);
+ }
+
final Process.ProcessStartResult startResult;
boolean regularZygote = false;
if (hostingRecord.usesWebviewZygote()) {
@@ -3104,6 +3122,7 @@
if (record != null && record.appZygote) {
removeProcessFromAppZygoteLocked(record);
}
+ mAppsInBackgroundRestricted.remove(record);
return old;
}
@@ -5019,6 +5038,75 @@
return true;
}
+ @GuardedBy("mService")
+ void updateBackgroundRestrictedForUidPackageLocked(int uid, String packageName,
+ boolean restricted) {
+ final UidRecord uidRec = getUidRecordLOSP(uid);
+ if (uidRec != null) {
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ uidRec.forEachProcess(app -> {
+ if (TextUtils.equals(app.info.packageName, packageName)) {
+ app.mState.setBackgroundRestricted(restricted);
+ if (restricted) {
+ mAppsInBackgroundRestricted.add(app);
+ final long future = killAppIfBgRestrictedAndCachedIdleLocked(
+ app, nowElapsed);
+ if (future > 0 && !mService.mHandler.hasMessages(IDLE_UIDS_MSG)) {
+ mService.mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+ future - nowElapsed);
+ }
+ } else {
+ mAppsInBackgroundRestricted.remove(app);
+ }
+ if (!app.isKilledByAm()) {
+ mService.enqueueOomAdjTargetLocked(app);
+ }
+ }
+ });
+ /* Will be a no-op if nothing pending */
+ mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
+ }
+ }
+
+ /**
+ * Kill the given app if it's in cached idle and background restricted mode.
+ *
+ * @return A future timestamp when the app should be killed at, or a 0 if it shouldn't
+ * be killed or it has been killed.
+ */
+ @GuardedBy("mService")
+ long killAppIfBgRestrictedAndCachedIdleLocked(ProcessRecord app, long nowElapsed) {
+ final UidRecord uidRec = app.getUidRecord();
+ final long lastCanKillTime = app.mState.getLastCanKillOnBgRestrictedAndIdleTime();
+ if (!mService.mConstants.mKillBgRestrictedAndCachedIdle
+ || app.isKilled() || app.getThread() == null || uidRec == null || !uidRec.isIdle()
+ || !app.isCached() || app.mState.shouldNotKillOnBgRestrictedAndIdle()
+ || !app.mState.isBackgroundRestricted() || lastCanKillTime == 0) {
+ return 0;
+ }
+ final long future = lastCanKillTime
+ + mService.mConstants.mKillBgRestrictedAndCachedIdleSettleTimeMs;
+ if (future <= nowElapsed) {
+ app.killLocked("cached idle & background restricted",
+ ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY,
+ true);
+ return 0;
+ }
+ return future;
+ }
+
+ /**
+ * Called by {@link ActivityManagerService#enqueueUidChangeLocked} only, it doesn't schedule
+ * the standy killing checks because it should have been scheduled before enqueueing UID idle
+ * changed.
+ */
+ @GuardedBy("mService")
+ void killAppIfBgRestrictedAndCachedIdleLocked(UidRecord uidRec) {
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ uidRec.forEachProcess(app -> killAppIfBgRestrictedAndCachedIdleLocked(app, nowElapsed));
+ }
+
/**
* Called by ActivityManagerService when a process died.
*/
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 85d06c3..46144f5 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -374,6 +374,34 @@
@ElapsedRealtimeLong
private long mLastInvisibleTime;
+ /**
+ * Whether or not this process could be killed when it's in background restricted mode
+ * and cached & idle state.
+ */
+ @GuardedBy("mService")
+ private boolean mNoKillOnBgRestrictedAndIdle;
+
+ /**
+ * Last set value of {@link #mCached}.
+ */
+ @GuardedBy("mService")
+ private boolean mSetCached;
+
+ /**
+ * Last set value of {@link #mNoKillOnBgRestrictedAndIdle}.
+ */
+ @GuardedBy("mService")
+ private boolean mSetNoKillOnBgRestrictedAndIdle;
+
+ /**
+ * The last time when the {@link #mNoKillOnBgRestrictedAndIdle} is false and the
+ * {@link #mCached} is true, and either the former state is flipping from true to false
+ * when latter state is true, or the latter state is flipping from false to true when the
+ * former state is false.
+ */
+ @GuardedBy("mService")
+ private @ElapsedRealtimeLong long mLastCanKillOnBgRestrictedAndIdleTime;
+
// Below are the cached task info for OomAdjuster only
private static final int VALUE_INVALID = -1;
private static final int VALUE_FALSE = 0;
@@ -1174,6 +1202,47 @@
return mLastInvisibleTime;
}
+ @GuardedBy("mService")
+ void setNoKillOnBgRestrictedAndIdle(boolean shouldNotKill) {
+ mNoKillOnBgRestrictedAndIdle = shouldNotKill;
+ }
+
+ @GuardedBy("mService")
+ boolean shouldNotKillOnBgRestrictedAndIdle() {
+ return mNoKillOnBgRestrictedAndIdle;
+ }
+
+ @GuardedBy("mService")
+ void setSetCached(boolean cached) {
+ mSetCached = cached;
+ }
+
+ @GuardedBy("mService")
+ boolean isSetCached() {
+ return mSetCached;
+ }
+
+ @GuardedBy("mService")
+ void setSetNoKillOnBgRestrictedAndIdle(boolean shouldNotKill) {
+ mSetNoKillOnBgRestrictedAndIdle = shouldNotKill;
+ }
+
+ @GuardedBy("mService")
+ boolean isSetNoKillOnBgRestrictedAndIdle() {
+ return mSetNoKillOnBgRestrictedAndIdle;
+ }
+
+ @GuardedBy("mService")
+ void setLastCanKillOnBgRestrictedAndIdleTime(@ElapsedRealtimeLong long now) {
+ mLastCanKillOnBgRestrictedAndIdleTime = now;
+ }
+
+ @ElapsedRealtimeLong
+ @GuardedBy("mService")
+ long getLastCanKillOnBgRestrictedAndIdleTime() {
+ return mLastCanKillOnBgRestrictedAndIdleTime;
+ }
+
@GuardedBy({"mService", "mProcLock"})
void dump(PrintWriter pw, String prefix, long nowUptime) {
if (mReportedInteraction || mFgInteractionTime != 0) {
diff --git a/services/core/java/com/android/server/pm/PackageInstalledInfo.java b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
index afe6bb2..d0ca9d84 100644
--- a/services/core/java/com/android/server/pm/PackageInstalledInfo.java
+++ b/services/core/java/com/android/server/pm/PackageInstalledInfo.java
@@ -18,7 +18,6 @@
import static com.android.server.pm.PackageManagerService.TAG;
-import android.content.pm.PackageParser;
import android.util.ExceptionUtils;
import android.util.Slog;
@@ -59,12 +58,6 @@
Slog.w(TAG, msg);
}
- public void setError(String msg, PackageParser.PackageParserException e) {
- setReturnCode(e.error);
- setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
- Slog.w(TAG, msg, e);
- }
-
public void setError(String msg, PackageManagerException e) {
mReturnCode = e.error;
setReturnMessage(ExceptionUtils.getCompleteMessage(msg, e));
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 8a8a302..4334bf6 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -21,7 +21,7 @@
import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-import android.content.pm.PackageParser;
+import android.content.pm.parsing.ParsingPackage;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -82,7 +82,7 @@
boolean hasClass = false;
String className = "android.content.pm.AndroidTestBaseUpdater";
try {
- Class clazz = (PackageParser.class.getClassLoader().loadClass(className));
+ Class clazz = ParsingPackage.class.getClassLoader().loadClass(className);
hasClass = clazz != null;
Log.i(TAG, "Loaded " + className);
} catch (ClassNotFoundException e) {
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index dd50b0c..4bbe373 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -33,7 +33,6 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.server.PermissionThread;
/**
* Class that handles one-time permissions for a user
@@ -80,8 +79,7 @@
mContext = context;
mActivityManager = context.getSystemService(ActivityManager.class);
mAlarmManager = context.getSystemService(AlarmManager.class);
- mPermissionControllerManager = new PermissionControllerManager(
- mContext, PermissionThread.getHandler());
+ mPermissionControllerManager = context.getSystemService(PermissionControllerManager.class);
mHandler = context.getMainThreadHandler();
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 919ed5f..cd03351 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -145,7 +145,6 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.PermissionThread;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
@@ -2057,7 +2056,7 @@
private byte[] backupRuntimePermissions(@UserIdInt int userId) {
CompletableFuture<byte[]> backup = new CompletableFuture<>();
mPermissionControllerManager.getRuntimePermissionBackup(UserHandle.of(userId),
- PermissionThread.getExecutor(), backup::complete);
+ mContext.getMainExecutor(), backup::complete);
try {
return backup.get(BACKUP_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
@@ -2102,7 +2101,7 @@
}
}
mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName,
- UserHandle.of(userId), PermissionThread.getExecutor(), (hasMoreBackup) -> {
+ UserHandle.of(userId), mContext.getMainExecutor(), (hasMoreBackup) -> {
if (hasMoreBackup) {
return;
}
@@ -4551,8 +4550,7 @@
}
}
- mPermissionControllerManager = new PermissionControllerManager(
- mContext, PermissionThread.getHandler());
+ mPermissionControllerManager = mContext.getSystemService(PermissionControllerManager.class);
mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
}
diff --git a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
index bdcd2cd..3524d7f 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldDurationLogger.java
@@ -44,8 +44,8 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ScreenState {}
- private @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
- private Long mLastChanged = null;
+ private volatile @ScreenState int mScreenState = SCREEN_STATE_UNKNOWN;
+ private volatile Long mLastChanged = null;
private static final int LOG_SUBTYPE_UNFOLDED = 0;
private static final int LOG_SUBTYPE_FOLDED = 1;
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 2709d4f..ad43514 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -64,8 +64,8 @@
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.PermissionThread;
import com.android.server.SystemService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -279,7 +279,7 @@
PermissionControllerManager manager = mPermControllerManagers.get(user);
if (manager == null) {
manager = new PermissionControllerManager(
- getUserContext(getContext(), user), PermissionThread.getHandler());
+ getUserContext(getContext(), user), FgThread.getHandler());
mPermControllerManagers.put(user, manager);
}
manager.updateUserSensitiveForApp(uid);
@@ -287,9 +287,8 @@
}, UserHandle.ALL, intentFilter, null, null);
PermissionControllerManager manager = new PermissionControllerManager(
- getUserContext(getContext(), Process.myUserHandle()),
- PermissionThread.getHandler());
- PermissionThread.getHandler().postDelayed(manager::updateUserSensitive,
+ getUserContext(getContext(), Process.myUserHandle()), FgThread.getHandler());
+ FgThread.getHandler().postDelayed(manager::updateUserSensitive,
USER_SENSITIVE_UPDATE_DELAY_MS);
}
@@ -316,7 +315,7 @@
if (isStarted(changedUserId)) {
synchronized (mLock) {
if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
- PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService
::synchronizePackagePermissionsAndAppOpsForUser,
this, packageName, changedUserId));
@@ -422,9 +421,9 @@
final PermissionControllerManager permissionControllerManager =
new PermissionControllerManager(
getUserContext(getContext(), UserHandle.of(userId)),
- PermissionThread.getHandler());
+ FgThread.getHandler());
permissionControllerManager.grantOrUpgradeDefaultRuntimePermissions(
- PermissionThread.getExecutor(), successful -> {
+ FgThread.getExecutor(), successful -> {
if (successful) {
future.complete(null);
} else {
@@ -528,7 +527,7 @@
synchronized (mLock) {
if (!mIsUidSyncScheduled.get(uid)) {
mIsUidSyncScheduled.put(uid, true);
- PermissionThread.getHandler().sendMessage(PooledLambda.obtainMessage(
+ FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService::resetAppOpPermissionsIfNotRequestedForUid,
this, uid));
}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 2a95416..06253a0 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -124,12 +124,8 @@
@Override
public void read(InputStream in) throws IOException {
while (in.available() > 0) {
- try {
- DataElement dataElement = new DataElement(in);
- mCallback.onReadDataElement(dataElement.getData());
- } catch (IOException e) {
- Slog.e(TAG, "Failed to read from storage. " + e.getMessage());
- }
+ DataElement dataElement = new DataElement(in);
+ mCallback.onReadDataElement(dataElement.getData());
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3a5d771..ed2c3b6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8644,8 +8644,9 @@
if (imeTargetWindowTask == null) {
return false;
}
- final TaskSnapshot snapshot = mAtmService.getTaskSnapshot(imeTargetWindowTask.mTaskId,
- false /* isLowResolution */);
+ final TaskSnapshot snapshot = getTaskSnapshot(imeTargetWindowTask.mTaskId,
+ imeTargetWindowTask.mUserId, false /* isLowResolution */,
+ false /* restoreFromDisk */);
return snapshot != null && snapshot.hasImeSurface();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6a25965..e38d8dc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3804,17 +3804,6 @@
}
}
- @Override
- public boolean isSeparateProfileChallengeAllowed(int userHandle) {
- Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()),
- String.format(NOT_SYSTEM_CALLER_MSG, "query separate challenge support"));
-
- ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
- // Profile challenge is supported on N or newer release.
- return profileOwner != null &&
- getTargetSdk(profileOwner.getPackageName(), userHandle) > Build.VERSION_CODES.M;
- }
-
private boolean canSetPasswordQualityOnParent(String packageName, final CallerIdentity caller) {
return !mInjector.isChangeEnabled(
PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT, packageName, caller.getUserId())
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index 607fb47..40b3664 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -1003,6 +1003,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
+ verify(l, times(1)).updateBackgroundRestrictedForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
+ eq(true));
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1017,6 +1019,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
+ verify(l, times(1)).updateBackgroundRestrictedForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
+ eq(false));
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1030,6 +1034,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1047,6 +1053,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean());
+ verify(l, times(1)).updateBackgroundRestrictedForUidPackage(eq(UID_10_2), eq(PACKAGE_2),
+ eq(true));
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1063,6 +1071,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1081,6 +1091,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1095,6 +1107,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1111,6 +1125,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1126,6 +1142,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1142,6 +1160,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1158,6 +1178,8 @@
verify(l, times(2)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1172,6 +1194,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1188,6 +1212,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1203,6 +1229,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(anyInt());
@@ -1225,6 +1253,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1240,6 +1270,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1255,6 +1287,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1270,6 +1304,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1286,6 +1322,8 @@
verify(l, times(1)).updateAllJobs();
verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(1)).updateAllAlarms();
verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1));
@@ -1301,6 +1339,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1316,6 +1356,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1331,6 +1373,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
@@ -1346,6 +1390,8 @@
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
+ verify(l, times(0)).updateBackgroundRestrictedForUidPackage(anyInt(), anyString(),
+ anyBoolean());
verify(l, times(0)).updateAllAlarms();
verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1));
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
index b580eae..850f881 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerTest.java
@@ -55,6 +55,7 @@
import android.support.test.uiautomator.UiDevice;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Pair;
@@ -99,6 +100,8 @@
private static final String ACTION_FGS_STATS_TEST =
"com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
private static final String EXTRA_MESSENGER = "extra_messenger";
+ private static final String ACTION_RECEIVER_TEST =
+ "com.android.servicestests.apps.simpleservicetestapp.TEST";
private static final String EXTRA_CALLBACK = "callback";
private static final String EXTRA_COMMAND = "command";
@@ -501,6 +504,205 @@
return false;
}
+ @LargeTest
+ @Test
+ public void testKillAppIfBgRestrictedCachedIdle() throws Exception {
+ final long shortTimeoutMs = 5_000;
+ final long backgroundSettleMs = 10_000;
+ final PackageManager pm = mContext.getPackageManager();
+ final int uid = pm.getPackageUid(TEST_APP1, 0);
+ final MyUidImportanceListener uidListener1 = new MyUidImportanceListener(uid);
+ final MyUidImportanceListener uidListener2 = new MyUidImportanceListener(uid);
+ final MyUidImportanceListener uidListener3 = new MyUidImportanceListener(uid);
+ SettingsSession<String> amConstantsSettings = null;
+ DeviceConfigSession<Boolean> killBgRestrictedAndCachedIdle = null;
+ DeviceConfigSession<Long> killBgRestrictedAndCachedIdleSettleTime = null;
+ final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+ final CountDownLatch[] latchHolder = new CountDownLatch[1];
+ final H handler = new H(Looper.getMainLooper(), latchHolder);
+ final Messenger messenger = new Messenger(handler);
+ try {
+ am.addOnUidImportanceListener(uidListener1,
+ RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
+ am.addOnUidImportanceListener(uidListener2, RunningAppProcessInfo.IMPORTANCE_GONE);
+ am.addOnUidImportanceListener(uidListener3, RunningAppProcessInfo.IMPORTANCE_CACHED);
+ toggleScreenOn(true);
+
+ killBgRestrictedAndCachedIdle = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ActivityManagerConstants.KEY_KILL_BG_RESTRICTED_CACHED_IDLE,
+ DeviceConfig::getBoolean,
+ ActivityManagerConstants.DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE);
+ killBgRestrictedAndCachedIdle.set(true);
+ killBgRestrictedAndCachedIdleSettleTime = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ActivityManagerConstants.KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME,
+ DeviceConfig::getLong,
+ ActivityManagerConstants.DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS);
+ killBgRestrictedAndCachedIdleSettleTime.set(backgroundSettleMs);
+ amConstantsSettings = new SettingsSession<>(
+ Settings.Global.getUriFor(Settings.Global.ACTIVITY_MANAGER_CONSTANTS),
+ Settings.Global::getString, Settings.Global::putString);
+ final KeyValueListParser parser = new KeyValueListParser(',');
+ long currentBackgroundSettleMs =
+ ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME;
+ try {
+ parser.setString(amConstantsSettings.get());
+ currentBackgroundSettleMs = parser.getLong(
+ ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME,
+ ActivityManagerConstants.DEFAULT_BACKGROUND_SETTLE_TIME);
+ } catch (IllegalArgumentException e) {
+ }
+ // Drain queue to make sure the existing UID_IDLE_MSG has been processed.
+ Thread.sleep(currentBackgroundSettleMs);
+ amConstantsSettings.set(
+ ActivityManagerConstants.KEY_BACKGROUND_SETTLE_TIME + "=" + backgroundSettleMs);
+
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+
+ final Intent intent = new Intent(ACTION_FGS_STATS_TEST);
+ final ComponentName cn = ComponentName.unflattenFromString(
+ TEST_APP1 + "/" + TEST_FGS_CLASS);
+ final Bundle bundle = new Bundle();
+ intent.setComponent(cn);
+ bundle.putBinder(EXTRA_MESSENGER, messenger.getBinder());
+ intent.putExtras(bundle);
+
+ // Start the FGS.
+ latchHolder[0] = new CountDownLatch(1);
+ mContext.startForegroundService(intent);
+ assertTrue("Timed out to start fg service", uidListener1.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+ assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Stop the FGS, it shouldn't be killed because it's not in FAS state.
+ latchHolder[0] = new CountDownLatch(1);
+ handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+ assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Set the FAS state.
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+ // Now it should've been killed.
+ assertTrue("Should have been killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Start the FGS.
+ // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+ latchHolder[0] = new CountDownLatch(1);
+ mContext.startForegroundService(intent);
+ assertTrue("Timed out to start fg service", uidListener1.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+ assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+ // It shouldn't be killed since it's not cached.
+ assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Stop the FGS, it should get killed because it's cached & uid idle & in FAS state.
+ latchHolder[0] = new CountDownLatch(1);
+ handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+ assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ assertTrue("Should have been killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Start the FGS.
+ // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+ latchHolder[0] = new CountDownLatch(1);
+ mContext.startForegroundService(intent);
+ assertTrue("Timed out to start fg service", uidListener1.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+ assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+ // It shouldn't be killed since it's not cached.
+ assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Stop the FGS.
+ latchHolder[0] = new CountDownLatch(1);
+ handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+ assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ assertTrue("Should have been in cached state", uidListener3.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_CACHED, shortTimeoutMs));
+ final long now = SystemClock.uptimeMillis();
+ // Sleep a while to let the UID idle ticking.
+ Thread.sleep(shortTimeoutMs);
+ // Now send a broadcast, it should bring the app out of cached for a while.
+ final Intent intent2 = new Intent(ACTION_RECEIVER_TEST);
+ final Bundle extras = new Bundle();
+ final IRemoteCallback callback = new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ latchHolder[0].countDown();
+ }
+ };
+ extras.putBinder(EXTRA_CALLBACK, callback.asBinder());
+ intent2.putExtras(extras);
+ intent2.setPackage(TEST_APP1);
+ latchHolder[0] = new CountDownLatch(1);
+ mContext.sendBroadcast(intent2);
+ assertTrue("Timed out to wait for receiving broadcast", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ // Try to wait for the killing, it should be killed after backgroundSettleMs
+ // since receiving the broadcast
+ assertFalse("Shouldn't be killed now", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE,
+ backgroundSettleMs + now - SystemClock.uptimeMillis() + 2_000));
+ // Now wait a bit longer, it should be killed.
+ assertTrue("Should have been killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Disable this FAS cached idle kill feature.
+ killBgRestrictedAndCachedIdle.set(false);
+
+ // Start the FGS.
+ // Temporarily allow RUN_ANY_IN_BACKGROUND to start FGS.
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND allow");
+ latchHolder[0] = new CountDownLatch(1);
+ mContext.startForegroundService(intent);
+ assertTrue("Timed out to start fg service", uidListener1.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE, shortTimeoutMs));
+ assertTrue("Timed out to get the remote messenger", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND deny");
+ assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+
+ // Stop the FGS, it shouldn't be killed because the feature has been turned off.
+ latchHolder[0] = new CountDownLatch(1);
+ handler.sendRemoteMessage(H.MSG_STOP_SERVICE, 0, 0, null);
+ assertTrue("Timed out to wait for stop fg", latchHolder[0].await(
+ shortTimeoutMs, TimeUnit.MILLISECONDS));
+ assertFalse("FGS shouldn't be killed", uidListener2.waitFor(
+ RunningAppProcessInfo.IMPORTANCE_GONE, backgroundSettleMs + shortTimeoutMs));
+ } finally {
+ runShellCommand("cmd appops set " + TEST_APP1 + " RUN_ANY_IN_BACKGROUND default");
+ if (amConstantsSettings != null) {
+ amConstantsSettings.close();
+ }
+ if (killBgRestrictedAndCachedIdle != null) {
+ killBgRestrictedAndCachedIdle.close();
+ }
+ if (killBgRestrictedAndCachedIdleSettleTime != null) {
+ killBgRestrictedAndCachedIdleSettleTime.close();
+ }
+ am.removeOnUidImportanceListener(uidListener1);
+ am.removeOnUidImportanceListener(uidListener2);
+ am.removeOnUidImportanceListener(uidListener3);
+ }
+ }
+
@Ignore("Need to disable calling uid check in ActivityManagerService.killPids before this test")
@Test
public void testKillPids() throws Exception {
@@ -717,6 +919,7 @@
static final int MSG_DONE = 1;
static final int MSG_START_FOREGROUND = 2;
static final int MSG_STOP_FOREGROUND = 3;
+ static final int MSG_STOP_SERVICE = 4;
private Messenger mRemoteMessenger;
private CountDownLatch[] mLatchHolder;
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
index 78afb7b..fdaf7cc 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/AndroidManifest.xml
@@ -27,6 +27,13 @@
<service android:name=".SimpleIsolatedService"
android:isolatedProcess="true"
android:exported="true" />
+ <receiver android:name=".SimpleReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.servicestests.apps.simpleservicetestapp.TEST" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
index ccfc0b7..56e1ab7 100644
--- a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleFgService.java
@@ -38,6 +38,7 @@
private static final int MSG_DONE = 1;
private static final int MSG_START_FOREGROUND = 2;
private static final int MSG_STOP_FOREGROUND = 3;
+ private static final int MSG_STOP_SERVICE = 4;
private static final String ACTION_FGS_STATS_TEST =
"com.android.servicestests.apps.simpleservicetestapp.ACTION_FGS_STATS_TEST";
@@ -57,6 +58,11 @@
stopForeground(true);
sendRemoteMessage(MSG_DONE, 0, 0, null);
} break;
+ case MSG_STOP_SERVICE: {
+ Log.i(TAG, "stopSelf");
+ stopSelf();
+ sendRemoteMessage(MSG_DONE, 0, 0, null);
+ } break;
}
}
};
diff --git a/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleReceiver.java b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleReceiver.java
new file mode 100644
index 0000000..1eced84
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SimpleServiceTestApp/src/com/android/servicestests/apps/simpleservicetestapp/SimpleReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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.servicestests.apps.simpleservicetestapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+
+public class SimpleReceiver extends BroadcastReceiver {
+ private static final String TAG = SimpleReceiver.class.getSimpleName();
+ private static final String EXTRA_CALLBACK = "callback";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, "onReceive " + intent);
+ final Bundle extra = intent.getExtras();
+ if (extra != null) {
+ final IBinder binder = extra.getBinder(EXTRA_CALLBACK);
+ if (binder != null) {
+ IRemoteCallback callback = IRemoteCallback.Stub.asInterface(binder);
+ try {
+ callback.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+}