Merge "Move registration of AssetManager.mObject to zygote." into pi-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index e54d2f6..20f0ba8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3663,6 +3663,7 @@
}
public final class ConfigUpdate {
+ field public static final java.lang.String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
field public static final java.lang.String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 6676196..2fc5808 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -46,6 +46,8 @@
import java.util.List;
public class Media extends BaseCommand {
+ // This doesn't belongs to any package. Setting the package name to empty string.
+ private static final String PACKAGE_NAME = "";
private ISessionManager mSessionService;
/**
@@ -104,7 +106,7 @@
private void sendMediaKey(KeyEvent event) {
try {
- mSessionService.dispatchMediaKeyEvent(event, false);
+ mSessionService.dispatchMediaKeyEvent(PACKAGE_NAME, false, event, false);
} catch (RemoteException e) {
}
}
@@ -264,13 +266,13 @@
} else if ("q".equals(line) || "quit".equals(line)) {
break;
} else if ("play".equals(line)) {
- mController.play("");
+ mController.play(PACKAGE_NAME);
} else if ("pause".equals(line)) {
- mController.pause("");
+ mController.pause(PACKAGE_NAME);
} else if ("next".equals(line)) {
- mController.next("");
+ mController.next(PACKAGE_NAME);
} else if ("previous".equals(line)) {
- mController.previous("");
+ mController.previous(PACKAGE_NAME);
} else {
System.out.println("Invalid command: " + line);
}
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index daafe9c..8487e67 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -503,7 +503,8 @@
void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
const int64_t timestampNs,
const DumpReportReason dumpReportReason) {
- if (mMetricsManagers.find(key) == mMetricsManagers.end()) {
+ if (mMetricsManagers.find(key) == mMetricsManagers.end() ||
+ !mMetricsManagers.find(key)->second->shouldWriteToDisk()) {
return;
}
ProtoOutputStream proto;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index a940d58..55dde10 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -186,7 +186,6 @@
flushIfNeededLocked(dumpTimeNs);
}
- flushIfNeededLocked(dumpTimeNs);
if (mPastBuckets.empty()) {
return;
}
@@ -324,6 +323,10 @@
triggerPuller = true;
break;
}
+ case GaugeMetric::CONDITION_CHANGE_TO_TRUE: {
+ triggerPuller = mCondition;
+ break;
+ }
default:
break;
}
@@ -348,7 +351,7 @@
flushIfNeededLocked(eventTimeNs);
mCondition = conditionMet;
- if (mPullTagId != -1 && mCondition) {
+ if (mPullTagId != -1) {
pullLocked(eventTimeNs);
} // else: Push mode. No need to proactively pull the gauge data.
}
@@ -538,7 +541,14 @@
size_t GaugeMetricProducer::byteSizeLocked() const {
size_t totalSize = 0;
for (const auto& pair : mPastBuckets) {
- totalSize += pair.second.size() * kBucketSize;
+ for (const auto& bucket : pair.second) {
+ totalSize += bucket.mGaugeAtoms.size() * sizeof(GaugeAtom);
+ for (const auto& atom : bucket.mGaugeAtoms) {
+ if (atom.mFields != nullptr) {
+ totalSize += atom.mFields->size() * sizeof(FieldValue);
+ }
+ }
+ }
}
return totalSize;
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 456da98..e143b5a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -67,6 +67,10 @@
return !mAllowedPkg.empty();
}
+ bool shouldWriteToDisk() const {
+ return mNoReportMetricIds.size() != mAllMetricProducers.size();
+ }
+
void dumpStates(FILE* out, bool verbose);
inline bool isInTtl(const int64_t timestampNs) const {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index fd36560..9b5d72b 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -234,6 +234,7 @@
enum SamplingType {
RANDOM_ONE_SAMPLE = 1;
ALL_CONDITION_CHANGES = 2;
+ CONDITION_CHANGE_TO_TRUE = 3;
}
optional SamplingType sampling_type = 9 [default = RANDOM_ONE_SAMPLE] ;
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 6a69100..7c07366 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -66,6 +66,7 @@
baseTimeNs, configAddedTimeNs, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mStatsPullerManager.ForceClearPullerCache();
int startBucketNum = processor->mMetricsManagers.begin()->second->
mAllMetricProducers[0]->getCurrentBucketNum();
@@ -211,6 +212,7 @@
baseTimeNs, configAddedTimeNs, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mStatsPullerManager.ForceClearPullerCache();
int startBucketNum = processor->mMetricsManagers.begin()->second->
mAllMetricProducers[0]->getCurrentBucketNum();
@@ -311,6 +313,7 @@
baseTimeNs, configAddedTimeNs, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mStatsPullerManager.ForceClearPullerCache();
int startBucketNum = processor->mMetricsManagers.begin()->second->
mAllMetricProducers[0]->getCurrentBucketNum();
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 545fa01..ad02569 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -110,8 +110,8 @@
TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
StatsService service(nullptr);
SendConfig(service, MakeConfig());
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
@@ -124,8 +124,8 @@
TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
StatsService service(nullptr);
SendConfig(service, MakeConfig());
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
// Force the uidmap to update at timestamp 2.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
@@ -142,8 +142,8 @@
TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
StatsService service(nullptr);
SendConfig(service, MakeConfig());
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
// Force the uidmap to update at timestamp 2.
@@ -165,8 +165,8 @@
TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
StatsService service(nullptr);
SendConfig(service, MakeConfig());
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
// Force the uidmap to update at timestamp 2.
@@ -190,8 +190,8 @@
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
SendConfig(service, MakeValueMetricConfig(0));
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
@@ -207,8 +207,8 @@
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
@@ -230,8 +230,8 @@
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
SendConfig(service, MakeGaugeMetricConfig(0));
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
@@ -247,8 +247,8 @@
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
- const long start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
- // initialized with.
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index 98a312f..febc958 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -66,6 +66,7 @@
baseTimeNs, configAddedTimeNs, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mStatsPullerManager.ForceClearPullerCache();
int startBucketNum = processor->mMetricsManagers.begin()->second->
mAllMetricProducers[0]->getCurrentBucketNum();
@@ -172,6 +173,7 @@
baseTimeNs, configAddedTimeNs, config, cfgKey);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mStatsPullerManager.ForceClearPullerCache();
int startBucketNum = processor->mMetricsManagers.begin()->second->
mAllMetricProducers[0]->getCurrentBucketNum();
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 96c3f85..290651c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -4105,6 +4105,7 @@
Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
+Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;Z)V
Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
Ldalvik/system/BlockGuard$Policy;->onNetwork()V
@@ -4145,6 +4146,10 @@
Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
Ldalvik/system/DexPathList;->splitPaths(Ljava/lang/String;Z)Ljava/util/List;
Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
+Ldalvik/system/SocketTagger;->get()Ldalvik/system/SocketTagger;
+Ldalvik/system/SocketTagger;->tag(Ljava/net/Socket;)V
+Ldalvik/system/SocketTagger;->untag(Ljava/net/Socket;)V
+Ldalvik/system/VMDebug;->allowHiddenApiReflectionFrom(Ljava/lang/Class;)V
Ldalvik/system/VMDebug;->dumpReferenceTables()V
Ldalvik/system/VMDebug;->isDebuggerConnected()Z
Ldalvik/system/VMRuntime;->addressOf(Ljava/lang/Object;)J
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 7032a2f..e469098 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -24,6 +24,7 @@
import android.hardware.display.VirtualDisplay;
import android.hardware.input.InputManager;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -111,6 +112,11 @@
* @see #startActivity(Intent)
*/
public abstract void onActivityViewDestroyed(ActivityView view);
+ /**
+ * Called when a task is moved to the front of the stack inside the container.
+ * This is a filtered version of {@link TaskStackListener}
+ */
+ public void onTaskMovedToFront(ActivityManager.StackInfo stackInfo) { }
}
/**
@@ -155,6 +161,28 @@
/**
* Launch a new activity into this container.
+ * <p>Activity resolved by the provided {@link Intent} must have
+ * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
+ * launched here. Also, if activity is not owned by the owner of this container, it must allow
+ * embedding and the caller must have permission to embed.
+ * <p>Note: This class must finish initializing and
+ * {@link StateCallback#onActivityViewReady(ActivityView)} callback must be triggered before
+ * this method can be called.
+ *
+ * @param intent Intent used to launch an activity.
+ * @param user The UserHandle of the user to start this activity for.
+ *
+ *
+ * @see StateCallback
+ * @see #startActivity(PendingIntent)
+ */
+ public void startActivity(@NonNull Intent intent, UserHandle user) {
+ final ActivityOptions options = prepareActivityOptions();
+ getContext().startActivityAsUser(intent, options.toBundle(), user);
+ }
+
+ /**
+ * Launch a new activity into this container.
* <p>Activity resolved by the provided {@link PendingIntent} must have
* {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
* launched here. Also, if activity is not owned by the owner of this container, it must allow
@@ -303,7 +331,9 @@
final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
mVirtualDisplay = displayManager.createVirtualDisplay(
DISPLAY_NAME + "@" + System.identityHashCode(this),
- width, height, getBaseDisplayDensity(), mSurface, 0 /* flags */);
+ width, height, getBaseDisplayDensity(), mSurface,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
+ | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
if (mVirtualDisplay == null) {
Log.e(TAG, "Failed to initialize ActivityView");
return;
@@ -317,7 +347,7 @@
e.rethrowAsRuntimeException();
}
mInputForwarder = InputManager.getInstance().createInputForwarder(displayId);
- mTaskStackListener = new TaskBackgroundChangeListener();
+ mTaskStackListener = new TaskStackListenerImpl();
try {
mActivityManager.registerTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
@@ -403,8 +433,11 @@
* A task change listener that detects background color change of the topmost stack on our
* virtual display and updates the background of the surface view. This background will be shown
* when surface view is resized, but the app hasn't drawn its content in new size yet.
+ * It also calls StateCallback.onTaskMovedToFront to notify interested parties that the stack
+ * associated with the {@link ActivityView} has had a Task moved to the front. This is useful
+ * when needing to also bring the host Activity to the foreground at the same time.
*/
- private class TaskBackgroundChangeListener extends TaskStackListener {
+ private class TaskStackListenerImpl extends TaskStackListener {
@Override
public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
@@ -413,6 +446,31 @@
return;
}
+ StackInfo stackInfo = getTopMostStackInfo();
+ if (stackInfo == null) {
+ return;
+ }
+ // Found the topmost stack on target display. Now check if the topmost task's
+ // description changed.
+ if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+ mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor());
+ }
+ }
+
+ @Override
+ public void onTaskMovedToFront(int taskId) throws RemoteException {
+ if (mActivityViewCallback != null) {
+ StackInfo stackInfo = getTopMostStackInfo();
+ // if StackInfo was null or unrelated to the "move to front" then there's no use
+ // notifying the callback
+ if (stackInfo != null
+ && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+ mActivityViewCallback.onTaskMovedToFront(stackInfo);
+ }
+ }
+ }
+
+ private StackInfo getTopMostStackInfo() throws RemoteException {
// Find the topmost task on our virtual display - it will define the background
// color of the surface view during resizing.
final int displayId = mVirtualDisplay.getDisplay().getDisplayId();
@@ -426,14 +484,10 @@
if (stackInfo.displayId != displayId) {
continue;
}
- // Found the topmost stack on target display. Now check if the topmost task's
- // description changed.
- if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
- mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor());
- }
- break;
+ // Found the topmost stack on target display.
+ return stackInfo;
}
+ return null;
}
}
-
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 07048f9..21a3c07 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -118,6 +118,13 @@
*/
public static final int MODE_FOREGROUND = 4;
+ /**
+ * Flag for {@link #startWatchingMode(String, String, int, OnOpChangedListener)}:
+ * Also get reports if the foreground state of an op's uid changes. This only works
+ * when watching a particular op, not when watching a package.
+ * @hide
+ */
+ public static final int WATCH_FOREGROUND_CHANGES = 1 << 0;
/**
* @hide
@@ -1900,6 +1907,21 @@
/**
* Monitor for changes to the operating mode for the given op in the given app package.
+ * You can watch op changes only for your UID.
+ *
+ * @param op The operation to monitor, one of OPSTR_*.
+ * @param packageName The name of the application to monitor.
+ * @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
+ * @param callback Where to report changes.
+ * @hide
+ */
+ public void startWatchingMode(String op, String packageName, int flags,
+ final OnOpChangedListener callback) {
+ startWatchingMode(strOpToOp(op), packageName, flags, callback);
+ }
+
+ /**
+ * Monitor for changes to the operating mode for the given op in the given app package.
*
* <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
* you can watch changes only for your UID.
@@ -1911,6 +1933,24 @@
*/
@RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
+ startWatchingMode(op, packageName, 0, callback);
+ }
+
+ /**
+ * Monitor for changes to the operating mode for the given op in the given app package.
+ *
+ * <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
+ * you can watch changes only for your UID.
+ *
+ * @param op The operation to monitor, one of OP_*.
+ * @param packageName The name of the application to monitor.
+ * @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
+ * @param callback Where to report changes.
+ * @hide
+ */
+ @RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
+ public void startWatchingMode(int op, String packageName, int flags,
+ final OnOpChangedListener callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.get(callback);
if (cb == null) {
@@ -1927,7 +1967,7 @@
mModeWatchers.put(callback, cb);
}
try {
- mService.startWatchingMode(op, packageName, cb);
+ mService.startWatchingModeWithFlags(op, packageName, flags, cb);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2080,6 +2120,19 @@
}
/**
+ * Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
+ * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
+ * @hide
+ */
+ public int unsafeCheckOpRaw(String op, int uid, String packageName) {
+ try {
+ return mService.checkOperation(strOpToOp(op), uid, packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Make note of an application performing an operation. Note that you must pass
* in both the uid and name of the application to be checked; this function will verify
* that these two match, and if not, return {@link #MODE_IGNORED}. If this call
@@ -2217,7 +2270,8 @@
*/
public int checkOpNoThrow(int op, int uid, String packageName) {
try {
- return mService.checkOperation(op, uid, packageName);
+ int mode = mService.checkOperation(op, uid, packageName);
+ return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 4b84ed4..ca3257f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -736,7 +736,13 @@
}
if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
- ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths);
+ // Temporarily disable logging of disk reads on the Looper thread as this is necessary
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
}
if (addedPaths != null && addedPaths.size() > 0) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 327d4fe..f771cbd 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7015,7 +7015,12 @@
contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
bindResult.getIconMarginEnd());
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
- mBuilder.resolveContrastColor());
+ mBuilder.isColorized() ? mBuilder.getPrimaryTextColor()
+ : mBuilder.resolveContrastColor());
+ contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
+ mBuilder.getPrimaryTextColor());
+ contentView.setInt(R.id.status_bar_latest_event_content, "setMessageTextColor",
+ mBuilder.getSecondaryTextColor());
contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd",
displayImagesAtEnd);
contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dec2cd4..ea08110 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1420,6 +1420,9 @@
* Activity Action: Start Voice Command.
* <p>Input: Nothing.
* <p>Output: Nothing.
+ * <p class="note">
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
@@ -5683,9 +5686,24 @@
/**
- * If set, resolution of this intent may take place via an instant app not
- * yet on the device if there does not yet exist an app on device to
- * resolve it.
+ * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
+ * this flag will attempt to launch an instant app if no full app on the device can already
+ * handle the intent.
+ * <p>
+ * When attempting to resolve instant apps externally, the following {@link Intent} properties
+ * are supported:
+ * <ul>
+ * <li>{@link Intent#setAction(String)}</li>
+ * <li>{@link Intent#addCategory(String)}</li>
+ * <li>{@link Intent#setData(Uri)}</li>
+ * <li>{@link Intent#setType(String)}</li>
+ * <li>{@link Intent#setPackage(String)}</li>
+ * <li>{@link Intent#addFlags(int)}</li>
+ * </ul>
+ * <p>
+ * In the case that no instant app can be found, the installer will be launched to notify the
+ * user that the intent could not be resolved. On devices that do not support instant apps,
+ * the flag will be ignored.
*/
public static final int FLAG_ACTIVITY_MATCH_EXTERNAL = 0x00000800;
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 07fbfb5..52e28a4 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -16,6 +16,10 @@
package android.content.pm;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.res.XmlResourceParser;
@@ -29,7 +33,11 @@
import android.util.Printer;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
import java.text.Collator;
+import java.util.BitSet;
import java.util.Comparator;
/**
@@ -42,6 +50,47 @@
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
+ private static final int LINE_FEED_CODE_POINT = 10;
+ private static final int NBSP_CODE_POINT = 160;
+
+ /**
+ * Flags for {@link #loadSafeLabel(PackageManager, float, int)}
+ *
+ * @hide
+ */
+ @Retention(SOURCE)
+ @IntDef(flag = true, prefix = "SAFE_LABEL_FLAG_",
+ value = {SAFE_LABEL_FLAG_TRIM, SAFE_LABEL_FLAG_SINGLE_LINE,
+ SAFE_LABEL_FLAG_FIRST_LINE})
+ public @interface SafeLabelFlags {}
+
+ /**
+ * Remove {@link Character#isWhitespace(int) whitespace} and non-breaking spaces from the edges
+ * of the label.
+ *
+ * @see #loadSafeLabel(PackageManager, float, int)
+ * @hide
+ */
+ public static final int SAFE_LABEL_FLAG_TRIM = 0x1;
+
+ /**
+ * Force entire string into single line of text (no newlines). Cannot be set at the same time as
+ * {@link #SAFE_LABEL_FLAG_FIRST_LINE}.
+ *
+ * @see #loadSafeLabel(PackageManager, float, int)
+ * @hide
+ */
+ public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 0x2;
+
+ /**
+ * Return only first line of text (truncate at first newline). Cannot be set at the same time as
+ * {@link #SAFE_LABEL_FLAG_SINGLE_LINE}.
+ *
+ * @see #loadSafeLabel(PackageManager, float, int)
+ * @hide
+ */
+ public static final int SAFE_LABEL_FLAG_FIRST_LINE = 0x4;
+
private static final float MAX_LABEL_SIZE_PX = 500f;
/** The maximum length of a safe label, in characters */
private static final int MAX_SAFE_LABEL_LENGTH = 50000;
@@ -164,18 +213,7 @@
}
/**
- * Same as {@link #loadLabel(PackageManager)} with the addition that
- * the returned label is safe for being presented in the UI since it
- * will not contain new lines and the length will be limited to a
- * reasonable amount. This prevents a malicious party to influence UI
- * layout via the app label misleading the user into performing a
- * detrimental for them action. If the label is too long it will be
- * truncated and ellipsized at the end.
- *
- * @param pm A PackageManager from which the label can be loaded; usually
- * the PackageManager from which you originally retrieved this item
- * @return Returns a CharSequence containing the item's label. If the
- * item does not have a label, its name is returned.
+ * Deprecated use loadSafeLabel(PackageManager, float, int) instead
*
* @hide
*/
@@ -225,6 +263,216 @@
TextUtils.TruncateAt.END);
}
+ private static boolean isNewline(int codePoint) {
+ int type = Character.getType(codePoint);
+ return type == Character.PARAGRAPH_SEPARATOR || type == Character.LINE_SEPARATOR
+ || codePoint == LINE_FEED_CODE_POINT;
+ }
+
+ private static boolean isWhiteSpace(int codePoint) {
+ return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT;
+ }
+
+ /**
+ * A special string manipulation class. Just records removals and executes the when onString()
+ * is called.
+ */
+ private static class StringWithRemovedChars {
+ /** The original string */
+ private final String mOriginal;
+
+ /**
+ * One bit per char in string. If bit is set, character needs to be removed. If whole
+ * bit field is not initialized nothing needs to be removed.
+ */
+ private BitSet mRemovedChars;
+
+ StringWithRemovedChars(@NonNull String original) {
+ mOriginal = original;
+ }
+
+ /**
+ * Mark all chars in a range {@code [firstRemoved - firstNonRemoved[} (not including
+ * firstNonRemoved) as removed.
+ */
+ void removeRange(int firstRemoved, int firstNonRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(firstRemoved, firstNonRemoved);
+ }
+
+ /**
+ * Remove all characters before {@code firstNonRemoved}.
+ */
+ void removeAllCharBefore(int firstNonRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(0, firstNonRemoved);
+ }
+
+ /**
+ * Remove all characters after and including {@code firstRemoved}.
+ */
+ void removeAllCharAfter(int firstRemoved) {
+ if (mRemovedChars == null) {
+ mRemovedChars = new BitSet(mOriginal.length());
+ }
+
+ mRemovedChars.set(firstRemoved, mOriginal.length());
+ }
+
+ @Override
+ public String toString() {
+ // Common case, no chars removed
+ if (mRemovedChars == null) {
+ return mOriginal;
+ }
+
+ StringBuilder sb = new StringBuilder(mOriginal.length());
+ for (int i = 0; i < mOriginal.length(); i++) {
+ if (!mRemovedChars.get(i)) {
+ sb.append(mOriginal.charAt(i));
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Return length or the original string
+ */
+ int length() {
+ return mOriginal.length();
+ }
+
+ /**
+ * Return if a certain {@code offset} of the original string is removed
+ */
+ boolean isRemoved(int offset) {
+ return mRemovedChars != null && mRemovedChars.get(offset);
+ }
+
+ /**
+ * Return codePoint of original string at a certain {@code offset}
+ */
+ int codePointAt(int offset) {
+ return mOriginal.codePointAt(offset);
+ }
+ }
+
+ /**
+ * Load, clean up and truncate label before use.
+ *
+ * <p>This method is meant to remove common mistakes and nefarious formatting from strings that
+ * are used in sensitive parts of the UI.
+ *
+ * <p>This method first treats the string like HTML and then ...
+ * <ul>
+ * <li>Removes new lines or truncates at first new line
+ * <li>Trims the white-space off the end
+ * <li>Truncates the string to a given length
+ * </ul>
+ * ... if specified.
+ *
+ * @param ellipsizeDip Assuming maximum length of the string (in dip), assuming font size 42.
+ * This is roughly 50 characters for {@code ellipsizeDip == 1000}.<br />
+ * Usually ellipsizing should be left to the view showing the string. If a
+ * string is used as an input to another string, it might be useful to
+ * control the length of the input string though. {@code 0} disables this
+ * feature.
+ * @return The safe label
+ * @hide
+ */
+ public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm,
+ @FloatRange(from = 0) float ellipsizeDip, @SafeLabelFlags int flags) {
+ boolean onlyKeepFirstLine = ((flags & SAFE_LABEL_FLAG_FIRST_LINE) != 0);
+ boolean forceSingleLine = ((flags & SAFE_LABEL_FLAG_SINGLE_LINE) != 0);
+ boolean trim = ((flags & SAFE_LABEL_FLAG_TRIM) != 0);
+
+ Preconditions.checkNotNull(pm);
+ Preconditions.checkArgument(ellipsizeDip >= 0);
+ Preconditions.checkFlagsArgument(flags, SAFE_LABEL_FLAG_TRIM | SAFE_LABEL_FLAG_SINGLE_LINE
+ | SAFE_LABEL_FLAG_FIRST_LINE);
+ Preconditions.checkArgument(!(onlyKeepFirstLine && forceSingleLine),
+ "Cannot set SAFE_LABEL_FLAG_SINGLE_LINE and SAFE_LABEL_FLAG_FIRST_LINE at the same "
+ + "time");
+
+ // loadLabel() always returns non-null
+ String label = loadUnsafeLabel(pm).toString();
+
+ // Treat string as HTML. This
+ // - converts HTML symbols: e.g. ß -> ß
+ // - applies some HTML tags: e.g. <br> -> \n
+ // - removes invalid characters such as \b
+ // - removes html styling, such as <b>
+ // - applies html formatting: e.g. a<p>b</p>c -> a\n\nb\n\nc
+ // - replaces some html tags by "object replacement" markers: <img> -> \ufffc
+ // - Removes leading white space
+ // - Removes all trailing white space beside a single space
+ // - Collapses double white space
+ StringWithRemovedChars labelStr = new StringWithRemovedChars(
+ Html.fromHtml(label).toString());
+
+ int firstNonWhiteSpace = -1;
+ int firstTrailingWhiteSpace = -1;
+
+ // Remove new lines (if requested) and control characters.
+ int labelLength = labelStr.length();
+ for (int offset = 0; offset < labelLength; ) {
+ int codePoint = labelStr.codePointAt(offset);
+ int type = Character.getType(codePoint);
+ int codePointLen = Character.charCount(codePoint);
+ boolean isNewline = isNewline(codePoint);
+
+ if (offset > MAX_SAFE_LABEL_LENGTH || onlyKeepFirstLine && isNewline) {
+ labelStr.removeAllCharAfter(offset);
+ break;
+ } else if (forceSingleLine && isNewline) {
+ labelStr.removeRange(offset, offset + codePointLen);
+ } else if (type == Character.CONTROL && !isNewline) {
+ labelStr.removeRange(offset, offset + codePointLen);
+ } else if (trim && !isWhiteSpace(codePoint)) {
+ // This is only executed if the code point is not removed
+ if (firstNonWhiteSpace == -1) {
+ firstNonWhiteSpace = offset;
+ }
+ firstTrailingWhiteSpace = offset + codePointLen;
+ }
+
+ offset += codePointLen;
+ }
+
+ if (trim) {
+ // Remove leading and trailing white space
+ if (firstNonWhiteSpace == -1) {
+ // No non whitespace found, remove all
+ labelStr.removeAllCharAfter(0);
+ } else {
+ if (firstNonWhiteSpace > 0) {
+ labelStr.removeAllCharBefore(firstNonWhiteSpace);
+ }
+ if (firstTrailingWhiteSpace < labelLength) {
+ labelStr.removeAllCharAfter(firstTrailingWhiteSpace);
+ }
+ }
+ }
+
+ if (ellipsizeDip == 0) {
+ return labelStr.toString();
+ } else {
+ // Truncate
+ final TextPaint paint = new TextPaint();
+ paint.setTextSize(42);
+
+ return TextUtils.ellipsize(labelStr.toString(), paint, ellipsizeDip,
+ TextUtils.TruncateAt.END);
+ }
+ }
+
/**
* Retrieve the current graphical icon associated with this item. This
* will call back on the given PackageManager to load the icon from
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1b80d3d5..9154ce0 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1660,23 +1660,29 @@
* @see ShutterCallback
*/
public final boolean enableShutterSound(boolean enabled) {
- if (!enabled) {
- IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
- IAudioService audioService = IAudioService.Stub.asInterface(b);
- try {
- if (audioService.isCameraSoundForced()) return false;
- } catch (RemoteException e) {
- Log.e(TAG, "Audio service is unavailable for queries");
+ boolean canDisableShutterSound = true;
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService audioService = IAudioService.Stub.asInterface(b);
+ try {
+ if (audioService.isCameraSoundForced()) {
+ canDisableShutterSound = false;
}
+ } catch (RemoteException e) {
+ Log.e(TAG, "Audio service is unavailable for queries");
+ }
+ if (!enabled && !canDisableShutterSound) {
+ return false;
}
synchronized (mShutterSoundLock) {
- if (enabled && mHasAppOpsPlayAudio) {
- Log.i(TAG, "Shutter sound is not allowed by AppOpsManager");
- return false;
- }
+ mShutterSoundEnabledFromApp = enabled;
+ // Return the result of _enableShutterSound(enabled) in all cases.
+ // If the shutter sound can be disabled, disable it when the device is in DnD mode.
boolean ret = _enableShutterSound(enabled);
- if (ret) {
- mShutterSoundEnabledFromApp = enabled;
+ if (enabled && !mHasAppOpsPlayAudio) {
+ Log.i(TAG, "Shutter sound is not allowed by AppOpsManager");
+ if (canDisableShutterSound) {
+ _enableShutterSound(false);
+ }
}
return ret;
}
@@ -1739,9 +1745,18 @@
}
if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
if (!mHasAppOpsPlayAudio) {
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ IAudioService audioService = IAudioService.Stub.asInterface(b);
+ try {
+ if (audioService.isCameraSoundForced()) {
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Audio service is unavailable for queries");
+ }
_enableShutterSound(false);
} else {
- _enableShutterSound(mShutterSoundEnabledFromApp);
+ enableShutterSound(mShutterSoundEnabledFromApp);
}
}
}
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index dda0ed8..53b1c51 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -90,6 +90,14 @@
public static final String ACTION_UPDATE_NETWORK_WATCHLIST
= "android.intent.action.UPDATE_NETWORK_WATCHLIST";
+ /**
+ * Update carrier id config file.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_UPDATE_CARRIER_ID_DB
+ = "android.os.action.UPDATE_CARRIER_ID_DB";
+
private ConfigUpdate() {
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 98d9bea..10ee728 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -123,6 +123,10 @@
* Input: Nothing.
* <p>
* Output: Nothing.
+ *
+ * <p class="note">
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS";
@@ -882,6 +886,10 @@
* Applications can also use {@link android.net.ConnectivityManager#getRestrictBackgroundStatus
* ConnectivityManager#getRestrictBackgroundStatus()} to determine the
* status of the background data restrictions for them.
+ *
+ * <p class="note">
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS =
@@ -1148,6 +1156,10 @@
* Input: Nothing.
* <p>
* Output: Nothing.
+ *
+ * <p class="note">
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS
@@ -8902,6 +8914,14 @@
public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
/**
+ * Comma separated list of privileged package names, which will be running out-of-box APK.
+ * Default: "ALL"
+ *
+ * @hide
+ */
+ public static final String PRIV_APP_OOB_LIST = "priv_app_oob_list";
+
+ /**
* The interval in milliseconds at which location requests will be throttled when they are
* coming from the background.
*
@@ -10417,6 +10437,25 @@
public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
/**
+ * App ops specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "state_settle_time=10000"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * state_settle_time (long)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.AppOpsService.Constants
+ */
+ public static final String APP_OPS_CONSTANTS = "app_ops_constants";
+
+ /**
* Device Idle (Doze) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 14727f0..00060ab 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -253,7 +253,7 @@
* @return String containing the OpenMobile API version (e.g. "3.0").
*/
public @NonNull String getVersion() {
- return "3.2";
+ return "3.3";
}
@NonNull ISecureElementListener getListener() {
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index ce94315c..362b94b 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -141,6 +141,10 @@
* <ul>
* <li>{@link #EXTRA_SECURE}
* </ul>
+ *
+ * <p class="note">
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
*/
public static final String ACTION_VOICE_SEARCH_HANDS_FREE =
"android.speech.action.VOICE_SEARCH_HANDS_FREE";
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 2505ea5..0ed9724 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -54,4 +54,6 @@
void startWatchingActive(in int[] ops, IAppOpsActiveCallback callback);
void stopWatchingActive(IAppOpsActiveCallback callback);
boolean isOperationActive(int code, int uid, String packageName);
+
+ void startWatchingModeWithFlags(int op, String packageName, int flags, IAppOpsCallback callback);
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index cbd3ad5..4ee950a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -68,6 +68,10 @@
*/
public static final int API_ENFORCEMENT_POLICY_SHIFT =
Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK);
+ /**
+ * Enable system server ART profiling.
+ */
+ public static final int PROFILE_SYSTEM_SERVER = 1 << 14;
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 33049be..da19560 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -702,6 +702,12 @@
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
+ boolean profileSystemServer = SystemProperties.getBoolean(
+ "dalvik.vm.profilesystemserver", false);
+ if (profileSystemServer) {
+ parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
+ }
+
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index a3c7a9e..fbf690f 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -370,6 +370,14 @@
return snapTarget;
}
+ /**
+ * @return whether or not there are more than 1 split targets that do not include the two
+ * dismiss targets, used in deciding to display the middle target for accessibility
+ */
+ public boolean showMiddleSplitTargetForAccessibility() {
+ return (mTargets.size() - 2) > 1;
+ }
+
public boolean isFirstSplitTargetAvailable() {
return mFirstSplitTarget != mMiddleTarget;
}
diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
index ebc2c71..1959301 100644
--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
@@ -23,7 +23,7 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.media.AudioManager;
-import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.MediaSessionManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
@@ -48,6 +48,7 @@
KeyguardManager mKeyguardManager;
SearchManager mSearchManager;
TelephonyManager mTelephonyManager;
+ MediaSessionManager mMediaSessionManager;
public PhoneFallbackEventHandler(Context context) {
mContext = context;
@@ -84,8 +85,7 @@
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
- event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+ handleVolumeKeyEvent(event);
return true;
}
@@ -216,8 +216,7 @@
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (!event.isCanceled()) {
- MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
- event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+ handleVolumeKeyEvent(event);
}
return true;
}
@@ -306,12 +305,25 @@
return mAudioManager;
}
+ MediaSessionManager getMediaSessionManager() {
+ if (mMediaSessionManager == null) {
+ mMediaSessionManager =
+ (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
+ }
+ return mMediaSessionManager;
+ }
+
void sendCloseSystemWindows() {
PhoneWindow.sendCloseSystemWindows(mContext, null);
}
+ private void handleVolumeKeyEvent(KeyEvent keyEvent) {
+ getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent,
+ AudioManager.USE_DEFAULT_STREAM_TYPE);
+ }
+
private void handleMediaKeyEvent(KeyEvent keyEvent) {
- MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
+ getMediaSessionManager().dispatchMediaKeyEventAsSystemService(keyEvent);
}
private boolean isUserSetupComplete() {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 7ea023e..3fe8f85 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -23,6 +23,7 @@
import android.app.ActivityManager;
import android.app.SearchManager;
+import android.media.session.MediaSessionManager;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -74,7 +75,6 @@
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.session.MediaController;
-import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -252,6 +252,7 @@
private AudioManager mAudioManager;
private KeyguardManager mKeyguardManager;
+ private MediaSessionManager mMediaSessionManager;
private int mUiOptions = 0;
@@ -1873,22 +1874,10 @@
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
- int direction = 0;
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- direction = AudioManager.ADJUST_RAISE;
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- direction = AudioManager.ADJUST_LOWER;
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- direction = AudioManager.ADJUST_TOGGLE_MUTE;
- break;
- }
- mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
+ mMediaController.dispatchVolumeButtonEventAsSystemService(event);
} else {
- MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
- event, mVolumeControlStreamType, false);
+ getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(event,
+ mVolumeControlStreamType);
}
return true;
}
@@ -1906,7 +1895,7 @@
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
if (mMediaController != null) {
- if (mMediaController.dispatchMediaButtonEvent(event)) {
+ if (mMediaController.dispatchMediaButtonEventAsSystemService(event)) {
return true;
}
}
@@ -1948,6 +1937,14 @@
return mAudioManager;
}
+ private MediaSessionManager getMediaSessionManager() {
+ if (mMediaSessionManager == null) {
+ mMediaSessionManager = (MediaSessionManager) getContext().getSystemService(
+ Context.MEDIA_SESSION_SERVICE);
+ }
+ return mMediaSessionManager;
+ }
+
/**
* A key was released and not handled by anything else in the window.
*
@@ -1969,12 +1966,10 @@
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
- final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
- | AudioManager.FLAG_FROM_KEY;
- mMediaController.adjustVolume(0, flags);
+ mMediaController.dispatchVolumeButtonEventAsSystemService(event);
} else {
- MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
- event, mVolumeControlStreamType, false);
+ getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(
+ event, mVolumeControlStreamType);
}
return true;
}
@@ -1983,8 +1978,8 @@
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
- event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+ getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(
+ event, AudioManager.USE_DEFAULT_STREAM_TYPE);
return true;
}
// These are all the recognized media key codes in
@@ -2001,7 +1996,7 @@
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
if (mMediaController != null) {
- if (mMediaController.dispatchMediaButtonEvent(event)) {
+ if (mMediaController.dispatchMediaButtonEventAsSystemService(event)) {
return true;
}
}
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 0f13078..318bccf 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -418,10 +418,23 @@
*
* @param isBgDarker {@code true} if {@code bg} is darker than {@code color}.
*/
- private static int ensureTextContrast(int color, int bg, boolean isBgDarker) {
+ public static int ensureTextContrast(int color, int bg, boolean isBgDarker) {
+ return ensureContrast(color, bg, isBgDarker, 4.5);
+ }
+
+ /**
+ * Finds a color with sufficient contrast over bg that has the same or darker hue as the
+ * original color, depending on the value of {@code isBgDarker}.
+ *
+ * @param color the color to start searching from
+ * @param bg the color to ensure contrast against
+ * @param isBgDarker {@code true} if {@code bg} is darker than {@code color}
+ * @param minRatio the minimum contrast ratio required
+ */
+ public static int ensureContrast(int color, int bg, boolean isBgDarker, double minRatio) {
return isBgDarker
- ? findContrastColorAgainstDark(color, bg, true, 4.5)
- : findContrastColor(color, bg, true, 4.5);
+ ? findContrastColorAgainstDark(color, bg, true, minRatio)
+ : findContrastColor(color, bg, true, minRatio);
}
/** Finds a background color for a text view with given text color and hint text color, that
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index b9a8864..7116f3a 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -148,8 +148,6 @@
}
mAvatarView.setVisibility(VISIBLE);
mSenderName.setVisibility(TextUtils.isEmpty(nameOverride) ? GONE : VISIBLE);
- mTextColor = getNormalTextColor();
- mSendingTextColor = calculateSendingTextColor();
}
public void setSending(boolean sending) {
@@ -160,10 +158,6 @@
}
}
- private int getNormalTextColor() {
- return mContext.getColor(R.color.notification_secondary_text_color_light);
- }
-
private int calculateSendingTextColor() {
TypedValue alphaValue = new TypedValue();
mContext.getResources().getValue(
@@ -363,6 +357,13 @@
}
}
+ public void setTextColors(int senderTextColor, int messageTextColor) {
+ mTextColor = messageTextColor;
+ mSendingTextColor = calculateSendingTextColor();
+ updateMessageColor();
+ mSenderName.setTextColor(senderTextColor);
+ }
+
public void setLayoutColor(int layoutColor) {
if (layoutColor != mLayoutColor){
mLayoutColor = layoutColor;
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 538ea11..79576bd 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -73,6 +73,8 @@
private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
private TextView mTitleView;
private int mLayoutColor;
+ private int mSenderTextColor;
+ private int mMessageTextColor;
private int mAvatarSize;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint mTextPaint = new Paint();
@@ -301,6 +303,16 @@
mIsOneToOne = oneToOne;
}
+ @RemotableViewMethod
+ public void setSenderTextColor(int color) {
+ mSenderTextColor = color;
+ }
+
+ @RemotableViewMethod
+ public void setMessageTextColor(int color) {
+ mMessageTextColor = color;
+ }
+
public void setUser(Person user) {
mUser = user;
if (mUser.getIcon() == null) {
@@ -344,6 +356,7 @@
}
newGroup.setDisplayImagesAtEnd(mDisplayImagesAtEnd);
newGroup.setLayoutColor(mLayoutColor);
+ newGroup.setTextColors(mSenderTextColor, mMessageTextColor);
Person sender = senders.get(groupIndex);
CharSequence nameOverride = null;
if (sender != mUser && mNameReplacement != null) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f8dd7ac..9da3b21 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -747,6 +747,12 @@
jittransitionweightOptBuf,
"-Xjittransitionweight:");
+ property_get("dalvik.vm.profilebootimage", propBuf, "");
+ if (strcmp(propBuf, "true") == 0) {
+ addOption("-Xps-profile-boot-class-path");
+ addOption("-Xps-profile-aot-code");
+ }
+
/*
* Madvise related options.
*/
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 3ea6049..df735ae 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -139,18 +139,9 @@
return throw_exception(env, ImageDecoder::kSourceMalformedData, "Could not open file",
nullptr, source);
}
+
std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
-
- if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
- return native_create(env, std::move(fileStream), source);
- }
-
- // FIXME: This allows us to pretend the current location is the beginning,
- // but it would be better if SkFILEStream allowed treating its starting
- // point as the beginning.
- std::unique_ptr<SkStream> stream(SkFrontBufferedStream::Make(std::move(fileStream),
- SkCodec::MinBufferedBytesNeeded()));
- return native_create(env, std::move(stream), source);
+ return native_create(env, std::move(fileStream), source);
}
static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1f8d43c..87d8915 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4262,7 +4262,7 @@
<receiver android:name="com.android.server.updates.CarrierIdInstallReceiver"
android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
- <action android:name="com.android.internal.intent.action.UPDATE_CARRIER_ID_DB" />
+ <action android:name="android.os.action.UPDATE_CARRIER_ID_DB" />
<data android:scheme="content" android:host="*" android:mimeType="*/*" />
</intent-filter>
</receiver>
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index fdc9f01..c8864c2 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -59,7 +59,7 @@
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
- android:textSize="24sp"
+ android:textSize="@dimen/notification_ambient_title_text_size"
android:textColor="#ffffffff"
/>
<TextView android:id="@+id/text"
@@ -70,7 +70,7 @@
android:layout_weight="1"
android:gravity="top|center_horizontal"
android:visibility="gone"
- android:textSize="16sp"
+ android:textSize="@dimen/notification_ambient_text_size"
android:textColor="#eeffffff"
android:layout_marginTop="4dp"
android:ellipsize="end"
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 095a632..79a7b90 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -137,7 +137,7 @@
<color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color>
<color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color>
<color name="notification_secondary_text_color_light">@color/primary_text_default_material_light</color>
- <item name="notification_secondary_text_disabled_alpha" format="float" type="dimen">0.30</item>
+ <item name="notification_secondary_text_disabled_alpha" format="float" type="dimen">0.38</item>
<color name="notification_secondary_text_color_dark">@color/primary_text_default_material_dark</color>
<color name="notification_default_color_dark">@color/primary_text_default_material_light</color>
<color name="notification_default_color_light">#a3202124</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 780cda2..bc43d91 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -506,11 +506,11 @@
<!-- String containing the apn value for tethering. May be overriden by secure settings
TETHER_DUN_APN. Value is a comma separated series of strings:
"name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type",
- Or string format of ApnSettingV3.
+ Or string format of ApnSettingV3 or higher.
note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN"
Multiple entries are separated by using string-array:
"<item>[ApnSettingV3]Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP,true,14,,,,,,,spn,testspn</item>
- <item>[ApnSettingV3]Name1,apn2,,,,,,,,,123,46,,mms|*,IPV6,IP,true,12,,,,,,,,</item>" -->
+ <item>[ApnSettingV5]Name1,apn2,,,,,,,,,123,46,,mms|*,IPV6,IP,true,12,,,,,,,,,,</item>" -->
<string-array translatable="false" name="config_tether_apndata">
</string-array>
@@ -665,7 +665,7 @@
<!-- Wifi driver supports IEEE80211AC for softap -->
<bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
-
+
<!-- Flag indicating whether the we should enable the automatic brightness in Settings.
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
@@ -3423,4 +3423,8 @@
<!-- Package name for ManagedProvisioning which is responsible for provisioning work profiles. -->
<string name="config_managed_provisioning_package" translatable="false">com.android.managedprovisioning</string>
+
+ <!-- Whether or not swipe up gesture is enabled by default -->
+ <bool name="config_swipe_up_gesture_default">false</bool>
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 791f7c6..2e8c7f9 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -374,6 +374,10 @@
<dimen name="notification_title_text_size">14sp</dimen>
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
<dimen name="notification_subtext_size">12sp</dimen>
+ <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
+ <dimen name="notification_ambient_text_size">16sp</dimen>
+ <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
+ <dimen name="notification_ambient_title_text_size">24sp</dimen>
<!-- Top padding for notifications in the standard layout. -->
<dimen name="notification_top_pad">10dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index de9f3b0..db2aa8e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3301,6 +3301,8 @@
<java-symbol type="string" name="shortcut_restore_signature_mismatch" />
<java-symbol type="string" name="shortcut_restore_unknown_issue" />
+ <java-symbol type="bool" name="config_swipe_up_gesture_default" />
+
<!-- From media projection -->
<java-symbol type="string" name="config_mediaProjectionPermissionDialogComponent" />
<java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" />
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index 821ee80..44510c2 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -20,6 +20,9 @@
import junit.framework.TestCase;
public class VintfObjectTest extends TestCase {
+ /**
+ * Sanity check for {@link VintfObject#report VintfObject.report()}.
+ */
public void testReport() {
String[] xmls = VintfObject.report();
assertTrue(xmls.length > 0);
@@ -28,6 +31,6 @@
"<manifest version=\"1.0\" type=\"framework\">"));
// From /system/compatibility-matrix.xml
assertTrue(String.join("", xmls).contains(
- "<compatibility-matrix version=\"1.0\" type=\"framework\">"));
+ "<compatibility-matrix version=\"1.0\" type=\"framework\""));
}
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ceb58f6..18bc20c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -115,6 +115,7 @@
Settings.Global.APN_DB_UPDATE_CONTENT_URL,
Settings.Global.APN_DB_UPDATE_METADATA_URL,
Settings.Global.APP_IDLE_CONSTANTS,
+ Settings.Global.APP_OPS_CONSTANTS,
Settings.Global.APP_STANDBY_ENABLED,
Settings.Global.ASSISTED_GPS_ENABLED,
Settings.Global.AUDIO_SAFE_VOLUME_STATE,
@@ -357,6 +358,7 @@
Settings.Global.POWER_MANAGER_CONSTANTS,
Settings.Global.PREFERRED_NETWORK_MODE,
Settings.Global.PRIV_APP_OOB_ENABLED,
+ Settings.Global.PRIV_APP_OOB_LIST,
Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
Settings.Global.RADIO_BLUETOOTH,
Settings.Global.RADIO_CELL,
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index c486e68..aa45709 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -2540,19 +2540,20 @@
if (position < 0) {
return -1;
}
- if (mPosition != position) {
- in.seek(position);
- mPosition = position;
- }
+ try {
+ if (mPosition != position) {
+ in.seek(position);
+ mPosition = position;
+ }
- int bytesRead = in.read(buffer, offset, size);
- if (bytesRead < 0) {
- mPosition = -1; // need to seek on next read
- return -1;
- }
-
- mPosition += bytesRead;
- return bytesRead;
+ int bytesRead = in.read(buffer, offset, size);
+ if (bytesRead >= 0) {
+ mPosition += bytesRead;
+ return bytesRead;
+ }
+ } catch (IOException e) {}
+ mPosition = -1; // need to seek on next read
+ return -1;
}
@Override
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 06f5863..b4f52f9 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -37,7 +37,7 @@
*/
interface ISessionController {
void sendCommand(String packageName, String command, in Bundle args, in ResultReceiver cb);
- boolean sendMediaButton(String packageName, in KeyEvent mediaButton);
+ boolean sendMediaButton(String packageName, boolean asSystemService, in KeyEvent mediaButton);
void registerCallbackListener(in ISessionControllerCallback cb);
void unregisterCallbackListener(in ISessionControllerCallback cb);
boolean isTransportControlEnabled();
@@ -46,7 +46,7 @@
PendingIntent getLaunchPendingIntent();
long getFlags();
ParcelableVolumeInfo getVolumeAttributes();
- void adjustVolume(String packageName, int direction, int flags);
+ void adjustVolume(String packageName, boolean asSystemService, int direction, int flags);
void setVolumeTo(String packageName, int value, int flags);
// These commands are for the TransportControls
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 56664a9..3578c16 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -34,9 +34,11 @@
interface ISessionManager {
ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
List<IBinder> getSessions(in ComponentName compName, int userId);
- void dispatchMediaKeyEvent(in KeyEvent keyEvent, boolean needWakeLock);
- void dispatchVolumeKeyEvent(in KeyEvent keyEvent, int stream, boolean musicOnly);
- void dispatchAdjustVolume(int suggestedStream, int delta, int flags);
+ void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
+ boolean needWakeLock);
+ void dispatchVolumeKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
+ int stream, boolean musicOnly);
+ void dispatchAdjustVolume(String packageName, int suggestedStream, int delta, int flags);
void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
int userId);
void removeSessionsListener(in IActiveSessionsListener listener);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 84f85e7..8c34a31 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -126,6 +126,27 @@
* @return true if the event was sent to the session, false otherwise.
*/
public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
+ return dispatchMediButtonEventInternal(false, keyEvent);
+ }
+
+ /**
+ * Dispatches the media button event as system service to the session. This only effects the
+ * {@link MediaSession.Callback#getCurrentControllerInfo()} and doesn't bypass any permission
+ * check done by the system service.
+ * <p>
+ * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
+ * foreground activity didn't consume the key from the hardware devices.
+ *
+ * @param keyEvent media key event
+ * @return {@code true} if the event was sent to the session, {@code false} otherwise
+ * @hide
+ */
+ public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
+ return dispatchMediButtonEventInternal(true, keyEvent);
+ }
+
+ private boolean dispatchMediButtonEventInternal(boolean asSystemService,
+ @NonNull KeyEvent keyEvent) {
if (keyEvent == null) {
throw new IllegalArgumentException("KeyEvent may not be null");
}
@@ -133,7 +154,8 @@
return false;
}
try {
- return mSessionBinder.sendMediaButton(mContext.getPackageName(), keyEvent);
+ return mSessionBinder.sendMediaButton(mContext.getPackageName(), asSystemService,
+ keyEvent);
} catch (RemoteException e) {
// System is dead. =(
}
@@ -141,6 +163,52 @@
}
/**
+ * Dispatches the volume button event as system service to the session. This only effects the
+ * {@link MediaSession.Callback#getCurrentControllerInfo()} and doesn't bypass any permission
+ * check done by the system service.
+ * <p>
+ * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
+ * foreground activity didn't consume the key from the hardware devices.
+ *
+ * @param keyEvent volume key event
+ * @hide
+ */
+ public void dispatchVolumeButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
+ switch (keyEvent.getAction()) {
+ case KeyEvent.ACTION_DOWN: {
+ int direction = 0;
+ switch (keyEvent.getKeyCode()) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ direction = AudioManager.ADJUST_RAISE;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ direction = AudioManager.ADJUST_LOWER;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ direction = AudioManager.ADJUST_TOGGLE_MUTE;
+ break;
+ }
+ try {
+ mSessionBinder.adjustVolume(mContext.getPackageName(), true, direction,
+ AudioManager.FLAG_SHOW_UI);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling adjustVolumeBy", e);
+ }
+ }
+
+ case KeyEvent.ACTION_UP: {
+ final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
+ | AudioManager.FLAG_FROM_KEY;
+ try {
+ mSessionBinder.adjustVolume(mContext.getPackageName(), true, 0, flags);
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Error calling adjustVolumeBy", e);
+ }
+ }
+ }
+ }
+
+ /**
* Get the current playback state for this session.
*
* @return The current PlaybackState or null
@@ -322,7 +390,7 @@
*/
public void adjustVolume(int direction, int flags) {
try {
- mSessionBinder.adjustVolume(mContext.getPackageName(), direction, flags);
+ mSessionBinder.adjustVolume(mContext.getPackageName(), false, direction, flags);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 5e8b8ca..6f4f20e 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -122,6 +122,15 @@
FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
public @interface SessionFlags { }
+ private static final String EXTRA_KEY_CALLING_PACKAGE =
+ "android.media.session.extra.CALLING_PACKAGE";
+ private static final String EXTRA_KEY_CALLING_PID =
+ "android.media.session.extra.CALLING_PID";
+ private static final String EXTRA_KEY_CALLING_UID =
+ "android.media.session.extra.CALLING_UID";
+ private static final String EXTRA_KEY_ORIGINAL_BUNDLE =
+ "android.media.session.extra.ORIGINAL_BUNDLE";
+
private final Object mLock = new Object();
private final int mMaxBitmapSize;
@@ -520,11 +529,15 @@
* @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
*/
public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
- if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
+ return createRemoteUserInfo(getCurrentData());
+ }
+
+ private @NonNull Bundle getCurrentData() {
+ if (mCallback == null || mCallback.mCurrentData == null) {
throw new IllegalStateException(
"This should be called inside of MediaSession.Callback methods");
}
- return mCallback.mCurrentControllerInfo;
+ return mCallback.mCurrentData;
}
/**
@@ -556,7 +569,7 @@
*/
public String getCallingPackage() {
if (mCallback != null) {
- return mCallback.mCurrentControllerInfo.getPackageName();
+ return createRemoteUserInfo(mCallback.mCurrentData).getPackageName();
}
return null;
}
@@ -659,6 +672,57 @@
}
/**
+ * Creates the extra bundle that includes the caller information.
+ *
+ * @return An extraBundle that contains caller information
+ */
+ private static Bundle createExtraBundle(String packageName, int pid, int uid) {
+ return createExtraBundle(packageName, pid, uid, null);
+ }
+
+ /**
+ * Creates the extra bundle that includes the caller information.
+ *
+ * @param originalBundle bundle
+ * @return An extraBundle that contains caller information
+ */
+ private static Bundle createExtraBundle(String packageName, int pid, int uid,
+ Bundle originalBundle) {
+ Bundle bundle = new Bundle();
+ bundle.putString(EXTRA_KEY_CALLING_PACKAGE, packageName);
+ bundle.putInt(EXTRA_KEY_CALLING_PID, pid);
+ bundle.putInt(EXTRA_KEY_CALLING_UID, uid);
+ if (originalBundle != null) {
+ bundle.putBundle(EXTRA_KEY_ORIGINAL_BUNDLE, originalBundle);
+ }
+ return bundle;
+ }
+
+ /**
+ * Creates the {@link RemoteUserInfo} from the extra bundle created by
+ * {@link #createExtraBundle}.
+ *
+ * @param extraBundle that previously created by createExtraBundle()
+ * @return a RemoteUserInfo
+ */
+ private static RemoteUserInfo createRemoteUserInfo(Bundle extraBundle) {
+ return new RemoteUserInfo(
+ extraBundle.getString(EXTRA_KEY_CALLING_PACKAGE),
+ extraBundle.getInt(EXTRA_KEY_CALLING_PID, INVALID_PID),
+ extraBundle.getInt(EXTRA_KEY_CALLING_UID, INVALID_UID));
+ }
+
+ /**
+ * Gets the original bundle from the extra bundle created by {@link #createExtraBundle}.
+ *
+ * @param extraBundle that previously created by createExtraBundle()
+ * @return a Bundle
+ */
+ private static Bundle getOriginalBundle(Bundle extraBundle) {
+ return extraBundle.getBundle(EXTRA_KEY_ORIGINAL_BUNDLE);
+ }
+
+ /**
* Return true if this is considered an active playback state.
*
* @hide
@@ -755,9 +819,6 @@
private MediaSession mSession;
private CallbackMessageHandler mHandler;
private boolean mMediaPlayPauseKeyPending;
- private String mCallingPackage;
- private int mCallingPid;
- private int mCallingUid;
public Callback() {
}
@@ -811,8 +872,9 @@
}
} else {
mMediaPlayPauseKeyPending = true;
- mHandler.sendEmptyMessageDelayed(CallbackMessageHandler
- .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+ mHandler.postDelayed(CallbackMessageHandler
+ .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+ mSession.getCurrentData(),
ViewConfiguration.getDoubleTapTimeout());
}
return true;
@@ -1242,22 +1304,6 @@
session.dispatchSetVolumeTo(value, createExtraBundle(packageName, pid, uid));
}
}
-
- private Bundle createExtraBundle(String packageName, int pid, int uid) {
- return createExtraBundle(packageName, pid, uid, null);
- }
-
- private Bundle createExtraBundle(String packageName, int pid, int uid,
- Bundle originalBundle) {
- Bundle bundle = new Bundle();
- bundle.putString(CallbackMessageHandler.EXTRA_KEY_CALLING_PACKAGE, packageName);
- bundle.putInt(CallbackMessageHandler.EXTRA_KEY_CALLING_PID, pid);
- bundle.putInt(CallbackMessageHandler.EXTRA_KEY_CALLING_UID, uid);
- if (originalBundle != null) {
- bundle.putBundle(CallbackMessageHandler.EXTRA_KEY_ORIGINAL_BUNDLE, originalBundle);
- }
- return bundle;
- }
}
/**
@@ -1379,15 +1425,6 @@
private class CallbackMessageHandler extends Handler {
- private static final String EXTRA_KEY_CALLING_PACKAGE =
- "android.media.session.extra.CALLING_PACKAGE";
- private static final String EXTRA_KEY_CALLING_PID =
- "android.media.session.extra.CALLING_PID";
- private static final String EXTRA_KEY_CALLING_UID =
- "android.media.session.extra.CALLING_UID";
- private static final String EXTRA_KEY_ORIGINAL_BUNDLE =
- "android.media.session.extra.ORIGINAL_BUNDLE";
-
private static final int MSG_COMMAND = 1;
private static final int MSG_MEDIA_BUTTON = 2;
private static final int MSG_PREPARE = 3;
@@ -1413,8 +1450,7 @@
private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
private MediaSession.Callback mCallback;
-
- private RemoteUserInfo mCurrentControllerInfo;
+ private Bundle mCurrentData;
public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
super(looper, null, true);
@@ -1422,22 +1458,25 @@
mCallback.mHandler = this;
}
- public void post(int what, Object obj, Bundle bundle) {
+ public void post(int what, Object obj, Bundle data) {
Message msg = obtainMessage(what, obj);
- msg.setData(bundle);
+ msg.setData(data);
msg.sendToTarget();
}
+ public void postDelayed(int what, Bundle data, long delayMs) {
+ Message msg = obtainMessage(what);
+ msg.setData(data);
+ sendMessageDelayed(msg, delayMs);
+ }
+
@Override
public void handleMessage(Message msg) {
VolumeProvider vp;
- Bundle bundle = msg.getData();
- Bundle originalBundle = bundle.getBundle(EXTRA_KEY_ORIGINAL_BUNDLE);
+ Bundle data = msg.getData();
+ Bundle originalBundle = getOriginalBundle(data);
- mCurrentControllerInfo = new RemoteUserInfo(
- bundle.getString(EXTRA_KEY_CALLING_PACKAGE),
- bundle.getInt(EXTRA_KEY_CALLING_PID, INVALID_PID),
- bundle.getInt(EXTRA_KEY_CALLING_UID, INVALID_UID));
+ mCurrentData = data;
switch (msg.what) {
case MSG_COMMAND:
@@ -1521,7 +1560,7 @@
mCallback.handleMediaPlayPauseKeySingleTapIfPending();
break;
}
- mCurrentControllerInfo = null;
+ mCurrentData = null;
}
}
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f358103..f54bfc1 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -300,8 +300,28 @@
* @hide
*/
public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean needWakeLock) {
+ dispatchMediaKeyEventInternal(false, keyEvent, needWakeLock);
+ }
+
+ /**
+ * Send a media key event as system component. The receiver will be selected automatically.
+ * <p>
+ * Should be only called by the {@link com.android.internal.policy.PhoneWindow} or
+ * {@link android.view.FallbackEventHandler} when the foreground activity didn't consume the key
+ * from the hardware devices.
+ *
+ * @param keyEvent The KeyEvent to send.
+ * @hide
+ */
+ public void dispatchMediaKeyEventAsSystemService(KeyEvent keyEvent) {
+ dispatchMediaKeyEventInternal(true, keyEvent, false);
+ }
+
+ private void dispatchMediaKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
+ boolean needWakeLock) {
try {
- mService.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+ mService.dispatchMediaKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
+ needWakeLock);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send key event.", e);
}
@@ -311,12 +331,33 @@
* Send a volume key event. The receiver will be selected automatically.
*
* @param keyEvent The volume KeyEvent to send.
- * @param needWakeLock True if a wake lock should be held while sending the key.
* @hide
*/
public void dispatchVolumeKeyEvent(@NonNull KeyEvent keyEvent, int stream, boolean musicOnly) {
+ dispatchVolumeKeyEventInternal(false, keyEvent, stream, musicOnly);
+ }
+
+ /**
+ * Dispatches the volume button event as system service to the session. This only effects the
+ * {@link MediaSession.Callback#getCurrentControllerInfo()} and doesn't bypass any permission
+ * check done by the system service.
+ * <p>
+ * Should be only called by the {@link com.android.internal.policy.PhoneWindow} or
+ * {@link android.view.FallbackEventHandler} when the foreground activity didn't consume the key
+ * from the hardware devices.
+ *
+ * @param keyEvent The KeyEvent to send.
+ * @hide
+ */
+ public void dispatchVolumeKeyEventAsSystemService(@NonNull KeyEvent keyEvent, int streamType) {
+ dispatchVolumeKeyEventInternal(true, keyEvent, streamType, false);
+ }
+
+ private void dispatchVolumeKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
+ int stream, boolean musicOnly) {
try {
- mService.dispatchVolumeKeyEvent(keyEvent, stream, musicOnly);
+ mService.dispatchVolumeKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
+ stream, musicOnly);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send volume key event.", e);
}
@@ -336,7 +377,8 @@
*/
public void dispatchAdjustVolume(int suggestedStream, int direction, int flags) {
try {
- mService.dispatchAdjustVolume(suggestedStream, direction, flags);
+ mService.dispatchAdjustVolume(mContext.getPackageName(), suggestedStream, direction,
+ flags);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send adjust volume.", e);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 54a1af4..6a2a04a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -47,8 +47,10 @@
"com.android.settings.category.ia.development";
public static final String CATEGORY_NOTIFICATIONS =
"com.android.settings.category.ia.notifications";
- public static final String CATEGORY_DO_NOT_DISTURB =
- "com.android.settings.category.ia.dnd";
+ public static final String CATEGORY_DO_NOT_DISTURB = "com.android.settings.category.ia.dnd";
+ public static final String CATEGORY_GESTURES = "com.android.settings.category.ia.gestures";
+ public static final String CATEGORY_NIGHT_LIGHT =
+ "com.android.settings.category.ia.night_light";
public static final Map<String, String> KEY_COMPAT_MAP;
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 06e2ee1..b7699f1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -67,6 +67,19 @@
return mWhitelistedApps.contains(pkg);
}
+ public boolean isWhitelisted(String[] pkgs) {
+ if (ArrayUtils.isEmpty(pkgs)) {
+ return false;
+ }
+ for (String pkg : pkgs) {
+ if (isWhitelisted(pkg)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public boolean isSysWhitelistedExceptIdle(String pkg) {
return mSysWhitelistedAppsExceptIdle.contains(pkg);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
index 6025d68..13364ab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
@@ -26,6 +26,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
+import android.text.format.DateUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
import java.util.ArrayList;
@@ -41,7 +42,8 @@
@VisibleForTesting
static final String ANDROID_SYSTEM_PACKAGE_NAME = "android";
- private static final int RECENT_TIME_INTERVAL_MILLIS = 15 * 60 * 1000;
+ // Keep last 24 hours of location app information.
+ private static final long RECENT_TIME_INTERVAL_MILLIS = DateUtils.DAY_IN_MILLIS;
@VisibleForTesting
static final int[] LOCATION_OPS = new int[] {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index d12473e..f34605c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -57,8 +57,10 @@
allKeys.add(CategoryKey.CATEGORY_SYSTEM);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
+ allKeys.add(CategoryKey.CATEGORY_GESTURES);
+ allKeys.add(CategoryKey.CATEGORY_NIGHT_LIGHT);
// DO NOT REMOVE ANYTHING ABOVE
- assertThat(allKeys.size()).isEqualTo(16);
+ assertThat(allKeys.size()).isEqualTo(18);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index f591781..0af2c05 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -61,24 +61,32 @@
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
mPowerWhitelistBackend.addApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).addPowerSaveWhitelistApp(PACKAGE_TWO);
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(
+ new String[]{PACKAGE_ONE, PACKAGE_TWO})).isTrue();
mPowerWhitelistBackend.removeApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
mPowerWhitelistBackend.removeApp(PACKAGE_ONE);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_ONE);
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerWhitelistBackend.isWhitelisted(
+ new String[]{PACKAGE_ONE, PACKAGE_TWO})).isFalse();
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
index 5e0fcef..8a54aee 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
@@ -37,8 +37,8 @@
// App running duration in milliseconds
private static final int DURATION = 10;
private static final long ONE_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(1);
- private static final long FOURTEEN_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(14);
- private static final long TWENTY_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(20);
+ private static final long TWENTY_THREE_HOURS_AGO = NOW - TimeUnit.HOURS.toMillis(23);
+ private static final long TWO_DAYS_AGO = NOW - TimeUnit.DAYS.toMillis(2);
private static final String[] TEST_PACKAGE_NAMES =
{"package_1MinAgo", "package_14MinAgo", "package_20MinAgo"};
@@ -74,7 +74,7 @@
when(mUserManager.getUserProfiles())
.thenReturn(Collections.singletonList(new UserHandle(mTestUserId)));
- long[] testRequestTime = {ONE_MIN_AGO, FOURTEEN_MIN_AGO, TWENTY_MIN_AGO};
+ long[] testRequestTime = {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO};
List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
when(mAppOpsManager.getPackagesForOps(RecentLocationApps.LOCATION_OPS)).thenReturn(appOps);
mockTestApplicationInfos(mTestUserId, TEST_PACKAGE_NAMES);
@@ -91,7 +91,7 @@
assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
assertThat(requests.get(0).requestFinishTime).isEqualTo(ONE_MIN_AGO + DURATION);
assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
- assertThat(requests.get(1).requestFinishTime).isEqualTo(FOURTEEN_MIN_AGO + DURATION);
+ assertThat(requests.get(1).requestFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO + DURATION);
}
@Test
@@ -105,7 +105,7 @@
ONE_MIN_AGO,
DURATION);
long[] testRequestTime =
- {ONE_MIN_AGO, FOURTEEN_MIN_AGO, TWENTY_MIN_AGO, ONE_MIN_AGO};
+ {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO, ONE_MIN_AGO};
List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
appOps.add(androidSystemPackageOps);
when(mAppOpsManager.getPackagesForOps(RecentLocationApps.LOCATION_OPS)).thenReturn(appOps);
@@ -119,7 +119,7 @@
assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
assertThat(requests.get(0).requestFinishTime).isEqualTo(ONE_MIN_AGO + DURATION);
assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
- assertThat(requests.get(1).requestFinishTime).isEqualTo(FOURTEEN_MIN_AGO + DURATION);
+ assertThat(requests.get(1).requestFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO + DURATION);
}
private void mockTestApplicationInfos(int userId, String... packageNameList)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 4c98bb8..1c635c4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -254,6 +254,7 @@
case Settings.Secure.TOUCH_EXPLORATION_ENABLED:
case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
+ case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED:
case Settings.Secure.UI_NIGHT_MODE:
return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
case Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES:
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index bd5b1f2..1ca6afe 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -10,7 +10,9 @@
../src/com/android/providers/settings/SettingsState.java \
../src/com/android/providers/settings/SettingsHelper.java
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-test \
+ truth-prebuilt
LOCAL_JAVA_LIBRARIES := android.test.base
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
new file mode 100644
index 0000000..b438e91
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 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.providers.settings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link SettingsHelper#restoreValue(Context, ContentResolver, ContentValues, Uri,
+ * String, String, int)}. Specifically verifies that we restore critical accessibility settings only
+ * if the user has not already configured these in SUW.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SettingsHelperRestoreTest {
+ private Context mContext;
+ private ContentResolver mContentResolver;
+ private SettingsHelper mSettingsHelper;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ mContentResolver = mContext.getContentResolver();
+ mSettingsHelper = new SettingsHelper(mContext);
+ }
+
+ /** Tests for {@link Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED}. */
+ @Test
+ public void
+ restoreAccessibilityDisplayMagnificationNavbarEnabled_alreadyConfigured_doesNotRestore()
+ throws Exception {
+ // Simulate already configuring setting via SUW.
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+ 1);
+
+ mSettingsHelper.restoreValue(
+ mContext,
+ mContentResolver,
+ new ContentValues(2),
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+ String.valueOf(0),
+ Build.VERSION.SDK_INT);
+
+ assertThat(
+ Settings.Secure.getInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED))
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void
+ restoreAccessibilityDisplayMagnificationNavbarEnabled_notAlreadyConfigured_restores()
+ throws Exception {
+ // Simulate system default at boot.
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+ 0);
+
+ mSettingsHelper.restoreValue(
+ mContext,
+ mContentResolver,
+ new ContentValues(2),
+ Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+ String.valueOf(1),
+ Build.VERSION.SDK_INT);
+
+ assertThat(
+ Settings.Secure.getInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED))
+ .isEqualTo(1);
+ }
+}
diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
index 93adaa0..31119a9 100644
--- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml
+++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
@@ -26,7 +26,8 @@
android:insetBottom="8dp">
<shape android:shape="rectangle">
<corners android:radius="8dp" />
- <stroke android:width="1dp" android:color="@color/smart_reply_button_stroke" />
+ <stroke android:width="@dimen/smart_reply_button_stroke_width"
+ android:color="@color/smart_reply_button_stroke" />
<solid android:color="@color/smart_reply_button_background"/>
</shape>
</inset>
diff --git a/packages/SystemUI/res/layout/hybrid_notification.xml b/packages/SystemUI/res/layout/hybrid_notification.xml
index bccf207..23e8a15 100644
--- a/packages/SystemUI/res/layout/hybrid_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_notification.xml
@@ -25,7 +25,6 @@
android:id="@+id/notification_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
android:singleLine="true"
style="?attr/hybridNotificationTitleStyle"
/>
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index b5d48b4..e902c92 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,7 +42,7 @@
android:singleLine="true"
android:ellipsize="start"
android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
- android:imeOptions="actionSend|flagNoExtractUi|flagNoFullscreen" />
+ android:imeOptions="actionSend" />
<FrameLayout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index a490c4b..9faed18 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -19,6 +19,7 @@
<!-- android:paddingHorizontal is set dynamically in SmartReplyView. -->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
style="@android:style/Widget.Material.Button"
+ android:stateListAnimator="@null"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="0dp"
diff --git a/packages/SystemUI/res/layout/smart_reply_view.xml b/packages/SystemUI/res/layout/smart_reply_view.xml
index aa5549f..9fffc72 100644
--- a/packages/SystemUI/res/layout/smart_reply_view.xml
+++ b/packages/SystemUI/res/layout/smart_reply_view.xml
@@ -25,6 +25,7 @@
android:layout_width="wrap_content"
systemui:spacing="@dimen/smart_reply_button_spacing"
systemui:singleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_single_line"
- systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line">
+ systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line"
+ systemui:buttonStrokeWidth="@dimen/smart_reply_button_stroke_width">
<!-- smart_reply_button(s) will be added here. -->
</com.android.systemui.statusbar.policy.SmartReplyView>
diff --git a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
index c8a5544..7931dfe 100644
--- a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
@@ -21,62 +21,70 @@
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_combo"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingStart="2dp"
- android:orientation="horizontal">
- <FrameLayout
- android:id="@+id/inout_container"
- android:layout_height="17dp"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical" >
+
+ <com.android.keyguard.AlphaOptimizedLinearLayout
+ android:id="@+id/mobile_group"
android:layout_width="wrap_content"
- android:layout_gravity="center_vertical">
- <ImageView
- android:id="@+id/mobile_in"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/ic_activity_down"
- android:visibility="gone"
- android:paddingEnd="2dp"
- />
- <ImageView
- android:id="@+id/mobile_out"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:src="@drawable/ic_activity_up"
- android:paddingEnd="2dp"
- android:visibility="gone"
- />
- </FrameLayout>
- <ImageView
- android:id="@+id/mobile_type"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingEnd="1dp"
- android:visibility="gone" />
- <Space
- android:id="@+id/mobile_roaming_space"
android:layout_height="match_parent"
- android:layout_width="@dimen/roaming_icon_start_padding"
- android:visibility="gone"
- />
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical">
- <com.android.systemui.statusbar.AnimatedImageView
- android:id="@+id/mobile_signal"
- android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:paddingStart="2dp"
+ android:orientation="horizontal" >
+
+ <FrameLayout
+ android:id="@+id/inout_container"
+ android:layout_height="17dp"
android:layout_width="wrap_content"
- systemui:hasOverlappingRendering="false"
- />
+ android:layout_gravity="center_vertical">
+ <ImageView
+ android:id="@+id/mobile_in"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_activity_down"
+ android:visibility="gone"
+ android:paddingEnd="2dp"
+ />
+ <ImageView
+ android:id="@+id/mobile_out"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_activity_up"
+ android:paddingEnd="2dp"
+ android:visibility="gone"
+ />
+ </FrameLayout>
<ImageView
- android:id="@+id/mobile_roaming"
+ android:id="@+id/mobile_type"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingEnd="1dp"
+ android:visibility="gone" />
+ <Space
+ android:id="@+id/mobile_roaming_space"
+ android:layout_height="match_parent"
+ android:layout_width="@dimen/roaming_icon_start_padding"
+ android:visibility="gone"
+ />
+ <FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:src="@drawable/stat_sys_roaming"
- android:contentDescription="@string/data_connection_roaming"
- android:visibility="gone" />
- </FrameLayout>
+ android:layout_gravity="center_vertical">
+ <com.android.systemui.statusbar.AnimatedImageView
+ android:id="@+id/mobile_signal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
+ />
+ <ImageView
+ android:id="@+id/mobile_roaming"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/stat_sys_roaming"
+ android:contentDescription="@string/data_connection_roaming"
+ android:visibility="gone" />
+ </FrameLayout>
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
</com.android.systemui.statusbar.StatusBarMobileView>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index b11266a..2ce9bfc 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -135,6 +135,7 @@
<attr name="spacing" format="dimension" />
<attr name="singleLineButtonPaddingHorizontal" format="dimension" />
<attr name="doubleLineButtonPaddingHorizontal" format="dimension" />
+ <attr name="buttonStrokeWidth" format="dimension" />
</declare-styleable>
<!-- Used to style rotate suggestion button AVD animations -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index efcca63..3472477 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -151,7 +151,8 @@
<color name="zen_introduction">#ffffffff</color>
<color name="smart_reply_button_text">#5F6368</color>
- <color name="smart_reply_button_background">#feffffff</color>
+ <color name="smart_reply_button_text_dark_bg">@*android:color/notification_primary_text_color_dark</color>
+ <color name="smart_reply_button_background">#ffffffff</color>
<color name="smart_reply_button_stroke">#ffdadce0</color>
<!-- Fingerprint dialog colors -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f3fe297..8c3cc42 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -951,6 +951,7 @@
<dimen name="smart_reply_button_padding_horizontal_single_line">20dp</dimen>
<dimen name="smart_reply_button_padding_horizontal_double_line">19dp</dimen>
<dimen name="smart_reply_button_min_height">48dp</dimen>
+ <dimen name="smart_reply_button_stroke_width">1dp</dimen>
<dimen name="smart_reply_button_font_size">14sp</dimen>
<dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 95ccc3c..654f407 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -623,6 +623,8 @@
<!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "+ 3" [CHAR LIMIT=5] -->
<string name="notification_group_overflow_indicator">+ <xliff:g id="number" example="3">%s</xliff:g></string>
+ <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "New message, +3" [CHAR LIMIT=7] -->
+ <string name="notification_group_overflow_indicator_ambient"><xliff:g id="notification_title" example="New message">%s</xliff:g>, +<xliff:g id="overflow" example="+3">%s</xliff:g></string>
<!-- Content description describing how many more notifications are in a group [CHAR LIMIT=NONE] -->
<plurals name="notification_group_overflow_description">
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c9b14dc..b3f4534 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -110,7 +110,6 @@
<item name="android:paddingStart">@*android:dimen/notification_extra_margin_ambient</item>
<item name="android:paddingEnd">@*android:dimen/notification_extra_margin_ambient</item>
<item name="android:orientation">vertical</item>
- <item name="android:paddingBottom">23.5dp</item>
</style>
<style name="hybrid_notification">
@@ -119,22 +118,28 @@
</style>
<style name="hybrid_notification_title_ambient">
+ <item name="android:layout_marginTop">@*android:dimen/notification_header_margin_top_ambient</item>
<item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
<item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
- <item name="android:textSize">20sp</item>
+ <item name="android:textAppearance">@*android:style/Notification.Header.Ambient</item>
+ <item name="android:layout_gravity">top|center_horizontal</item>
+ <item name="android:textSize">@*android:dimen/notification_ambient_title_text_size</item>
<item name="android:textColor">#ffffffff</item>
</style>
<style name="hybrid_notification_title">
<item name="android:paddingEnd">4dp</item>
+ <item name="android:textAppearance">@*android:style/TextAppearance.Material.Notification.Title</item>
</style>
<style name="hybrid_notification_text_ambient">
<item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
<item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
- <item name="android:textSize">16sp</item>
+ <item name="android:textSize">@*android:dimen/notification_ambient_text_size</item>
<item name="android:textColor">#eeffffff</item>
- <item name="android:layout_marginTop">4dp</item>
+ <item name="android:gravity">top|center_horizontal</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:maxLines">3</item>
</style>
<style name="hybrid_notification_text"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 5a0dddc..cc536a5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -57,6 +57,7 @@
public static final int HIT_TARGET_BACK = 1;
public static final int HIT_TARGET_HOME = 2;
public static final int HIT_TARGET_OVERVIEW = 3;
+ public static final int HIT_TARGET_ROTATION = 4;
@Retention(RetentionPolicy.SOURCE)
@IntDef({FLAG_DISABLE_SWIPE_UP,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 5b4d652..aa0bcc5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -241,6 +241,10 @@
mViewMediatorCallback.resetKeyguard();
}
+ public void resetSecurityContainer() {
+ mSecurityContainer.reset();
+ }
+
@Override
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
if (mViewMediatorCallback != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index a265a5e..0ca0a11 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -74,6 +74,7 @@
private boolean mEnforceBouncer = false;
private boolean mBouncerOn = false;
+ private boolean mBouncerOffOnDown = false;
private boolean mSessionActive = false;
private boolean mIsTouchScreen = true;
private int mState = StatusBarState.SHADE;
@@ -459,10 +460,19 @@
public void onTouchEvent(MotionEvent event, int width, int height) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mIsTouchScreen = event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN);
+ // If the bouncer was not shown during the down event,
+ // we want the entire gesture going to HumanInteractionClassifier
+ mBouncerOffOnDown = !mBouncerOn;
}
- if (mSessionActive && !mBouncerOn) {
- mDataCollector.onTouchEvent(event, width, height);
- mHumanInteractionClassifier.onTouchEvent(event);
+ if (mSessionActive) {
+ if (!mBouncerOn) {
+ // In case bouncer is "visible", but onFullyShown has not yet been called,
+ // avoid adding the event to DataCollector
+ mDataCollector.onTouchEvent(event, width, height);
+ }
+ if (mBouncerOffOnDown) {
+ mHumanInteractionClassifier.onTouchEvent(event);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index ea3f95e..4b65288 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -26,6 +26,7 @@
import android.app.KeyguardManager;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -699,6 +700,9 @@
UserHandle.USER_ALL);
try {
WindowManagerGlobal.getWindowManagerService().lockNow(null);
+ // Lock profiles (if any) on the background thread.
+ final Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
+ bgHandler.post(() -> lockProfiles());
} catch (RemoteException e) {
Log.e(TAG, "Error while trying to lock device.", e);
}
@@ -716,6 +720,18 @@
};
}
+ private void lockProfiles() {
+ final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ final TrustManager tm = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
+ final int currentUserId = getCurrentUser().id;
+ final int[] profileIds = um.getEnabledProfileIds(currentUserId);
+ for (final int id : profileIds) {
+ if (id != currentUserId) {
+ tm.setDeviceLockedForUser(id, true);
+ }
+ }
+ }
+
private UserInfo getCurrentUser() {
try {
return ActivityManager.getService().getCurrentUser();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index f60e207..d16e1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -69,7 +69,8 @@
private static final boolean RESET_PREFS_FOR_DEBUG = false;
private static final boolean ONBOARDING_ENABLED = true;
private static final long SHOW_DELAY_MS = 500;
- private static final long SHOW_HIDE_DURATION_MS = 300;
+ private static final long SHOW_DURATION_MS = 300;
+ private static final long HIDE_DURATION_MS = 100;
// Show swipe-up tips after opening overview from home this number of times.
private static final int SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT = 3;
// Show quick scrub tips after opening overview this number of times.
@@ -172,6 +173,11 @@
}
@Override
+ public void onQuickStepStarted() {
+ hide(true);
+ }
+
+ @Override
public void onQuickScrubStarted() {
boolean alreadySeenQuickScrubsOnboarding = hasSeenQuickScrubOnboarding();
if (!alreadySeenQuickScrubsOnboarding) {
@@ -292,7 +298,7 @@
mHasDismissedQuickScrubTip = false;
mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
- hide(false);
+ hide(true);
}
public void onConfigurationChanged(Configuration newConfiguration) {
@@ -305,15 +311,12 @@
if (!shouldShow()) {
return;
}
- if (mLayoutAttachedToWindow) {
- hide(false);
- }
mDismissView.setTag(stringRes);
mLayout.setTag(stringRes);
mTextView.setText(stringRes);
// Only show in portrait.
int orientation = mContext.getResources().getConfiguration().orientation;
- if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
mWindowManager.addView(mLayout, getWindowLayoutParams());
@@ -322,7 +325,7 @@
.alpha(1f)
.withLayer()
.setStartDelay(SHOW_DELAY_MS)
- .setDuration(SHOW_HIDE_DURATION_MS)
+ .setDuration(SHOW_DURATION_MS)
.setInterpolator(new DecelerateInterpolator())
.start();
}
@@ -344,7 +347,8 @@
mLayout.animate()
.alpha(0f)
.withLayer()
- .setDuration(SHOW_HIDE_DURATION_MS)
+ .setStartDelay(0)
+ .setDuration(HIDE_DURATION_MS)
.setInterpolator(new AccelerateInterpolator())
.withEndAction(() -> mWindowManager.removeViewImmediate(mLayout))
.start();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c8ee8735..6d677ab 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -180,16 +180,20 @@
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
+ final DividerSnapAlgorithm snapAlgorithm = getSnapAlgorithm();
if (isHorizontalDivision()) {
info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
mContext.getString(R.string.accessibility_action_divider_top_full)));
- if (mSnapAlgorithm.isFirstSplitTargetAvailable()) {
+ if (snapAlgorithm.isFirstSplitTargetAvailable()) {
info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
mContext.getString(R.string.accessibility_action_divider_top_70)));
}
- info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
+ if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
+ // Only show the middle target if there are more than 1 split target
+ info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
mContext.getString(R.string.accessibility_action_divider_top_50)));
- if (mSnapAlgorithm.isLastSplitTargetAvailable()) {
+ }
+ if (snapAlgorithm.isLastSplitTargetAvailable()) {
info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
mContext.getString(R.string.accessibility_action_divider_top_30)));
}
@@ -198,13 +202,16 @@
} else {
info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
mContext.getString(R.string.accessibility_action_divider_left_full)));
- if (mSnapAlgorithm.isFirstSplitTargetAvailable()) {
+ if (snapAlgorithm.isFirstSplitTargetAvailable()) {
info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
mContext.getString(R.string.accessibility_action_divider_left_70)));
}
- info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
+ if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
+ // Only show the middle target if there are more than 1 split target
+ info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
mContext.getString(R.string.accessibility_action_divider_left_50)));
- if (mSnapAlgorithm.isLastSplitTargetAvailable()) {
+ }
+ if (snapAlgorithm.isLastSplitTargetAvailable()) {
info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
mContext.getString(R.string.accessibility_action_divider_left_30)));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 8b6b5fe..364ed80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -581,7 +581,7 @@
}
}
- private void setBackgroundTintColor(int color) {
+ protected void setBackgroundTintColor(int color) {
if (color != mCurrentBackgroundTint) {
mCurrentBackgroundTint = color;
if (color == mNormalColor) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8adf4bc..991b47e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -469,6 +469,7 @@
updateNotificationColor();
if (mMenuRow != null) {
mMenuRow.onNotificationUpdated(mStatusBarNotification);
+ mMenuRow.setAppName(mAppName);
}
if (mIsSummaryWithChildren) {
mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
@@ -1089,6 +1090,15 @@
}
}
+ @Override
+ protected void setBackgroundTintColor(int color) {
+ super.setBackgroundTintColor(color);
+ NotificationContentView view = getShowingLayout();
+ if (view != null) {
+ view.setBackgroundTintColor(color);
+ }
+ }
+
public void closeRemoteInput() {
for (NotificationContentView l : mLayouts) {
l.closeRemoteInput();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
index 20e5f86..1b613cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
@@ -23,8 +23,10 @@
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.notification.NotificationCounters;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.Collections;
@@ -97,6 +99,9 @@
// We don't care about the touch origin (x, y) since we're opening guts without any
// explicit user interaction.
manager.openGuts(mBlockingHelperRow, 0, 0, menuRow.getLongpressMenuItem(mContext));
+
+ Dependency.get(MetricsLogger.class)
+ .count(NotificationCounters.BLOCKING_HELPER_SHOWN, 1);
return true;
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 285f639..8fa1b67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -887,6 +887,12 @@
mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
}
+ public void setBackgroundTintColor(int color) {
+ if (mExpandedSmartReplyView != null) {
+ mExpandedSmartReplyView.setBackgroundTintColor(color);
+ }
+ }
+
public int getVisibleType() {
return mVisibleType;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index dff5f38..46600cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -372,7 +372,7 @@
@Override
public void run() {
if (row.getWindowToken() == null) {
- Log.e(TAG, "Trying to show notification guts, but not attached to "
+ Log.e(TAG, "Trying to show notification guts in post(), but not attached to "
+ "window");
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index ec49f43..98e9268 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -91,22 +91,24 @@
private boolean mIsForBlockingHelper;
private boolean mNegativeUserSentiment;
- /** Counter tag that describes how the user exit or quit out of this view. */
- private String mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+ /**
+ * String that describes how the user exit or quit out of this view, also used as a counter tag.
+ */
+ private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
private OnClickListener mOnKeepShowing = v -> {
- mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+ mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
closeControls(v);
};
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
- mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
+ mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
swapContent(false);
};
private OnClickListener mOnUndo = v -> {
// Reset exit counter that we'll log and record an undo event separately (not an exit event)
- mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+ mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
swapContent(true);
};
@@ -197,8 +199,6 @@
bindHeader();
bindPrompt();
bindButtons();
-
- logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_SHOWN);
}
private void bindHeader() throws RemoteException {
@@ -300,7 +300,9 @@
private void saveImportance() {
if (!mIsNonblockable) {
- if (mCheckSaveListener != null) {
+ // Only go through the lock screen/bouncer if the user didn't hit 'Keep showing'.
+ if (mCheckSaveListener != null
+ && !NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING.equals(mExitReason)) {
mCheckSaveListener.checkSave(this::updateImportance, mSbn);
} else {
updateImportance();
@@ -495,7 +497,7 @@
if (save) {
saveImportance();
}
- logBlockingHelperCounter(mExitReasonCounter);
+ logBlockingHelperCounter(mExitReason);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 19980a2..04c500f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar;
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
@@ -24,10 +27,14 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.settingslib.graph.SignalDrawable;
@@ -35,10 +42,14 @@
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
-public class StatusBarMobileView extends AlphaOptimizedLinearLayout implements DarkReceiver,
+public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
StatusIconDisplayable {
private static final String TAG = "StatusBarMobileView";
+ /// Used to show etc dots
+ private StatusBarIconView mDotView;
+ /// The main icon view
+ private LinearLayout mMobileGroup;
private String mSlot;
private MobileIconState mState;
private SignalDrawable mMobileDrawable;
@@ -47,12 +58,17 @@
private ImageView mOut;
private ImageView mMobile, mMobileType, mMobileRoaming;
private View mMobileRoamingSpace;
+ private int mVisibleState = -1;
- public static StatusBarMobileView fromContext(Context context) {
+ public static StatusBarMobileView fromContext(Context context, String slot) {
LayoutInflater inflater = LayoutInflater.from(context);
-
- return (StatusBarMobileView)
+ StatusBarMobileView v = (StatusBarMobileView)
inflater.inflate(R.layout.status_bar_mobile_signal_group, null);
+
+ v.setSlot(slot);
+ v.init();
+ v.setVisibleState(STATE_ICON);
+ return v;
}
public StatusBarMobileView(Context context) {
@@ -72,14 +88,8 @@
super(context, attrs, defStyleAttr, defStyleRes);
}
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- init();
- }
-
private void init() {
+ mMobileGroup = findViewById(R.id.mobile_group);
mMobile = findViewById(R.id.mobile_signal);
mMobileType = findViewById(R.id.mobile_type);
mMobileRoaming = findViewById(R.id.mobile_roaming);
@@ -90,6 +100,18 @@
mMobileDrawable = new SignalDrawable(getContext());
mMobile.setImageDrawable(mMobileDrawable);
+
+ initDotView();
+ }
+
+ private void initDotView() {
+ mDotView = new StatusBarIconView(mContext, mSlot, null);
+ mDotView.setVisibleState(STATE_DOT);
+
+ int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size);
+ LayoutParams lp = new LayoutParams(width, width);
+ lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
+ addView(mDotView, lp);
}
public void applyMobileState(MobileIconState state) {
@@ -113,9 +135,9 @@
private void initViewState() {
setContentDescription(mState.contentDescription);
if (!mState.visible) {
- setVisibility(View.GONE);
+ mMobileGroup.setVisibility(View.GONE);
} else {
- setVisibility(View.VISIBLE);
+ mMobileGroup.setVisibility(View.VISIBLE);
}
mMobileDrawable.setLevel(mState.strengthId);
if (mState.typeId > 0) {
@@ -137,7 +159,7 @@
private void updateState(MobileIconState state) {
setContentDescription(state.contentDescription);
if (mState.visible != state.visible) {
- setVisibility(state.visible ? View.VISIBLE : View.GONE);
+ mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
}
if (mState.strengthId != state.strengthId) {
mMobileDrawable.setLevel(state.strengthId);
@@ -173,6 +195,8 @@
mOut.setImageTintList(color);
mMobileType.setImageTintList(color);
mMobileRoaming.setImageTintList(color);
+ mDotView.setDecorColor(tint);
+ mDotView.setIconColor(tint, false);
}
@Override
@@ -194,11 +218,12 @@
mOut.setImageTintList(list);
mMobileType.setImageTintList(list);
mMobileRoaming.setImageTintList(list);
+ mDotView.setDecorColor(color);
}
@Override
public void setDecorColor(int color) {
- //TODO: May also not be needed
+ mDotView.setDecorColor(color);
}
@Override
@@ -208,12 +233,30 @@
@Override
public void setVisibleState(int state) {
- //TODO: May not be needed. Mobile is always expected to be visible (not a dot)
+ if (state == mVisibleState) {
+ return;
+ }
+
+ mVisibleState = state;
+ switch (state) {
+ case STATE_ICON:
+ mMobileGroup.setVisibility(View.VISIBLE);
+ mDotView.setVisibility(View.GONE);
+ break;
+ case STATE_DOT:
+ mMobileGroup.setVisibility(View.INVISIBLE);
+ mDotView.setVisibility(View.VISIBLE);
+ break;
+ case STATE_HIDDEN:
+ default:
+ setVisibility(View.INVISIBLE);
+ break;
+ }
}
@Override
public int getVisibleState() {
- return 0;
+ return mVisibleState;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
index 3975ec2..a096508 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
@@ -151,6 +151,17 @@
return reusableView;
}
+ public TextView bindOverflowNumberAmbient(TextView titleView, Notification notification,
+ int number) {
+ String text = mContext.getResources().getString(
+ R.string.notification_group_overflow_indicator_ambient,
+ resolveTitle(notification), number);
+ if (!text.equals(titleView.getText())) {
+ titleView.setText(text);
+ }
+ return titleView;
+ }
+
public void setOverflowNumberDark(TextView view, boolean dark, boolean fade, long delay) {
mDozer.setIntensityDark((f)->{
mDarkAmount = f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 46b4078..e0e991b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -237,9 +237,8 @@
public void addMobileView(MobileIconState state) {
Log.d(TAG, "addMobileView: ");
- StatusBarMobileView view = StatusBarMobileView.fromContext(mContext);
+ StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, state.slot);
- view.setSlot(state.slot);
view.applyMobileState(state);
view.setStaticDrawableColor(mColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index f134151..48eb3e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -76,7 +76,7 @@
protected KeyguardHostView mKeyguardView;
private final Runnable mResetRunnable = ()-> {
if (mKeyguardView != null) {
- mKeyguardView.reset();
+ mKeyguardView.resetSecurityContainer();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 533d5ec..98f9f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -88,6 +88,7 @@
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
final static boolean DEBUG = false;
@@ -116,6 +117,7 @@
private Rect mHomeButtonBounds = new Rect();
private Rect mBackButtonBounds = new Rect();
private Rect mRecentsButtonBounds = new Rect();
+ private Rect mRotationButtonBounds = new Rect();
private int[] mTmpPosition = new int[2];
private KeyButtonDrawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
@@ -341,6 +343,8 @@
mDownHitTarget = HIT_TARGET_HOME;
} else if (mRecentsButtonBounds.contains(x, y)) {
mDownHitTarget = HIT_TARGET_OVERVIEW;
+ } else if (mRotationButtonBounds.contains(x, y)) {
+ mDownHitTarget = HIT_TARGET_ROTATION;
}
break;
}
@@ -893,6 +897,7 @@
updateButtonLocationOnScreen(getBackButton(), mBackButtonBounds);
updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
updateButtonLocationOnScreen(getRecentsButton(), mRecentsButtonBounds);
+ updateButtonLocationOnScreen(getRotateSuggestionButton(), mRotationButtonBounds);
mGestureHelper.onLayout(changed, left, top, right, bottom);
mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 061677c..65cb56c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -249,7 +249,7 @@
public class StatusBar extends SystemUI implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
- OnHeadsUpChangedListener, CommandQueue.Callbacks,
+ OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
public static final boolean MULTIUSER_DEBUG = false;
@@ -785,12 +785,7 @@
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
- mZenController.addCallback(new ZenModeController.Callback() {
- @Override
- public void onZenChanged(int zen) {
- updateEmptyShadeView();
- }
- });
+ mZenController.addCallback(this);
mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
this,
mNotificationPanel,
@@ -3376,6 +3371,7 @@
Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
mDeviceProvisionedController.removeCallback(mUserSetupObserver);
Dependency.get(ConfigurationController.class).removeCallback(this);
+ mZenController.removeCallback(this);
mAppOpsListener.destroy();
}
@@ -5536,6 +5532,11 @@
}
@Override
+ public void onZenChanged(int zen) {
+ updateEmptyShadeView();
+ }
+
+ @Override
public void showAssistDisclosure() {
if (mAssistManager != null) {
mAssistManager.showDisclosure();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 1ba37a9..3b9ee8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -296,8 +296,7 @@
}
private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
- StatusBarMobileView view = StatusBarMobileView.fromContext(mContext);
- view.setSlot(slot);
+ StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot);
return view;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 4538977..0811179 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -49,7 +49,7 @@
private static final String TAG = "StatusIconContainer";
private static final boolean DEBUG = false;
private static final boolean DEBUG_OVERFLOW = false;
- // Max 5 status icons including battery
+ // Max 8 status icons including battery
private static final int MAX_ICONS = 7;
private static final int MAX_DOTS = 1;
@@ -152,7 +152,7 @@
int visibleCount = mMeasureViews.size();
int maxVisible = visibleCount <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;
- int totalWidth = getPaddingStart() + getPaddingEnd();
+ int totalWidth = mPaddingLeft + mPaddingRight;
boolean trackWidth = true;
// Measure all children so that they report the correct width
@@ -208,8 +208,8 @@
*/
private void calculateIconTranslations() {
mLayoutStates.clear();
- float width = getWidth() - getPaddingEnd();
- float translationX = width;
+ float width = getWidth();
+ float translationX = width - getPaddingEnd();
float contentStart = getPaddingStart();
int childCount = getChildCount();
// Underflow === don't show content until that index
@@ -344,10 +344,11 @@
animate = true;
}
- icon.setVisibleState(visibleState);
if (animate) {
animateTo(view, animationProperties);
+ icon.setVisibleState(visibleState);
} else {
+ icon.setVisibleState(visibleState);
super.applyToView(view);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 59bf982..310f14c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -565,6 +565,11 @@
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+ //if pinned, set imeOption to keep the behavior like in portrait.
+ if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isPinned()) {
+ outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI
+ | EditorInfo.IME_FLAG_NO_FULLSCREEN;
+ }
if (mShowImeOnInputConnection && inputConnection != null) {
final InputMethodManager imm = InputMethodManager.getInstance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 351868d..c279e63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -1,12 +1,17 @@
package com.android.systemui.statusbar.policy;
+import android.annotation.ColorInt;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
import android.content.Intent;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.RippleDrawable;
import android.os.Bundle;
import android.text.Layout;
@@ -22,6 +27,7 @@
import android.widget.Button;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.NotificationColorUtil;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -75,6 +81,23 @@
private View mSmartReplyContainer;
+ @ColorInt
+ private int mCurrentBackgroundColor;
+ @ColorInt
+ private final int mDefaultBackgroundColor;
+ @ColorInt
+ private final int mDefaultStrokeColor;
+ @ColorInt
+ private final int mDefaultTextColor;
+ @ColorInt
+ private final int mDefaultTextColorDarkBg;
+ @ColorInt
+ private final int mRippleColorDarkBg;
+ @ColorInt
+ private final int mRippleColor;
+ private final int mStrokeWidth;
+ private final double mMinStrokeContrast;
+
public SmartReplyView(Context context, AttributeSet attrs) {
super(context, attrs);
mConstants = Dependency.get(SmartReplyConstants.class);
@@ -83,9 +106,21 @@
mHeightUpperLimit = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.smart_reply_button_max_height);
+ mCurrentBackgroundColor = context.getColor(R.color.smart_reply_button_background);
+ mDefaultBackgroundColor = mCurrentBackgroundColor;
+ mDefaultTextColor = mContext.getColor(R.color.smart_reply_button_text);
+ mDefaultTextColorDarkBg = mContext.getColor(R.color.smart_reply_button_text_dark_bg);
+ mDefaultStrokeColor = mContext.getColor(R.color.smart_reply_button_stroke);
+ mRippleColor = mContext.getColor(R.color.notification_ripple_untinted_color);
+ mRippleColorDarkBg = Color.argb(Color.alpha(mRippleColor),
+ 255 /* red */, 255 /* green */, 255 /* blue */);
+ mMinStrokeContrast = NotificationColorUtil.calculateContrast(mDefaultStrokeColor,
+ mDefaultBackgroundColor);
+
int spacing = 0;
int singleLineButtonPaddingHorizontal = 0;
int doubleLineButtonPaddingHorizontal = 0;
+ int strokeWidth = 0;
final TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SmartReplyView,
0, 0);
@@ -102,10 +137,14 @@
case R.styleable.SmartReplyView_doubleLineButtonPaddingHorizontal:
doubleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
break;
+ case R.styleable.SmartReplyView_buttonStrokeWidth:
+ strokeWidth = arr.getDimensionPixelSize(i, 0);
+ break;
}
}
arr.recycle();
+ mStrokeWidth = strokeWidth;
mSpacing = spacing;
mSingleLineButtonPaddingHorizontal = singleLineButtonPaddingHorizontal;
mDoubleLineButtonPaddingHorizontal = doubleLineButtonPaddingHorizontal;
@@ -139,6 +178,7 @@
View smartReplyContainer) {
mSmartReplyContainer = smartReplyContainer;
removeAllViews();
+ mCurrentBackgroundColor = mDefaultBackgroundColor;
if (remoteInput != null && pendingIntent != null) {
CharSequence[] choices = remoteInput.getChoices();
if (choices != null) {
@@ -194,6 +234,7 @@
}
});
+ setColors(b, mCurrentBackgroundColor, mDefaultStrokeColor, mDefaultTextColor, mRippleColor);
return b;
}
@@ -523,6 +564,51 @@
return lp.show && super.drawChild(canvas, child, drawingTime);
}
+ public void setBackgroundTintColor(int backgroundColor) {
+ if (backgroundColor == mCurrentBackgroundColor) {
+ // Same color ignoring.
+ return;
+ }
+ mCurrentBackgroundColor = backgroundColor;
+
+ final boolean dark = !NotificationColorUtil.isColorLight(backgroundColor);
+
+ int textColor = NotificationColorUtil.ensureTextContrast(
+ dark ? mDefaultTextColorDarkBg : mDefaultTextColor,
+ backgroundColor | 0xff000000, dark);
+ int strokeColor = NotificationColorUtil.ensureContrast(
+ mDefaultStrokeColor, backgroundColor | 0xff000000, dark, mMinStrokeContrast);
+ int rippleColor = dark ? mRippleColorDarkBg : mRippleColor;
+
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final Button child = (Button) getChildAt(i);
+ setColors(child, backgroundColor, strokeColor, textColor, rippleColor);
+ }
+ }
+
+ private void setColors(Button button, int backgroundColor, int strokeColor, int textColor,
+ int rippleColor) {
+ Drawable drawable = button.getBackground();
+ if (drawable instanceof RippleDrawable) {
+ // Mutate in case other notifications are using this drawable.
+ drawable = drawable.mutate();
+ RippleDrawable ripple = (RippleDrawable) drawable;
+ ripple.setColor(ColorStateList.valueOf(rippleColor));
+ Drawable inset = ripple.getDrawable(0);
+ if (inset instanceof InsetDrawable) {
+ Drawable background = ((InsetDrawable) inset).getDrawable();
+ if (background instanceof GradientDrawable) {
+ GradientDrawable gradientDrawable = (GradientDrawable) background;
+ gradientDrawable.setColor(backgroundColor);
+ gradientDrawable.setStroke(mStrokeWidth, strokeColor);
+ }
+ }
+ button.setBackground(drawable);
+ }
+ button.setTextColor(textColor);
+ }
+
@VisibleForTesting
static class LayoutParams extends ViewGroup.LayoutParams {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 339c115..2031b27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -36,6 +36,7 @@
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.qs.GlobalSetting;
@@ -112,6 +113,10 @@
@Override
public void addCallback(Callback callback) {
+ if (callback == null) {
+ Slog.e(TAG, "Attempted to add a null callback.");
+ return;
+ }
mCallbacks.add(callback);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 8115297..55ec142 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -52,7 +52,7 @@
private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
- private static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 3;
+ private static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 1;
private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() {
private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
@@ -208,9 +208,9 @@
// We need to measure all children even the GONE ones, such that the heights are
// calculated correctly as they are used to calculate how many we can fit on the screen.
boolean isOverflow = i == overflowIndex;
- child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null
- ? mOverflowNumber.getMeasuredWidth()
- : 0);
+ child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null &&
+ !mContainingNotification.isShowingAmbient()
+ ? mOverflowNumber.getMeasuredWidth() : 0);
child.measure(widthMeasureSpec, newHeightSpec);
// layout the divider
View divider = mDividers.get(i);
@@ -394,8 +394,19 @@
int childCount = mChildren.size();
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
if (childCount > maxAllowedVisibleChildren) {
- mOverflowNumber = mHybridGroupManager.bindOverflowNumber(
- mOverflowNumber, childCount - maxAllowedVisibleChildren);
+ int number = childCount - maxAllowedVisibleChildren;
+ mOverflowNumber = mHybridGroupManager.bindOverflowNumber(mOverflowNumber, number);
+ if (mContainingNotification.isShowingAmbient()) {
+ ExpandableNotificationRow overflowView = mChildren.get(0);
+ HybridNotificationView ambientSingleLineView = overflowView == null ? null
+ : overflowView.getAmbientSingleLineView();
+ if (ambientSingleLineView != null) {
+ mHybridGroupManager.bindOverflowNumberAmbient(
+ ambientSingleLineView.getTitleView(),
+ mContainingNotification.getStatusBarNotification().getNotification(),
+ number);
+ }
+ }
if (mGroupOverFlowState == null) {
mGroupOverFlowState = new ViewState();
mNeverAppliedGroupState = true;
@@ -617,16 +628,13 @@
}
if (mOverflowNumber != null) {
ExpandableNotificationRow overflowView = mChildren.get(Math.min(
- getMaxAllowedVisibleChildren(true /* likeCollpased */), childCount) - 1);
+ getMaxAllowedVisibleChildren(true /* likeCollapsed */), childCount) - 1);
mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
- if (mContainingNotification.isShowingAmbient() || !mChildrenExpanded) {
- HybridNotificationView alignView = null;
- if (mContainingNotification.isShowingAmbient()) {
- alignView = overflowView.getAmbientSingleLineView();
- } else if (mUserLocked) {
- alignView = overflowView.getSingleLineView();
- }
+ if (mContainingNotification.isShowingAmbient()) {
+ mGroupOverFlowState.alpha = 0.0f;
+ } else if (!mChildrenExpanded) {
+ HybridNotificationView alignView = overflowView.getSingleLineView();
if (alignView != null) {
View mirrorView = alignView.getTextView();
if (mirrorView.getVisibility() == GONE) {
@@ -635,9 +643,9 @@
if (mirrorView.getVisibility() == GONE) {
mirrorView = alignView;
}
+ mGroupOverFlowState.alpha = mirrorView.getAlpha();
mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(
mirrorView, overflowView);
- mGroupOverFlowState.alpha = mirrorView.getAlpha();
}
} else {
mGroupOverFlowState.yTranslation += mNotificationHeaderMargin;
@@ -881,6 +889,7 @@
public void notifyShowAmbientChanged() {
updateHeaderVisibility(false);
+ updateGroupOverflow();
}
private void updateHeaderVisibility(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 5deebff..176905a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -112,7 +112,6 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.function.BiConsumer;
/**
@@ -4078,23 +4077,20 @@
int newVisibility = visible ? VISIBLE : GONE;
boolean changedVisibility = oldVisibility != newVisibility;
- if (changedVisibility || newVisibility != GONE) {
+ if (changedVisibility) {
if (newVisibility != GONE) {
- int oldText = mEmptyShadeView.getTextResource();
- int newText;
- if (mStatusBar.areNotificationsHidden()) {
- newText = R.string.dnd_suppressing_shade_text;
- } else {
- newText = R.string.empty_shade_text;
- }
- if (changedVisibility || !Objects.equals(oldText, newText)) {
- mEmptyShadeView.setText(newText);
- showFooterView(mEmptyShadeView);
- }
+ showFooterView(mEmptyShadeView);
} else {
hideFooterView(mEmptyShadeView, true);
}
}
+
+ int oldTextRes = mEmptyShadeView.getTextResource();
+ int newTextRes = mStatusBar.areNotificationsHidden()
+ ? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text;
+ if (oldTextRes != newTextRes) {
+ mEmptyShadeView.setText(newTextRes);
+ }
}
public void updateFooterView(boolean visible, boolean showDismissView) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
index b3dddd5..a6d87af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
@@ -20,6 +20,7 @@
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import android.content.Context;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -29,6 +30,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -48,6 +50,7 @@
* Tests for {@link NotificationBlockingHelperManager}.
*/
@SmallTest
+@FlakyTest
@org.junit.runner.RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
@@ -56,7 +59,6 @@
private NotificationTestHelper mHelper;
- @Rule public MockitoRule mockito = MockitoJUnit.rule();
@Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationEntryManager mEntryManager;
@Mock private NotificationMenuRow mMenuRow;
@@ -64,20 +66,22 @@
@Before
public void setUp() {
- mBlockingHelperManager = new NotificationBlockingHelperManager(mContext);
- // By default, have the shade visible/expanded.
- mBlockingHelperManager.setNotificationShadeExpanded(1f);
-
- mHelper = new NotificationTestHelper(mContext);
+ MockitoAnnotations.initMocks(this);
when(mGutsManager.openGuts(
any(View.class),
anyInt(),
anyInt(),
any(NotificationMenuRowPlugin.MenuItem.class)))
.thenReturn(true);
+ when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
mDependency.injectTestDependency(NotificationGutsManager.class, mGutsManager);
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
- when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
+
+ mHelper = new NotificationTestHelper(mContext);
+
+ mBlockingHelperManager = new NotificationBlockingHelperManager(mContext);
+ // By default, have the shade visible/expanded.
+ mBlockingHelperManager.setNotificationShadeExpanded(1f);
}
@Test
@@ -89,7 +93,7 @@
@Test
public void testDismissCurrentBlockingHelper_withDetachedBlockingHelperRow() throws Exception {
- ExpandableNotificationRow row = spy(createBlockableRowSpy());
+ ExpandableNotificationRow row = createBlockableRowSpy();
row.setBlockingHelperShowing(true);
when(row.isAttachedToWindow()).thenReturn(false);
mBlockingHelperManager.setBlockingHelperRowForTest(row);
@@ -102,7 +106,7 @@
@Test
public void testDismissCurrentBlockingHelper_withAttachedBlockingHelperRow() throws Exception {
- ExpandableNotificationRow row = spy(createBlockableRowSpy());
+ ExpandableNotificationRow row = createBlockableRowSpy();
row.setBlockingHelperShowing(true);
when(row.isAttachedToWindow()).thenReturn(true);
mBlockingHelperManager.setBlockingHelperRowForTest(row);
@@ -200,7 +204,7 @@
@Test
public void testBlockingHelperShowAndDismiss() throws Exception{
- ExpandableNotificationRow row = spy(createBlockableRowSpy());
+ ExpandableNotificationRow row = createBlockableRowSpy();
row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
when(row.isAttachedToWindow()).thenReturn(true);
@@ -227,6 +231,4 @@
when(row.getIsNonblockable()).thenReturn(false);
return row;
}
-
-
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 65fd7f5..bdeb8bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -314,12 +314,11 @@
@Test
public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
- // Bind notification logs an event, so this counts as one invocation for the metrics logger.
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
true);
mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
- verify(mMetricsLogger, times(2)).count(anyString(), anyInt());
+ verify(mMetricsLogger, times(1)).count(anyString(), anyInt());
}
@Test
@@ -509,6 +508,36 @@
anyString(), eq(TEST_UID), eq(true));
}
+
+ @Test
+ public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing()
+ throws Exception {
+ NotificationInfo.CheckSaveListener listener =
+ mock(NotificationInfo.CheckSaveListener.class);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
+ 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
+ null /* onSettingsClick */, null /* onAppSettingsClick */ ,
+ false /* isNonblockable */, true /* isForBlockingHelper */,
+ true /* isUserSentimentNegative */);
+
+ NotificationGuts guts = spy(new NotificationGuts(mContext, null));
+ when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
+ doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
+ doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
+ guts.setGutsContent(mNotificationInfo);
+ mNotificationInfo.setGutsParent(guts);
+
+ mNotificationInfo.findViewById(R.id.keep).performClick();
+
+ verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
+ mTestableLooper.processAllMessages();
+ verify(mMockINotificationManager, times(1))
+ .setNotificationsEnabledWithImportanceLockForPackage(
+ anyString(), eq(TEST_UID), eq(true));
+ }
+
+
@Test
public void testCloseControls_blockingHelperDismissedIfShown() throws Exception {
mNotificationInfo.bindNotification(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index da8017e..ff65587 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -105,4 +105,10 @@
assertTrue(mController.areNotificationsHiddenInShade());
}
-}
\ No newline at end of file
+
+ @Test
+ public void testAddNullCallback() {
+ mController.addCallback(null);
+ mController.fireConfigChanged(null);
+ }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 1541231..7c05b2b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5818,6 +5818,16 @@
// Tag used to report whether an activity is being autofilled on compatibility mode.
FIELD_AUTOFILL_COMPAT_MODE = 1414;
+ // OPEN: Settings > Sound > Switch a2dp devices dialog
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_SWITCH_A2DP_DEVICES = 1415;
+
+ // OPEN: Settings > Sound > Switch hfp devices dialog
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_SWITCH_HFP_DEVICES = 1416;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 85b0220..f992049 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -568,8 +568,9 @@
Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
UserHandle.of(providerUserId));
PackageManager pm = userContext.getPackageManager();
- Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
+ Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm).mutate();
// Create a bitmap of the icon which is what the widget's remoteview requires.
+ icon.setColorFilter(mIconUtilities.getDisabledColorFilter());
return mIconUtilities.createIconBitmap(icon);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Fail to get application icon", e);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 51c0488..9b833f7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -157,6 +157,9 @@
}
};
+ @GuardedBy("mLock")
+ private boolean mAllowInstantService;
+
public AutofillManagerService(Context context) {
super(context);
mContext = context;
@@ -518,6 +521,23 @@
sFullScreenMode = mode;
}
+ // Called by Shell command.
+ boolean getAllowInstantService() {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+ synchronized (mLock) {
+ return mAllowInstantService;
+ }
+ }
+
+ // Called by Shell command.
+ void setAllowInstantService(boolean mode) {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+ Slog.i(TAG, "setAllowInstantService(): " + mode);
+ synchronized (mLock) {
+ mAllowInstantService = mode;
+ }
+ }
+
private void setDebugLocked(boolean debug) {
com.android.server.autofill.Helper.sDebug = debug;
android.view.autofill.Helper.sDebug = debug;
@@ -866,7 +886,8 @@
synchronized (mLock) {
final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
- autofillId, bounds, value, hasCallback, flags, componentName, compatMode);
+ autofillId, bounds, value, hasCallback, componentName, compatMode,
+ mAllowInstantService, flags);
}
}
@@ -1202,6 +1223,7 @@
mAutofillCompatState.dump(prefix2, pw);
pw.print(prefix2); pw.print("from settings: ");
pw.println(getWhitelistedCompatModePackagesFromSettings());
+ pw.print("Allow instant service: "); pw.println(mAllowInstantService);
}
if (showHistory) {
pw.println(); pw.println("Requests history:"); pw.println();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 6ff9539..d97253e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -32,6 +32,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
@@ -341,7 +342,8 @@
int startSessionLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
@NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
- int flags, @NonNull ComponentName componentName, boolean compatMode) {
+ @NonNull ComponentName componentName, boolean compatMode,
+ boolean bindInstantServiceAllowed, int flags) {
if (!isEnabledLocked()) {
return 0;
}
@@ -371,7 +373,7 @@
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
- hasCallback, componentName, compatMode, flags);
+ hasCallback, componentName, compatMode, bindInstantServiceAllowed, flags);
if (newSession == null) {
return NO_SESSION;
}
@@ -490,7 +492,8 @@
@GuardedBy("mLock")
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
@NonNull IBinder appCallbackToken, boolean hasCallback,
- @NonNull ComponentName componentName, boolean compatMode, int flags) {
+ @NonNull ComponentName componentName, boolean compatMode,
+ boolean bindInstantServiceAllowed, int flags) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -509,7 +512,7 @@
final Session newSession = new Session(this, mUi, mContext, mHandler, mUserId, mLock,
sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode,
- flags);
+ bindInstantServiceAllowed, flags);
mSessions.put(newSession.id, newSession);
return newSession;
@@ -667,7 +670,10 @@
@NonNull
CharSequence getServiceLabel() {
- return mInfo.getServiceInfo().loadLabel(mContext.getPackageManager());
+ final CharSequence label = mInfo.getServiceInfo().loadSafeLabel(
+ mContext.getPackageManager(), 0 /* do not ellipsize */,
+ PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
+ return label;
}
@NonNull
@@ -912,6 +918,7 @@
} else {
pw.println();
mInfo.dump(prefix2, pw);
+ pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabel());
}
pw.print(prefix); pw.print("Component from settings: ");
pw.println(getComponentNameFromSettings());
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index c76c8ac..f7b7ceb4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -86,6 +86,9 @@
pw.println(" get fc_score [--algorithm ALGORITHM] value1 value2");
pw.println(" Gets the field classification score for 2 fields.");
pw.println("");
+ pw.println(" get bind-instant-service-allowed");
+ pw.println(" Gets whether binding to services provided by instant apps is allowed");
+ pw.println("");
pw.println(" set log_level [off | debug | verbose]");
pw.println(" Sets the Autofill log level.");
pw.println("");
@@ -98,6 +101,9 @@
pw.println(" set full_screen_mode [true | false | default]");
pw.println(" Sets the Fill UI full screen mode");
pw.println("");
+ pw.println(" set bind-instant-service-allowed [true | false]");
+ pw.println(" Sets whether binding to services provided by instant apps is allowed");
+ pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" Lists all pending sessions.");
pw.println("");
@@ -123,6 +129,8 @@
return getFieldClassificationScore(pw);
case "full_screen_mode":
return getFullScreenMode(pw);
+ case "bind-instant-service-allowed":
+ return getBindInstantService(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -141,6 +149,8 @@
return setMaxVisibileDatasets();
case "full_screen_mode":
return setFullScreenMode(pw);
+ case "bind-instant-service-allowed":
+ return setBindInstantService(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -259,6 +269,30 @@
}
}
+ private int getBindInstantService(PrintWriter pw) {
+ if (mService.getAllowInstantService()) {
+ pw.println("true");
+ } else {
+ pw.println("false");
+ }
+ return 0;
+ }
+
+ private int setBindInstantService(PrintWriter pw) {
+ final String mode = getNextArgRequired();
+ switch (mode.toLowerCase()) {
+ case "true":
+ mService.setAllowInstantService(true);
+ return 0;
+ case "false":
+ mService.setAllowInstantService(false);
+ return 0;
+ default:
+ pw.println("Invalid mode: " + mode);
+ return -1;
+ }
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
index 9bec856..ba544f1 100644
--- a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
+++ b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
@@ -15,8 +15,6 @@
*/
package com.android.server.autofill;
-import static android.view.autofill.AutofillManager.FC_SERVICE_TIMEOUT;
-
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import static android.service.autofill.AutofillFieldClassificationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS;
@@ -52,8 +50,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
/**
* Strategy used to bridge the field classification algorithms provided by a service in an external
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 5372d0c..f781013 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -68,6 +68,9 @@
/**
* When non-null, overrides whether the UI should be shown on full-screen mode.
+ *
+ * <p>Note: access to this variable is not synchronized because it's "final" on real usage -
+ * it's only set by Shell cmd, for development purposes.
*/
public static Boolean sFullScreenMode = null;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index f7a4b73..4ded3fe 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -84,6 +84,8 @@
private final Handler mHandler;
+ private final boolean mBindInstantServiceAllowed;
+
private IAutoFillService mAutoFillService;
private boolean mBinding;
@@ -109,13 +111,14 @@
}
public RemoteFillService(Context context, ComponentName componentName,
- int userId, FillServiceCallbacks callbacks) {
+ int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) {
mContext = context;
mCallbacks = callbacks;
mComponentName = componentName;
mIntent = new Intent(AutofillService.SERVICE_INTERFACE).setComponent(mComponentName);
mUserId = userId;
mHandler = new Handler(FgThread.getHandler().getLooper());
+ mBindInstantServiceAllowed = bindInstantServiceAllowed;
}
public void destroy() {
@@ -207,6 +210,7 @@
.append(String.valueOf(isBound())).println();
pw.append(prefix).append(tab).append("hasPendingRequest=")
.append(String.valueOf(mPendingRequest != null)).println();
+ pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
pw.println();
}
@@ -258,12 +262,17 @@
if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
mBinding = true;
- boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+ if (mBindInstantServiceAllowed) {
+ flags |= Context.BIND_ALLOW_INSTANT;
+ }
+
+ final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
new UserHandle(mUserId));
if (!willBind) {
- if (sDebug) Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent);
+ Slog.w(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent + " using flags "
+ + flags);
mBinding = false;
if (!mServiceDied) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 88a679b..73c7172 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -517,7 +517,7 @@
@NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
@NonNull LocalLog wtfHistory,
@NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
- boolean compatMode, int flags) {
+ boolean compatMode, boolean bindInstantServiceAllowed, int flags) {
id = sessionId;
mFlags = flags;
this.uid = uid;
@@ -526,7 +526,8 @@
mLock = lock;
mUi = ui;
mHandler = handler;
- mRemoteFillService = new RemoteFillService(context, serviceComponentName, userId, this);
+ mRemoteFillService = new RemoteFillService(context, serviceComponentName, userId, this,
+ bindInstantServiceAllowed);
mActivityToken = activityToken;
mHasCallback = hasCallback;
mUiLatencyHistory = uiLatencyHistory;
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 2a76055..cff1a84 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -18,7 +18,6 @@
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static com.android.server.autofill.Helper.sDebug;
-import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.Nullable;
import android.graphics.Rect;
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 5c5f0f8..0775abf 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3023,20 +3023,26 @@
}
private boolean isBackgroundRestricted(Alarm alarm) {
- final boolean allowWhileIdle = (alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0;
+ boolean exemptOnBatterySaver = (alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0;
if (alarm.alarmClock != null) {
- // Don't block alarm clocks
+ // Don't defer alarm clocks
return false;
}
- if (alarm.operation != null
- && (alarm.operation.isActivity() || alarm.operation.isForegroundService())) {
- // Don't block starting foreground components
- return false;
+ if (alarm.operation != null) {
+ if (alarm.operation.isActivity()) {
+ // Don't defer starting actual UI
+ return false;
+ }
+ if (alarm.operation.isForegroundService()) {
+ // FG service alarms are nearly as important; consult AST policy
+ exemptOnBatterySaver = true;
+ }
}
final String sourcePackage = alarm.sourcePackage;
final int sourceUid = alarm.creatorUid;
return (mAppStateTracker != null) &&
- mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage, allowWhileIdle);
+ mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage,
+ exemptOnBatterySaver);
}
private native long init();
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 13503e6..7f26575 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -21,13 +21,16 @@
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
+import android.database.ContentObserver;
import android.media.AudioAttributes;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
@@ -43,9 +46,11 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManagerInternal;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.KeyValueListParser;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -109,9 +114,6 @@
// Write at most every 30 minutes.
static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
- // How long we want for a drop in uid state to settle before applying it.
- static final long STATE_SETTLE_TIME = 10*1000;
-
// Constant meaning that any UID should be matched when dispatching callbacks
private static final int UID_ANY = -2;
@@ -198,6 +200,75 @@
*/
private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
+ /**
+ * All times are in milliseconds. These constants are kept synchronized with the system
+ * global Settings. Any access to this class or its fields should be done while
+ * holding the AppOpsService lock.
+ */
+ private final class Constants extends ContentObserver {
+ // Key names stored in the settings value.
+ private static final String KEY_STATE_SETTLE_TIME = "state_settle_time";
+
+ /**
+ * How long we want for a drop in uid state to settle before applying it.
+ * @see Settings.Global#APP_OPS_CONSTANTS
+ * @see #KEY_STATE_SETTLE_TIME
+ */
+ public long STATE_SETTLE_TIME;
+
+
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+ private ContentResolver mResolver;
+
+ public Constants(Handler handler) {
+ super(handler);
+ updateConstants();
+ }
+
+ public void startMonitoring(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS),
+ false, this);
+ updateConstants();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (AppOpsService.this) {
+ try {
+ if (mResolver != null) {
+ mParser.setString(Settings.Global.getString(mResolver,
+ Settings.Global.APP_OPS_CONSTANTS));
+ } else {
+ mParser.setString("");
+ }
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad app ops settings", e);
+ }
+
+ STATE_SETTLE_TIME = mParser.getDurationMillis(
+ KEY_STATE_SETTLE_TIME, 10 * 1000L);
+ }
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(" Settings:");
+
+ pw.print(" "); pw.print(KEY_STATE_SETTLE_TIME); pw.print("=");
+ TimeUtils.formatDuration(STATE_SETTLE_TIME, pw);
+ pw.println();
+ }
+ }
+
+ private final Constants mConstants;
+
@VisibleForTesting
static final class UidState {
public final int uid;
@@ -210,7 +281,9 @@
public ArrayMap<String, Ops> pkgOps;
public SparseIntArray opModes;
+ // true indicates there is an interested observer, false there isn't but it has such an op
public SparseBooleanArray foregroundOps;
+ public boolean hasForegroundWatchers;
public UidState(int uid) {
this.uid = uid;
@@ -234,8 +307,35 @@
return mode;
}
- public void evalForegroundOps() {
+ private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
+ SparseBooleanArray which) {
+ boolean curValue = which.get(op, false);
+ ArraySet<ModeCallback> callbacks = watchers.get(op);
+ if (callbacks != null) {
+ for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
+ if ((callbacks.valueAt(cbi).mFlags
+ & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
+ hasForegroundWatchers = true;
+ curValue = true;
+ }
+ }
+ }
+ which.put(op, curValue);
+ }
+
+ public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
SparseBooleanArray which = null;
+ hasForegroundWatchers = false;
+ if (opModes != null) {
+ for (int i = opModes.size() - 1; i >= 0; i--) {
+ if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
+ if (which == null) {
+ which = new SparseBooleanArray();
+ }
+ evalForegroundWatchers(opModes.keyAt(i), watchers, which);
+ }
+ }
+ }
if (pkgOps != null) {
for (int i = pkgOps.size() - 1; i >= 0; i--) {
Ops ops = pkgOps.valueAt(i);
@@ -244,7 +344,7 @@
if (which == null) {
which = new SparseBooleanArray();
}
- which.put(ops.keyAt(j), true);
+ evalForegroundWatchers(ops.keyAt(j), watchers, which);
}
}
}
@@ -313,13 +413,15 @@
final class ModeCallback implements DeathRecipient {
final IAppOpsCallback mCallback;
final int mWatchingUid;
+ final int mFlags;
final int mCallingUid;
final int mCallingPid;
- ModeCallback(IAppOpsCallback callback, int watchingUid, int callingUid,
+ ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
int callingPid) {
mCallback = callback;
mWatchingUid = watchingUid;
+ mFlags = flags;
mCallingUid = callingUid;
mCallingPid = callingPid;
try {
@@ -328,6 +430,10 @@
}
}
+ public boolean isWatchingUid(int uid) {
+ return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
@@ -335,6 +441,8 @@
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" watchinguid=");
UserHandle.formatUid(sb, mWatchingUid);
+ sb.append(" flags=0x");
+ sb.append(Integer.toHexString(mFlags));
sb.append(" from uid=");
UserHandle.formatUid(sb, mCallingUid);
sb.append(" pid=");
@@ -439,6 +547,7 @@
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops");
mHandler = handler;
+ mConstants = new Constants(mHandler);
readState();
}
@@ -449,6 +558,7 @@
public void systemReady() {
synchronized (this) {
+ mConstants.startMonitoring(mContext.getContentResolver());
boolean changed = false;
for (int i = mUidStates.size() - 1; i >= 0; i--) {
UidState uidState = mUidStates.valueAt(i);
@@ -611,14 +721,16 @@
final UidState uidState = getUidStateLocked(uid, true);
final int newState = PROCESS_STATE_TO_UID_STATE[procState];
if (uidState != null && uidState.pendingState != newState) {
+ final int oldPendingState = uidState.pendingState;
+ uidState.pendingState = newState;
if (newState < uidState.state) {
// We are moving to a more important state, always do it immediately.
- uidState.state = newState;
- uidState.pendingStateCommitTime = 0;
+ commitUidPendingStateLocked(uidState);
} else if (uidState.pendingStateCommitTime == 0) {
// We are moving to a less important state for the first time,
// delay the application for a bit.
- uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + STATE_SETTLE_TIME;
+ uidState.pendingStateCommitTime = SystemClock.uptimeMillis() +
+ mConstants.STATE_SETTLE_TIME;
}
if (uidState.startNesting != 0) {
// There is some actively running operation... need to find it
@@ -629,13 +741,12 @@
for (int j = ops.size() - 1; j >= 0; j--) {
final Op op = ops.valueAt(j);
if (op.startNesting > 0) {
- op.time[uidState.pendingState] = now;
+ op.time[oldPendingState] = now;
op.time[newState] = now;
}
}
}
}
- uidState.pendingState = newState;
}
}
}
@@ -867,7 +978,9 @@
ModeCallback callback = callbacks.valueAt(i);
ArraySet<String> changedPackages = new ArraySet<>();
Collections.addAll(changedPackages, uidPackageNames);
- callbackSpecs = new ArrayMap<>();
+ if (callbackSpecs == null) {
+ callbackSpecs = new ArrayMap<>();
+ }
callbackSpecs.put(callback, changedPackages);
}
}
@@ -932,7 +1045,7 @@
if (op.mode != mode) {
op.mode = mode;
if (uidState != null) {
- uidState.evalForegroundOps();
+ uidState.evalForegroundOps(mOpModeWatchers);
}
ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
if (cbs != null) {
@@ -1126,7 +1239,7 @@
mUidStates.remove(uidState.uid);
}
if (uidChanged) {
- uidState.evalForegroundOps();
+ uidState.evalForegroundOps(mOpModeWatchers);
}
}
@@ -1148,8 +1261,23 @@
}
}
+ private void evalAllForegroundOpsLocked() {
+ for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
+ final UidState uidState = mUidStates.valueAt(uidi);
+ if (uidState.foregroundOps != null) {
+ uidState.evalForegroundOps(mOpModeWatchers);
+ }
+ }
+ }
+
@Override
public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
+ startWatchingModeWithFlags(op, packageName, 0, callback);
+ }
+
+ @Override
+ public void startWatchingModeWithFlags(int op, String packageName, int flags,
+ IAppOpsCallback callback) {
int watchedUid = -1;
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -1166,7 +1294,7 @@
op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
ModeCallback cb = mModeWatchers.get(callback.asBinder());
if (cb == null) {
- cb = new ModeCallback(callback, watchedUid, callingUid, callingPid);
+ cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
mModeWatchers.put(callback.asBinder(), cb);
}
if (op != AppOpsManager.OP_NONE) {
@@ -1185,6 +1313,7 @@
}
cbs.add(cb);
}
+ evalAllForegroundOpsLocked();
}
}
@@ -1212,6 +1341,7 @@
}
}
}
+ evalAllForegroundOpsLocked();
}
}
@@ -1249,7 +1379,7 @@
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
- return op.mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : op.mode;
+ return op.mode;
}
}
@@ -1699,13 +1829,11 @@
} else {
if (uidState.pendingStateCommitTime != 0) {
if (uidState.pendingStateCommitTime < mLastUptime) {
- uidState.state = uidState.pendingState;
- uidState.pendingStateCommitTime = 0;
+ commitUidPendingStateLocked(uidState);
} else {
mLastUptime = SystemClock.uptimeMillis();
if (uidState.pendingStateCommitTime < mLastUptime) {
- uidState.state = uidState.pendingState;
- uidState.pendingStateCommitTime = 0;
+ commitUidPendingStateLocked(uidState);
}
}
}
@@ -1713,6 +1841,44 @@
return uidState;
}
+ private void commitUidPendingStateLocked(UidState uidState) {
+ uidState.state = uidState.pendingState;
+ uidState.pendingStateCommitTime = 0;
+ if (uidState.hasForegroundWatchers) {
+ for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
+ if (!uidState.foregroundOps.valueAt(fgi)) {
+ continue;
+ }
+ final int code = uidState.foregroundOps.keyAt(fgi);
+
+ final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
+ if (callbacks != null) {
+ for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
+ final ModeCallback callback = callbacks.valueAt(cbi);
+ if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
+ || !callback.isWatchingUid(uidState.uid)) {
+ continue;
+ }
+ boolean doAllPackages = uidState.opModes != null
+ && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
+ if (uidState.pkgOps != null) {
+ for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
+ final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
+ if (doAllPackages || (op != null
+ && op.mode == AppOpsManager.MODE_FOREGROUND)) {
+ mHandler.sendMessage(PooledLambda.obtainMessage(
+ AppOpsService::notifyOpChanged,
+ this, callback, code, uidState.uid,
+ uidState.pkgOps.keyAt(pkgi)));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
boolean uidMismatchExpected) {
UidState uidState = getUidStateLocked(uid, edit);
@@ -1952,7 +2118,7 @@
}
}
if (changed) {
- uidState.evalForegroundOps();
+ uidState.evalForegroundOps(mOpModeWatchers);
}
}
}
@@ -2151,7 +2317,7 @@
}
UidState uidState = getUidStateLocked(uid, false);
if (uidState != null) {
- uidState.evalForegroundOps();
+ uidState.evalForegroundOps(mOpModeWatchers);
}
}
@@ -2322,7 +2488,7 @@
}
}
- int strModeToMode(String modeStr, PrintWriter err) {
+ static int strModeToMode(String modeStr, PrintWriter err) {
for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
return i;
@@ -2716,6 +2882,10 @@
pw.println(" Print this help text.");
pw.println(" --op [OP]");
pw.println(" Limit output to data associated with the given app op code.");
+ pw.println(" --mode [MODE]");
+ pw.println(" Limit output to data associated with the given app op mode.");
+ pw.println(" --package [PACKAGE]");
+ pw.println(" Limit output to data associated with the given package name.");
}
private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
@@ -2751,6 +2921,9 @@
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
int dumpOp = -1;
+ String dumpPackage = null;
+ int dumpUid = -1;
+ int dumpMode = -1;
if (args != null) {
for (int i=0; i<args.length; i++) {
@@ -2770,6 +2943,34 @@
if (dumpOp < 0) {
return;
}
+ } else if ("--package".equals(arg)) {
+ i++;
+ if (i >= args.length) {
+ pw.println("No argument for --package option");
+ return;
+ }
+ dumpPackage = args[i];
+ try {
+ dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
+ PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
+ 0);
+ } catch (RemoteException e) {
+ }
+ if (dumpUid < 0) {
+ pw.println("Unknown package: " + dumpPackage);
+ return;
+ }
+ dumpUid = UserHandle.getAppId(dumpUid);
+ } else if ("--mode".equals(arg)) {
+ i++;
+ if (i >= args.length) {
+ pw.println("No argument for --mode option");
+ return;
+ }
+ dumpMode = Shell.strModeToMode(args[i], pw);
+ if (dumpMode < 0) {
+ return;
+ }
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
pw.println("Unknown option: " + arg);
return;
@@ -2782,6 +2983,8 @@
synchronized (this) {
pw.println("Current AppOps Service state:");
+ mConstants.dump(pw);
+ pw.println();
final long now = System.currentTimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
final long nowUptime = SystemClock.uptimeMillis();
@@ -2789,29 +2992,46 @@
final Date date = new Date();
boolean needSep = false;
if (mOpModeWatchers.size() > 0) {
- needSep = true;
boolean printedHeader = false;
for (int i=0; i<mOpModeWatchers.size(); i++) {
if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
continue;
}
- if (!printedHeader) {
- pw.println(" Op mode watchers:");
- printedHeader = true;
- }
- pw.print(" Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
- pw.println(":");
+ boolean printedOpHeader = false;
ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
for (int j=0; j<callbacks.size(); j++) {
+ final ModeCallback cb = callbacks.valueAt(j);
+ if (dumpPackage != null && cb.mWatchingUid >= 0
+ && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+ continue;
+ }
+ needSep = true;
+ if (!printedHeader) {
+ pw.println(" Op mode watchers:");
+ printedHeader = true;
+ }
+ if (!printedOpHeader) {
+ pw.print(" Op ");
+ pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
+ pw.println(":");
+ printedOpHeader = true;
+ }
pw.print(" #"); pw.print(j); pw.print(": ");
- pw.println(callbacks.valueAt(j));
+ pw.println(cb);
}
}
}
- if (mPackageModeWatchers.size() > 0) {
- needSep = true;
- pw.println(" Package mode watchers:");
+ if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
+ boolean printedHeader = false;
for (int i=0; i<mPackageModeWatchers.size(); i++) {
+ if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
+ continue;
+ }
+ needSep = true;
+ if (!printedHeader) {
+ pw.println(" Package mode watchers:");
+ printedHeader = true;
+ }
pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
pw.println(":");
ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
@@ -2822,15 +3042,24 @@
}
}
if (mModeWatchers.size() > 0 && dumpOp < 0) {
- needSep = true;
- pw.println(" All op mode watchers:");
+ boolean printedHeader = false;
for (int i=0; i<mModeWatchers.size(); i++) {
+ final ModeCallback cb = mModeWatchers.valueAt(i);
+ if (dumpPackage != null && cb.mWatchingUid >= 0
+ && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+ continue;
+ }
+ needSep = true;
+ if (!printedHeader) {
+ pw.println(" All op mode watchers:");
+ printedHeader = true;
+ }
pw.print(" ");
pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
- pw.print(": "); pw.println(mModeWatchers.valueAt(i));
+ pw.print(": "); pw.println(cb);
}
}
- if (mActiveWatchers.size() > 0) {
+ if (mActiveWatchers.size() > 0 && dumpMode < 0) {
needSep = true;
boolean printedHeader = false;
for (int i = 0; i < mActiveWatchers.size(); i++) {
@@ -2838,9 +3067,14 @@
if (activeWatchers.size() <= 0) {
continue;
}
+ final ActiveCallback cb = activeWatchers.valueAt(0);
if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
continue;
}
+ if (dumpPackage != null && cb.mWatchingUid >= 0
+ && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+ continue;
+ }
if (!printedHeader) {
pw.println(" All op active watchers:");
printedHeader = true;
@@ -2862,10 +3096,10 @@
}
pw.println("]");
pw.print(" ");
- pw.println(activeWatchers.valueAt(0));
+ pw.println(cb);
}
}
- if (mClients.size() > 0) {
+ if (mClients.size() > 0 && dumpMode < 0) {
needSep = true;
boolean printedHeader = false;
for (int i=0; i<mClients.size(); i++) {
@@ -2878,6 +3112,9 @@
if (dumpOp >= 0 && op.op != dumpOp) {
continue;
}
+ if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
+ continue;
+ }
if (!printedHeader) {
pw.println(" Clients:");
printedHeader = true;
@@ -2898,7 +3135,8 @@
}
}
}
- if (mAudioRestrictions.size() > 0 && dumpOp < 0) {
+ if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
+ && dumpMode < 0) {
boolean printedHeader = false;
for (int o=0; o<mAudioRestrictions.size(); o++) {
final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
@@ -2931,19 +3169,44 @@
final SparseIntArray opModes = uidState.opModes;
final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
- if (dumpOp >= 0) {
- boolean hasOp = uidState.opModes != null
- && uidState.opModes.indexOfKey(dumpOp) >= 0;
- if (pkgOps != null) {
- for (int pkgi = 0; !hasOp && pkgi < pkgOps.size(); pkgi++) {
- Ops ops = pkgOps.valueAt(pkgi);
- if (ops != null && ops.indexOfKey(dumpOp) >= 0) {
- hasOp = true;
- continue;
+ if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
+ boolean hasOp = dumpOp < 0 || (uidState.opModes != null
+ && uidState.opModes.indexOfKey(dumpOp) >= 0);
+ boolean hasPackage = dumpPackage == null;
+ boolean hasMode = dumpMode < 0;
+ if (!hasMode && opModes != null) {
+ for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
+ if (opModes.valueAt(opi) == dumpMode) {
+ hasMode = true;
}
}
}
- if (!hasOp) {
+ if (pkgOps != null) {
+ for (int pkgi = 0;
+ (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
+ pkgi++) {
+ Ops ops = pkgOps.valueAt(pkgi);
+ if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
+ hasOp = true;
+ }
+ if (!hasMode) {
+ for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
+ if (ops.valueAt(opi).mode == dumpMode) {
+ hasMode = true;
+ }
+ }
+ }
+ if (!hasPackage && dumpPackage.equals(ops.packageName)) {
+ hasPackage = true;
+ }
+ }
+ }
+ if (uidState.foregroundOps != null && !hasOp) {
+ if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
+ hasOp = true;
+ }
+ }
+ if (!hasOp || !hasPackage || !hasMode) {
continue;
}
}
@@ -2964,12 +3227,20 @@
pw.print(" startNesting=");
pw.println(uidState.startNesting);
}
- if (uidState.foregroundOps != null) {
+ if (uidState.foregroundOps != null && (dumpMode < 0
+ || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
pw.println(" foregroundOps:");
for (int j = 0; j < uidState.foregroundOps.size(); j++) {
- pw.print(" ");
- pw.println(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
+ if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
+ continue;
+ }
+ pw.print(" ");
+ pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
+ pw.print(": ");
+ pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
}
+ pw.print(" hasForegroundWatchers=");
+ pw.println(uidState.hasForegroundWatchers);
}
needSep = true;
@@ -2981,6 +3252,9 @@
if (dumpOp >= 0 && dumpOp != code) {
continue;
}
+ if (dumpMode >= 0 && dumpMode != mode) {
+ continue;
+ }
pw.print(" "); pw.print(AppOpsManager.opToName(code));
pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
}
@@ -2991,19 +3265,34 @@
}
for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
- Ops ops = pkgOps.valueAt(pkgi);
+ final Ops ops = pkgOps.valueAt(pkgi);
+ if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
+ continue;
+ }
boolean printedPackage = false;
for (int j=0; j<ops.size(); j++) {
- Op op = ops.valueAt(j);
+ final Op op = ops.valueAt(j);
if (dumpOp >= 0 && dumpOp != op.op) {
continue;
}
+ if (dumpMode >= 0 && dumpMode != op.mode) {
+ continue;
+ }
if (!printedPackage) {
pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
printedPackage = true;
}
pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
+ final int switchOp = AppOpsManager.opToSwitch(op.op);
+ if (switchOp != op.op) {
+ pw.print(" / switch ");
+ pw.print(AppOpsManager.opToName(switchOp));
+ final Op switchObj = ops.get(switchOp);
+ int mode = switchObj != null
+ ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
+ pw.print("="); pw.print(AppOpsManager.modeToName(mode));
+ }
pw.println("): ");
dumpTimesLocked(pw,
" Access: ",
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 23c5779..9b001ce 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -1056,9 +1056,9 @@
* @return whether alarms should be restricted for a UID package-name.
*/
public boolean areAlarmsRestricted(int uid, @NonNull String packageName,
- boolean allowWhileIdle) {
+ boolean isExemptOnBatterySaver) {
return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false,
- /* exemptOnBatterySaver =*/ allowWhileIdle);
+ isExemptOnBatterySaver);
}
/**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 72f9d74..797cb4b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -500,24 +500,24 @@
private static final int MAX_VALIDATION_LOGS = 10;
private static class ValidationLog {
final Network mNetwork;
- final String mNetworkExtraInfo;
+ final String mName;
final ReadOnlyLocalLog mLog;
- ValidationLog(Network network, String networkExtraInfo, ReadOnlyLocalLog log) {
+ ValidationLog(Network network, String name, ReadOnlyLocalLog log) {
mNetwork = network;
- mNetworkExtraInfo = networkExtraInfo;
+ mName = name;
mLog = log;
}
}
private final ArrayDeque<ValidationLog> mValidationLogs =
new ArrayDeque<ValidationLog>(MAX_VALIDATION_LOGS);
- private void addValidationLogs(ReadOnlyLocalLog log, Network network, String networkExtraInfo) {
+ private void addValidationLogs(ReadOnlyLocalLog log, Network network, String name) {
synchronized (mValidationLogs) {
while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
mValidationLogs.removeLast();
}
- mValidationLogs.addFirst(new ValidationLog(network, networkExtraInfo, log));
+ mValidationLogs.addFirst(new ValidationLog(network, name, log));
}
}
@@ -2097,7 +2097,7 @@
synchronized (mValidationLogs) {
pw.println("mValidationLogs (most recent first):");
for (ValidationLog p : mValidationLogs) {
- pw.println(p.mNetwork + " - " + p.mNetworkExtraInfo);
+ pw.println(p.mNetwork + " - " + p.mName);
pw.increaseIndent();
p.mLog.dump(fd, pw, args);
pw.decreaseIndent();
@@ -4628,8 +4628,10 @@
synchronized (this) {
nai.networkMonitor.systemReady = mSystemReady;
}
- addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network,
- networkInfo.getExtraInfo());
+ final String extraInfo = networkInfo.getExtraInfo();
+ final String name = TextUtils.isEmpty(extraInfo)
+ ? nai.networkCapabilities.getSSID() : extraInfo;
+ addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
if (DBG) log("registerNetworkAgent " + nai);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
return nai.network.netId;
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 33ca02f..60f1877 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -107,7 +107,6 @@
static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved
static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer
- static final String TUNNEL_INTERFACE_PREFIX = "ipsec";
/* Binder context for this service */
private final Context mContext;
@@ -1270,7 +1269,7 @@
final int resourceId = mNextResourceId++;
final int ikey = reserveNetId();
final int okey = reserveNetId();
- String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId);
+ String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId);
try {
// Calls to netd:
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 58b40b1..48090f2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -466,6 +466,7 @@
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.dex.DexManager;
import com.android.server.utils.PriorityDump;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.PinnedStackWindowController;
@@ -4311,7 +4312,7 @@
}
if (app.info.isPrivilegedApp() &&
- SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
+ DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}
@@ -22994,18 +22995,27 @@
}
}
- private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
+ private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
boolean doingAll, long now) {
if (mAdjSeq == app.adjSeq) {
- // This adjustment has already been computed.
- return app.curRawAdj;
+ if (app.adjSeq == app.completedAdjSeq) {
+ // This adjustment has already been computed successfully.
+ return false;
+ } else {
+ // The process is being computed, so there is a cycle. We cannot
+ // rely on this process's state.
+ app.containsCycle = true;
+ return false;
+ }
}
if (app.thread == null) {
app.adjSeq = mAdjSeq;
app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
- return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
+ app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ;
+ app.completedAdjSeq = app.adjSeq;
+ return false;
}
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
@@ -23018,6 +23028,8 @@
final int appUid = app.info.uid;
final int logUid = mCurOomAdjUid;
+ int prevAppAdj = app.curAdj;
+
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
@@ -23062,7 +23074,10 @@
app.curSchedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
}
}
- return (app.curAdj=app.maxAdj);
+ app.curAdj = app.maxAdj;
+ app.completedAdjSeq = app.adjSeq;
+ // if curAdj is less than prevAppAdj, then this process was promoted
+ return app.curAdj < prevAppAdj;
}
app.systemNoUi = false;
@@ -23074,6 +23089,8 @@
int adj;
int schedGroup;
int procState;
+ int cachedAdjSeq;
+
boolean foregroundActivities = false;
mTmpBroadcastQueue.clear();
if (PROCESS_STATE_CUR_TOP == ActivityManager.PROCESS_STATE_TOP && app == TOP_APP) {
@@ -23387,9 +23404,9 @@
// there are applications dependent on our services or providers, but
// this gives us a baseline and makes sure we don't get into an
// infinite recursion.
- app.adjSeq = mAdjSeq;
app.curRawAdj = adj;
app.hasStartedServices = false;
+ app.adjSeq = mAdjSeq;
if (mBackupTarget != null && app == mBackupTarget.app) {
// If possible we want to avoid killing apps while they're being backed up
@@ -23488,8 +23505,15 @@
if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
ProcessRecord client = cr.binding.client;
- int clientAdj = computeOomAdjLocked(client, cachedAdj,
- TOP_APP, doingAll, now);
+ computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+ if (client.containsCycle) {
+ // We've detected a cycle. We should ignore this connection and allow
+ // this process to retry computeOomAdjLocked later in case a later-checked
+ // connection from a client would raise its priority legitimately.
+ app.containsCycle = true;
+ continue;
+ }
+ int clientAdj = client.curRawAdj;
int clientProcState = client.curProcState;
if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
@@ -23708,7 +23732,15 @@
// Being our own client is not interesting.
continue;
}
- int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+ computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+ if (client.containsCycle) {
+ // We've detected a cycle. We should ignore this connection and allow
+ // this process to retry computeOomAdjLocked later in case a later-checked
+ // connection from a client would raise its priority legitimately.
+ app.containsCycle = true;
+ continue;
+ }
+ int clientAdj = client.curRawAdj;
int clientProcState = client.curProcState;
if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
// If the other app is cached for any reason, for purposes here
@@ -23936,8 +23968,10 @@
app.curSchedGroup = schedGroup;
app.curProcState = procState;
app.foregroundActivities = foregroundActivities;
+ app.completedAdjSeq = mAdjSeq;
- return app.curRawAdj;
+ // if curAdj is less than prevAppAdj, then this process was promoted
+ return app.curAdj < prevAppAdj;
}
/**
@@ -24911,12 +24945,23 @@
int nextCachedAdj = curCachedAdj+1;
int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
+
+ boolean retryCycles = false;
+
+ // need to reset cycle state before calling computeOomAdjLocked because of service connections
+ for (int i=N-1; i>=0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
+ app.containsCycle = false;
+ }
for (int i=N-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
if (!app.killedByAm && app.thread != null) {
app.procStateChanged = false;
computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
+ // if any app encountered a cycle, we need to perform an additional loop later
+ retryCycles |= app.containsCycle;
+
// If we haven't yet assigned the final cached adj
// to the process, do that now.
if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
@@ -24970,6 +25015,39 @@
}
}
+
+ }
+ }
+
+ // Cycle strategy:
+ // - Retry computing any process that has encountered a cycle.
+ // - Continue retrying until no process was promoted.
+ // - Iterate from least important to most important.
+ int cycleCount = 0;
+ while (retryCycles) {
+ cycleCount++;
+ retryCycles = false;
+
+ for (int i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+ app.adjSeq--;
+ app.completedAdjSeq--;
+ }
+ }
+
+ for (int i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+ if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now)) {
+ retryCycles = true;
+ }
+ }
+ }
+ }
+ for (int i=N-1; i>=0; i--) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (!app.killedByAm && app.thread != null) {
applyOomAdjLocked(app, true, now, nowElapsed);
// Count the number of process types.
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b7fde1d..caf52e3 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -149,6 +149,8 @@
String waitingToKill; // Process is waiting to be killed when in the bg, and reason
Object forcingToImportant; // Token that is forcing this process to be important
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
+ int completedAdjSeq; // Sequence id for identifying oom_adj assignment cycles
+ boolean containsCycle; // Whether this app has encountered a cycle in the most recent update
int lruSeq; // Sequence id for identifying LRU update cycles
CompatibilityInfo compat; // last used compatibility mode
IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 02459bd..36a2476 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -26,6 +26,7 @@
import android.net.wifi.WifiInfo;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -131,16 +132,17 @@
final String tag = tagFor(id);
final int eventId = notifyType.eventId;
final int transportType;
- final String extraInfo;
+ final String name;
if (nai != null) {
transportType = getFirstTransportType(nai);
- extraInfo = nai.networkInfo.getExtraInfo();
+ final String extraInfo = nai.networkInfo.getExtraInfo();
+ name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
// Only notify for Internet-capable networks.
if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
} else {
// Legacy notifications.
transportType = TRANSPORT_CELLULAR;
- extraInfo = null;
+ name = null;
}
// Clear any previous notification with lower priority, otherwise return. http://b/63676954.
@@ -157,9 +159,8 @@
if (DBG) {
Slog.d(TAG, String.format(
- "showNotification tag=%s event=%s transport=%s extraInfo=%s highPrioriy=%s",
- tag, nameOf(eventId), getTransportName(transportType), extraInfo,
- highPriority));
+ "showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
+ tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
Resources r = Resources.getSystem();
@@ -188,7 +189,7 @@
break;
default:
title = r.getString(R.string.network_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+ details = r.getString(R.string.network_available_sign_in_detailed, name);
break;
}
} else if (notifyType == NotificationType.NETWORK_SWITCH) {
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 03d8f39..d7057f4 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -166,7 +166,7 @@
private SyncManager getSyncManager() {
synchronized(mSyncManagerLock) {
try {
- // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
+ // Try to create the SyncManager, return null if it fails (which it shouldn't).
if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
} catch (SQLiteException e) {
Log.e(TAG, "Can't create SyncManager", e);
@@ -199,7 +199,7 @@
final long identityToken = clearCallingIdentity();
try {
if (mSyncManager == null) {
- pw.println("No SyncManager created! (Disk full?)");
+ pw.println("SyncManager not available yet");
} else {
mSyncManager.dump(fd, pw, dumpAll);
}
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index 9980930..089632d 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -115,7 +115,10 @@
Slog.v(TAG, "onStopJob called " + params.getJobId() + ", reason: "
+ params.getStopReason());
}
- mLogger.log("onStopJob() ", mLogger.jobParametersToString(params));
+ final boolean readyToSync = SyncManager.readyToSync();
+
+ mLogger.log("onStopJob() ", mLogger.jobParametersToString(params),
+ " readyToSync=", readyToSync);
synchronized (mLock) {
final int jobId = params.getJobId();
mJobParamsMap.remove(jobId);
@@ -124,13 +127,15 @@
final long nowUptime = SystemClock.uptimeMillis();
final long runtime = nowUptime - startUptime;
+
if (startUptime == 0) {
wtf("Job " + jobId + " start uptime not found: "
+ " params=" + jobParametersToString(params));
} else if (runtime > 60 * 1000) {
// WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon.
// (1 minute threshold.)
- if (!mStartedSyncs.get(jobId)) {
+ // Also don't wtf when it's not ready to sync.
+ if (readyToSync && !mStartedSyncs.get(jobId)) {
wtf("Job " + jobId + " didn't start: "
+ " startUptime=" + startUptime
+ " nowUptime=" + nowUptime
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 5fa4245..33cf11b 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -91,6 +91,7 @@
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
@@ -215,6 +216,10 @@
private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
| Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
+ /** Singleton instance. */
+ @GuardedBy("SyncManager.class")
+ private static SyncManager sInstance;
+
private Context mContext;
private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
@@ -571,6 +576,14 @@
}
public SyncManager(Context context, boolean factoryTest) {
+ synchronized (SyncManager.class) {
+ if (sInstance == null) {
+ sInstance = this;
+ } else {
+ Slog.wtf(TAG, "SyncManager instantiated multiple times");
+ }
+ }
+
// Initialize the SyncStorageEngine first, before registering observers
// and creating threads and so on; it may fail if the disk is full.
mContext = context;
@@ -2851,6 +2864,16 @@
}
/**
+ * @return whether the device is ready to run sync jobs.
+ */
+ public static boolean readyToSync() {
+ synchronized (SyncManager.class) {
+ return sInstance != null && sInstance.mProvisioned && sInstance.mBootCompleted
+ && sInstance.mJobServiceReady;
+ }
+ }
+
+ /**
* Handles SyncOperation Messages that are posted to the associated
* HandlerThread.
*/
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 030c915..213ec36 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -189,7 +189,7 @@
mController = new ColorDisplayController(getContext(), mCurrentUser);
mController.setListener(this);
- setCoefficientMatrix(getContext(), DisplayTransformManager.isNativeModeEnabled());
+ setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix());
// Prepare color transformation matrix.
setMatrix(mController.getColorTemperature(), mMatrixNight);
@@ -293,7 +293,7 @@
mColorMatrixAnimator.cancel();
}
- setCoefficientMatrix(getContext(), DisplayTransformManager.isColorModeNative(mode));
+ setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
setMatrix(mController.getColorTemperature(), mMatrixNight);
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
@@ -306,13 +306,12 @@
}
/**
- * Set coefficients based on native mode. Use DisplayTransformManager#isNativeModeEnabled while
- * setting is stable; when setting is changing, pass native mode selection directly.
+ * Set coefficients based on whether the color matrix is linear or not.
*/
- private void setCoefficientMatrix(Context context, boolean isNative) {
- final String[] coefficients = context.getResources().getStringArray(isNative
- ? R.array.config_nightDisplayColorTemperatureCoefficientsNative
- : R.array.config_nightDisplayColorTemperatureCoefficients);
+ private void setCoefficientMatrix(Context context, boolean needsLinear) {
+ final String[] coefficients = context.getResources().getStringArray(needsLinear
+ ? R.array.config_nightDisplayColorTemperatureCoefficients
+ : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
for (int i = 0; i < 9 && i < coefficients.length; i++) {
mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
}
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 57d88e1..57a4f0d 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -231,21 +231,19 @@
}
/**
- * Return true when colors are stretched from the working color space to the
- * native color space.
+ * Return true when the color matrix works in linear space.
*/
- public static boolean isNativeModeEnabled() {
+ public static boolean needsLinearColorMatrix() {
return SystemProperties.getInt(PERSISTENT_PROPERTY_DISPLAY_COLOR,
- DISPLAY_COLOR_MANAGED) != DISPLAY_COLOR_MANAGED;
+ DISPLAY_COLOR_UNMANAGED) != DISPLAY_COLOR_UNMANAGED;
}
/**
- * Return true when the specified colorMode stretches colors from the
- * working color space to the native color space.
+ * Return true when the specified colorMode requires the color matrix to
+ * work in linear space.
*/
- public static boolean isColorModeNative(int colorMode) {
- return !(colorMode == ColorDisplayController.COLOR_MODE_NATURAL ||
- colorMode == ColorDisplayController.COLOR_MODE_BOOSTED);
+ public static boolean needsLinearColorMatrix(int colorMode) {
+ return colorMode != ColorDisplayController.COLOR_MODE_SATURATED;
}
public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 0d1644b..b3aa0bf 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -45,6 +45,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
@@ -82,6 +83,7 @@
private final SessionStub mSession;
private final SessionCb mSessionCb;
private final MediaSessionService mService;
+ private final Context mContext;
private final Object mLock = new Object();
private final ArrayList<ISessionControllerCallbackHolder> mControllerCallbackHolders =
@@ -126,8 +128,9 @@
mSession = new SessionStub();
mSessionCb = new SessionCb(cb);
mService = service;
+ mContext = mService.getContext();
mHandler = new MessageHandler(handlerLooper);
- mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
}
@@ -232,12 +235,17 @@
* @param packageName The package that made the original volume request.
* @param pid The pid that made the original volume request.
* @param uid The uid that made the original volume request.
+ * @param asSystemService {@code true} if the event sent to the session as if it was come from
+ * the system service instead of the app process. This helps sessions to distinguish
+ * between the key injection by the app and key events from the hardware devices.
+ * Should be used only when the volume key events aren't handled by foreground
+ * activity. {@code false} otherwise to tell session about the real caller.
* @param direction The direction to adjust volume in.
* @param flags Any of the flags from {@link AudioManager}.
* @param useSuggested True to use adjustSuggestedStreamVolume instead of
*/
- public void adjustVolume(String packageName, int pid, int uid, int direction, int flags,
- boolean useSuggested) {
+ public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
+ int direction, int flags, boolean useSuggested) {
int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
if (isPlaybackActive() || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
@@ -258,7 +266,7 @@
Log.w(TAG, "Muting remote playback is not supported");
return;
}
- mSessionCb.adjustVolume(packageName, pid, uid, direction);
+ mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
mOptimisticVolume = volumeBefore + direction;
@@ -418,9 +426,9 @@
return mSessionCb.mCb;
}
- public void sendMediaButton(String packageName, int pid, int uid, KeyEvent ke, int sequenceId,
- ResultReceiver cb) {
- mSessionCb.sendMediaButton(packageName, pid, uid, ke, sequenceId, cb);
+ public void sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
+ KeyEvent ke, int sequenceId, ResultReceiver cb) {
+ mSessionCb.sendMediaButton(packageName, pid, uid, asSystemService, ke, sequenceId, cb);
}
public void dump(PrintWriter pw, String prefix) {
@@ -698,11 +706,7 @@
}
private String getPackageName(int uid) {
- Context context = mService.getContext();
- if (context == null) {
- return null;
- }
- String[] packages = context.getPackageManager().getPackagesForUid(uid);
+ String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
return packages[0];
}
@@ -907,12 +911,17 @@
mCb = cb;
}
- public boolean sendMediaButton(String packageName, int pid, int uid, KeyEvent keyEvent,
- int sequenceId, ResultReceiver cb) {
+ public boolean sendMediaButton(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
try {
- mCb.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceId, cb);
+ if (asSystemService) {
+ mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+ Process.SYSTEM_UID, mediaButtonIntent, sequenceId, cb);
+ } else {
+ mCb.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceId, cb);
+ }
return true;
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
@@ -1079,9 +1088,15 @@
}
}
- public void adjustVolume(String packageName, int pid, int uid, int direction) {
+ public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
+ int direction) {
try {
- mCb.onAdjustVolume(packageName, pid, uid, direction);
+ if (asSystemService) {
+ mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
+ Process.SYSTEM_UID, direction);
+ } else {
+ mCb.onAdjustVolume(packageName, pid, uid, direction);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Remote failure in adjustVolume.", e);
}
@@ -1105,9 +1120,10 @@
}
@Override
- public boolean sendMediaButton(String packageName, KeyEvent mediaButtonIntent) {
+ public boolean sendMediaButton(String packageName, boolean asSystemService,
+ KeyEvent mediaButtonIntent) {
return mSessionCb.sendMediaButton(packageName, Binder.getCallingPid(),
- Binder.getCallingUid(), mediaButtonIntent, 0, null);
+ Binder.getCallingUid(), asSystemService, mediaButtonIntent, 0, null);
}
@Override
@@ -1188,13 +1204,14 @@
}
@Override
- public void adjustVolume(String packageName, int direction, int flags) {
+ public void adjustVolume(String packageName, boolean asSystemService, int direction,
+ int flags) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- MediaSessionRecord.this.adjustVolume(packageName, pid, uid, direction, flags,
- false /* useSuggested */);
+ MediaSessionRecord.this.adjustVolume(packageName, pid, uid, asSystemService,
+ direction, flags, false /* useSuggested */);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a3c6c80..a6e9389 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1093,13 +1093,21 @@
* registered listeners, or if there was none, broadcast an
* ACTION_MEDIA_BUTTON intent to the rest of the system.
*
+ * @param packageName The caller package
+ * @param asSystemService {@code true} if the event sent to the session as if it was come
+ * from the system service instead of the app process. This helps sessions to
+ * distinguish between the key injection by the app and key events from the
+ * hardware devices. Should be used only when the volume key events aren't handled
+ * by foreground activity. {@code false} otherwise to tell session about the real
+ * caller.
* @param keyEvent a non-null KeyEvent whose key code is one of the
* supported media buttons
* @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
* while this key event is dispatched.
*/
@Override
- public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+ public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
+ KeyEvent keyEvent, boolean needWakeLock) {
if (keyEvent == null || !KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
Log.w(TAG, "Attempted to dispatch null or non-media key event.");
return;
@@ -1110,7 +1118,8 @@
final long token = Binder.clearCallingIdentity();
try {
if (DEBUG) {
- Log.d(TAG, "dispatchMediaKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
+ Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
+ + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
+ keyEvent);
}
if (!isUserSetupComplete()) {
@@ -1137,7 +1146,8 @@
}
try {
mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
- new MediaKeyListenerResultReceiver(keyEvent, needWakeLock));
+ new MediaKeyListenerResultReceiver(packageName, pid, uid,
+ asSystemService, keyEvent, needWakeLock));
return;
} catch (RemoteException e) {
Log.w(TAG, "Failed to send " + keyEvent
@@ -1146,9 +1156,11 @@
}
}
if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
- handleVoiceKeyEventLocked(keyEvent, needWakeLock);
+ handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
+ needWakeLock);
} else {
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock);
}
}
} finally {
@@ -1324,6 +1336,13 @@
* there's no active global priority session, long-pressess will be sent to the
* long-press listener instead of adjusting volume.
*
+ * @param packageName The caller package.
+ * @param asSystemService {@code true} if the event sent to the session as if it was come
+ * from the system service instead of the app process. This helps sessions to
+ * distinguish between the key injection by the app and key events from the
+ * hardware devices. Should be used only when the volume key events aren't handled
+ * by foreground activity. {@code false} otherwise to tell session about the real
+ * caller.
* @param keyEvent a non-null KeyEvent whose key code is one of the
* {@link KeyEvent#KEYCODE_VOLUME_UP},
* {@link KeyEvent#KEYCODE_VOLUME_DOWN},
@@ -1332,7 +1351,8 @@
* @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
*/
@Override
- public void dispatchVolumeKeyEvent(KeyEvent keyEvent, int stream, boolean musicOnly) {
+ public void dispatchVolumeKeyEvent(String packageName, boolean asSystemService,
+ KeyEvent keyEvent, int stream, boolean musicOnly) {
if (keyEvent == null ||
(keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
&& keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
@@ -1346,15 +1366,16 @@
final long token = Binder.clearCallingIdentity();
if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "dispatchVolumeKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
- + keyEvent);
+ Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
+ + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
}
try {
synchronized (mLock) {
if (isGlobalPriorityActiveLocked()
|| mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
- dispatchVolumeKeyEventLocked(keyEvent, stream, musicOnly);
+ dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, stream, musicOnly);
} else {
// TODO: Consider the case when both volume up and down keys are pressed
// at the same time.
@@ -1387,11 +1408,12 @@
&& mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
.getDownTime() == keyEvent.getDownTime()) {
// Short-press. Should change volume.
- dispatchVolumeKeyEventLocked(
+ dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
mCurrentFullUserRecord.mInitialDownVolumeStream,
mCurrentFullUserRecord.mInitialDownMusicOnly);
- dispatchVolumeKeyEventLocked(keyEvent, stream, musicOnly);
+ dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, stream, musicOnly);
} else {
dispatchVolumeKeyLongPressLocked(keyEvent);
}
@@ -1403,8 +1425,8 @@
}
}
- private void dispatchVolumeKeyEventLocked(
- KeyEvent keyEvent, int stream, boolean musicOnly) {
+ private void dispatchVolumeKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
int direction = 0;
@@ -1438,21 +1460,27 @@
if (up) {
direction = 0;
}
- dispatchAdjustVolumeLocked(stream, direction, flags);
+ dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
+ direction, flags);
} else if (isMute) {
if (down && keyEvent.getRepeatCount() == 0) {
- dispatchAdjustVolumeLocked(stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
+ dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
+ AudioManager.ADJUST_TOGGLE_MUTE, flags);
}
}
}
}
@Override
- public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
+ public void dispatchAdjustVolume(String packageName, int suggestedStream, int delta,
+ int flags) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- dispatchAdjustVolumeLocked(suggestedStream, delta, flags);
+ dispatchAdjustVolumeLocked(packageName, pid, uid, false,
+ suggestedStream, delta, flags);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1777,7 +1805,8 @@
return false;
}
- private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags) {
+ private void dispatchAdjustVolumeLocked(String packageName, int pid, int uid,
+ boolean asSystemService, int suggestedStream, int direction, int flags) {
MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
: mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
@@ -1822,12 +1851,13 @@
}
});
} else {
- session.adjustVolume(getContext().getPackageName(), Process.myPid(),
- Process.SYSTEM_UID, direction, flags, true);
+ session.adjustVolume(packageName, pid, uid, asSystemService,
+ direction, flags, true);
}
}
- private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
+ private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
int action = keyEvent.getAction();
boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
if (action == KeyEvent.ACTION_DOWN) {
@@ -1844,14 +1874,17 @@
if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
// Resend the down then send this event through
KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
- dispatchMediaKeyEventLocked(downEvent, needWakeLock);
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ downEvent, needWakeLock);
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock);
}
}
}
}
- private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
+ private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
if (session != null) {
if (DEBUG_KEY_EVENT) {
@@ -1861,17 +1894,13 @@
mKeyEventReceiver.aquireWakeLockLocked();
}
// If we don't need a wakelock use -1 as the id so we won't release it later.
- session.sendMediaButton(getContext().getPackageName(),
- Process.myPid(),
- Process.SYSTEM_UID,
- keyEvent,
+ session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mKeyEventReceiver);
if (mCurrentFullUserRecord.mCallback != null) {
try {
mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
- keyEvent,
- new MediaSession.Token(session.getControllerBinder()));
+ keyEvent, new MediaSession.Token(session.getControllerBinder()));
} catch (RemoteException e) {
Log.w(TAG, "Failed to send callback", e);
}
@@ -1884,6 +1913,10 @@
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ // TODO: Find a way to also send PID/UID in secure way.
+ String callerPackageName =
+ (asSystemService) ? getContext().getPackageName() : packageName;
+ mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
try {
if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
@@ -1984,13 +2017,22 @@
}
private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
- private KeyEvent mKeyEvent;
- private boolean mNeedWakeLock;
+ private final String mPackageName;
+ private final int mPid;
+ private final int mUid;
+ private final boolean mAsSystemService;
+ private final KeyEvent mKeyEvent;
+ private final boolean mNeedWakeLock;
private boolean mHandled;
- private MediaKeyListenerResultReceiver(KeyEvent keyEvent, boolean needWakeLock) {
+ private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
super(mHandler);
mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
+ mPackageName = packageName;
+ mPid = pid;
+ mUid = uid;
+ mAsSystemService = asSystemService;
mKeyEvent = keyEvent;
mNeedWakeLock = needWakeLock;
}
@@ -2020,9 +2062,11 @@
synchronized (mLock) {
if (!isGlobalPriorityActiveLocked()
&& isVoiceKey(mKeyEvent.getKeyCode())) {
- handleVoiceKeyEventLocked(mKeyEvent, mNeedWakeLock);
+ handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+ mKeyEvent, mNeedWakeLock);
} else {
- dispatchMediaKeyEventLocked(mKeyEvent, mNeedWakeLock);
+ dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+ mKeyEvent, mNeedWakeLock);
}
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a6dfec7..f082271 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -389,16 +389,11 @@
final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
false);
if (pi != null) {
- /*
- * Only update overlay settings when an overlay becomes enabled or disabled.
- * Enabling or disabling components of a target should not change the
- * target's overlays. Since, overlays do not have components, this will only
- * update overlay settings if an overlay package becomes enabled or
- * disabled.
- */
mPackageManager.cachePackageInfo(packageName, userId, pi);
if (pi.isOverlayPackage()) {
mImpl.onOverlayPackageChanged(packageName, userId);
+ } else {
+ mImpl.onTargetPackageChanged(packageName, userId);
}
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index bb36ab1..3639082 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -212,15 +212,21 @@
}
}
+ void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
+ }
+
+ updateAllOverlaysForTarget(packageName, userId, 0);
+ }
+
void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
if (DEBUG) {
Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId="
+ userId);
}
- if (updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING)) {
- mListener.onOverlaysChanged(packageName, userId);
- }
+ updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING);
}
void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) {
@@ -228,9 +234,7 @@
Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
}
- if (updateAllOverlaysForTarget(packageName, userId, 0)) {
- mListener.onOverlaysChanged(packageName, userId);
- }
+ updateAllOverlaysForTarget(packageName, userId, 0);
}
void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
@@ -688,6 +692,11 @@
}
interface OverlayChangeListener {
+
+ /**
+ * An event triggered by changes made to overlay state or settings as well as changes that
+ * add or remove target packages of overlays.
+ **/
void onOverlaysChanged(@NonNull String targetPackage, int userId);
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index ebab1a7..b0be4a9 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -34,6 +34,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
import com.android.server.pm.dex.PackageDexUsage;
@@ -495,10 +496,9 @@
boolean isUsedByOtherApps) {
int flags = info.flags;
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
- // When pm.dexopt.priv-apps-oob is true, we only verify privileged apps.
- if (info.isPrivilegedApp() &&
- SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
- return "verify";
+ // When a priv app is configured to run out of box, only verify it.
+ if (info.isPrivilegedApp() && DexManager.isPackageSelectedToRunOob(info.packageName)) {
+ return "verify";
}
if (vmSafeMode) {
return getSafeModeCompilerFilter(targetCompilerFilter);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 00d2f74..2650ef0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -578,8 +578,6 @@
private static final String PRODUCT_OVERLAY_DIR = "/product/overlay";
- private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
-
/** Canonical intent used to identify what counts as a "web browser" app */
private static final Intent sBrowserIntent;
static {
@@ -2459,7 +2457,7 @@
"*dexopt*");
DexManager.Listener dexManagerListener = DexLogger.getListener(this,
installer, mInstallLock);
- mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock,
+ mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock,
dexManagerListener);
mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
@@ -10428,11 +10426,7 @@
Log.d(TAG, "Scanning package " + pkg.packageName);
}
- if (Build.IS_DEBUGGABLE &&
- pkg.isPrivileged() &&
- SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
- PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
- }
+ DexManager.maybeLogUnexpectedPackageDetails(pkg);
// Initialize package source and resource directories
final File scanFile = new File(pkg.codePath);
@@ -21038,23 +21032,6 @@
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
co.onChange(true);
- // This observer provides an one directional mapping from Global.PRIV_APP_OOB_ENABLED to
- // pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
- // it is done.
- ContentObserver privAppOobObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
- SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
- oobEnabled == 1 ? "true" : "false");
- }
- };
- mContext.getContentResolver().registerContentObserver(
- Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
- UserHandle.USER_SYSTEM);
- // At boot, restore the value from the setting, which persists across reboot.
- privAppOobObserver.onChange(true);
-
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
@@ -21143,6 +21120,7 @@
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
+ mDexManager.systemReady();
mPackageDexOptimizer.systemReady();
StorageManagerInternal StorageManagerInternal = LocalServices.getService(
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 4b907f4..1aea8f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -26,7 +26,6 @@
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.pm.dex.DexManager;
@@ -56,7 +55,6 @@
import android.util.Log;
import android.util.PackageUtils;
import android.util.Slog;
-import android.util.jar.StrictJarFile;
import android.util.proto.ProtoOutputStream;
import dalvik.system.VMRuntime;
@@ -85,12 +83,10 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
-import java.util.zip.ZipEntry;
/**
* Class containing helper methods for the PackageManagerService.
@@ -317,61 +313,6 @@
return maxModifiedTime;
}
- /**
- * Checks that the archive located at {@code fileName} has uncompressed dex file and so
- * files that can be direclty mapped.
- */
- public static void logApkHasUncompressedCode(String fileName) {
- StrictJarFile jarFile = null;
- try {
- jarFile = new StrictJarFile(fileName,
- false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
- Iterator<ZipEntry> it = jarFile.iterator();
- while (it.hasNext()) {
- ZipEntry entry = it.next();
- if (entry.getName().endsWith(".dex")) {
- if (entry.getMethod() != ZipEntry.STORED) {
- Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
- entry.getName());
- } else if ((entry.getDataOffset() & 0x3) != 0) {
- Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
- entry.getName());
- }
- } else if (entry.getName().endsWith(".so")) {
- if (entry.getMethod() != ZipEntry.STORED) {
- Slog.w(TAG, "APK " + fileName + " has compressed native code " +
- entry.getName());
- } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
- Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
- entry.getName());
- }
- }
- }
- } catch (IOException ignore) {
- Slog.wtf(TAG, "Error when parsing APK " + fileName);
- } finally {
- try {
- if (jarFile != null) {
- jarFile.close();
- }
- } catch (IOException ignore) {}
- }
- return;
- }
-
- /**
- * Checks that the APKs in the given package have uncompressed dex file and so
- * files that can be direclty mapped.
- */
- public static void logPackageHasUncompressedCode(PackageParser.Package pkg) {
- logApkHasUncompressedCode(pkg.baseCodePath);
- if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
- for (int i = 0; i < pkg.splitCodePaths.length; i++) {
- logApkHasUncompressedCode(pkg.splitCodePaths[i]);
- }
- }
- }
-
private static File getSettingsProblemFile() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a92fbb6..01f84c4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -25,6 +25,7 @@
import android.accounts.IAccountManager;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.IIntentReceiver;
@@ -53,17 +54,20 @@
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
-import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IUserManager;
import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseInputStream;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
@@ -78,27 +82,41 @@
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.PrintWriterPrinter;
-
import com.android.internal.content.PackageHelper;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
-
import dalvik.system.DexFile;
-
-import libcore.io.IoUtils;
-
-import java.io.FileDescriptor;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
-import java.util.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.FileAttribute;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.WeakHashMap;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
class PackageManagerShellCommand extends ShellCommand {
/** Path for streaming APK content */
private static final String STDIN_PATH = "-";
+ /** Path where ART profiles snapshots are dumped for the shell user */
+ private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
final IPackageManager mInterface;
final private WeakHashMap<String, Resources> mResourceCache =
@@ -167,6 +185,8 @@
return runDexoptJob();
case "dump-profiles":
return runDumpProfiles();
+ case "snapshot-profile":
+ return runSnapshotProfile();
case "uninstall":
return runUninstall();
case "clear":
@@ -1287,6 +1307,120 @@
return 0;
}
+ private int runSnapshotProfile() throws RemoteException {
+ PrintWriter pw = getOutPrintWriter();
+
+ // Parse the arguments
+ final String packageName = getNextArg();
+ final boolean isBootImage = "android".equals(packageName);
+
+ String codePath = null;
+ String opt;
+ while ((opt = getNextArg()) != null) {
+ switch (opt) {
+ case "--code-path":
+ if (isBootImage) {
+ pw.write("--code-path cannot be used for the boot image.");
+ return -1;
+ }
+ codePath = getNextArg();
+ break;
+ default:
+ pw.write("Unknown arg: " + opt);
+ return -1;
+ }
+ }
+
+ // If no code path was explicitly requested, select the base code path.
+ String baseCodePath = null;
+ if (!isBootImage) {
+ PackageInfo packageInfo = mInterface.getPackageInfo(packageName, /* flags */ 0,
+ /* userId */0);
+ if (packageInfo == null) {
+ pw.write("Package not found " + packageName);
+ return -1;
+ }
+ baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+ if (codePath == null) {
+ codePath = baseCodePath;
+ }
+ }
+
+ // Create the profile snapshot.
+ final SnapshotRuntimeProfileCallback callback = new SnapshotRuntimeProfileCallback();
+ // The calling package is needed to debug permission access.
+ final String callingPackage = (Binder.getCallingUid() == Process.ROOT_UID)
+ ? "root" : "com.android.shell";
+ final int profileType = isBootImage
+ ? ArtManager.PROFILE_BOOT_IMAGE : ArtManager.PROFILE_APPS;
+ if (!mInterface.getArtManager().isRuntimeProfilingEnabled(profileType, callingPackage)) {
+ pw.println("Error: Runtime profiling is not enabled");
+ return -1;
+ }
+ mInterface.getArtManager().snapshotRuntimeProfile(profileType, packageName,
+ codePath, callback, callingPackage);
+ if (!callback.waitTillDone()) {
+ pw.println("Error: callback not called");
+ return callback.mErrCode;
+ }
+
+ // Copy the snapshot profile to the output profile file.
+ try (InputStream inStream = new AutoCloseInputStream(callback.mProfileReadFd)) {
+ final String outputFileSuffix = isBootImage || Objects.equals(baseCodePath, codePath)
+ ? "" : ("-" + new File(codePath).getName());
+ final String outputProfilePath =
+ ART_PROFILE_SNAPSHOT_DEBUG_LOCATION + packageName + outputFileSuffix + ".prof";
+ try (OutputStream outStream = new FileOutputStream(outputProfilePath)) {
+ Streams.copy(inStream, outStream);
+ }
+ } catch (IOException e) {
+ pw.println("Error when reading the profile fd: " + e.getMessage());
+ e.printStackTrace(pw);
+ return -1;
+ }
+ return 0;
+ }
+
+ private static class SnapshotRuntimeProfileCallback
+ extends ISnapshotRuntimeProfileCallback.Stub {
+ private boolean mSuccess = false;
+ private int mErrCode = -1;
+ private ParcelFileDescriptor mProfileReadFd = null;
+ private CountDownLatch mDoneSignal = new CountDownLatch(1);
+
+ @Override
+ public void onSuccess(ParcelFileDescriptor profileReadFd) {
+ mSuccess = true;
+ try {
+ // We need to dup the descriptor. We are in the same process as system server
+ // and we will be receiving the same object (which will be closed on the
+ // server side).
+ mProfileReadFd = profileReadFd.dup();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ mDoneSignal.countDown();
+ }
+
+ @Override
+ public void onError(int errCode) {
+ mSuccess = false;
+ mErrCode = errCode;
+ mDoneSignal.countDown();
+ }
+
+ boolean waitTillDone() {
+ boolean done = false;
+ try {
+ // The time-out is an arbitrary large value. Since this is a local call the result
+ // will come very fast.
+ done = mDoneSignal.await(10000000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ignored) {
+ }
+ return done && mSuccess;
+ }
+ }
+
private int runUninstall() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
int flags = 0;
@@ -2761,7 +2895,13 @@
pw.println("");
pw.println(" dump-profiles TARGET-PACKAGE");
pw.println(" Dumps method/class profile files to");
- pw.println(" /data/misc/profman/TARGET-PACKAGE.txt");
+ pw.println(" " + ART_PROFILE_SNAPSHOT_DEBUG_LOCATION + "TARGET-PACKAGE.txt");
+ pw.println("");
+ pw.println(" snapshot-profile TARGET-PACKAGE [--code-path path]");
+ pw.println(" Take a snapshot of the package profiles to");
+ pw.println(" " + ART_PROFILE_SNAPSHOT_DEBUG_LOCATION
+ + "TARGET-PACKAGE[-code-path].prof");
+ pw.println(" If TARGET-PACKAGE=android it will take a snapshot of the boot image");
pw.println("");
pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT");
pw.println(" Set the default home activity (aka launcher).");
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 1d5c580..0ba7822 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -34,6 +34,7 @@
import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -44,6 +45,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.RoSystemProperties;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
@@ -106,7 +108,7 @@
LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
}
- private boolean checkPermission(int callingUid, String callingPackage) {
+ private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
// Callers always need this permission
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_RUNTIME_PROFILES, TAG);
@@ -125,11 +127,51 @@
}
}
+ /**
+ * Checks if the calling user is the shell user and if it is, it checks if it can
+ * to take a profile snapshot of the give package:
+ * - on debuggable builds the shell user can take profile snapshots of any app.
+ * - on non-debuggable builds the shell user can only take snapshots of debuggable apps.
+ *
+ * Returns true iff the callingUid is the shell uid and the shell is allowed snapshot profiles.
+ *
+ * Note that the root users will go through the regular {@link #checkAndroidPermissions) checks.
+ */
+ private boolean checkShellPermissions(@ProfileType int profileType, String packageName,
+ int callingUid) {
+ if (callingUid != Process.SHELL_UID) {
+ return false;
+ }
+ if (RoSystemProperties.DEBUGGABLE) {
+ return true;
+ }
+ if (profileType == ArtManager.PROFILE_BOOT_IMAGE) {
+ // The shell cannot profile the boot image on non-debuggable builds.
+ return false;
+ }
+ PackageInfo info = null;
+ try {
+ info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+ } catch (RemoteException ignored) {
+ // Should not happen.
+ }
+ if (info == null) {
+ return false;
+ }
+
+ // On user builds the shell can only profile debuggable apps.
+ return (info.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)
+ == ApplicationInfo.FLAG_DEBUGGABLE;
+ }
+
+
@Override
public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
@Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback,
String callingPackage) {
- if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
+ int callingUid = Binder.getCallingUid();
+ if (!checkShellPermissions(profileType, packageName, callingUid) &&
+ !checkAndroidPermissions(callingUid, callingPackage)) {
try {
callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
} catch (RemoteException ignored) {
@@ -266,7 +308,8 @@
@Override
public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) {
- if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SHELL_UID && !checkAndroidPermissions(callingUid, callingPackage)) {
return false;
}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 3e63fb4..392d4d8 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -16,17 +16,25 @@
package com.android.server.pm.dex;
+import android.content.ContentResolver;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.database.ContentObserver;
+import android.os.Build;
import android.os.FileUtils;
import android.os.RemoteException;
import android.os.storage.StorageManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
-
+import android.provider.Settings.Global;
import android.util.Slog;
+import android.util.jar.StrictJarFile;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageDexOptimizer;
@@ -36,13 +44,16 @@
import java.io.File;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.zip.ZipEntry;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
@@ -59,8 +70,14 @@
public class DexManager {
private static final String TAG = "DexManager";
+ private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
+ private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
+ "pm.dexopt.priv-apps-oob-list";
+
private static final boolean DEBUG = false;
+ private final Context mContext;
+
// Maps package name to code locations.
// It caches the code locations for the installed packages. This allows for
// faster lookups (no locks) when finding what package owns the dex file.
@@ -106,8 +123,9 @@
String dexPath, int storageFlags);
}
- public DexManager(IPackageManager pms, PackageDexOptimizer pdo,
+ public DexManager(Context context, IPackageManager pms, PackageDexOptimizer pdo,
Installer installer, Object installLock, Listener listener) {
+ mContext = context;
mPackageCodeLocationsCache = new HashMap<>();
mPackageDexUsage = new PackageDexUsage();
mPackageManager = pms;
@@ -117,6 +135,10 @@
mListener = listener;
}
+ public void systemReady() {
+ registerSettingObserver();
+ }
+
/**
* Notify about dex files loads.
* Note that this method is invoked when apps load dex files and it should
@@ -641,6 +663,141 @@
mPackageDexUsage.writeNow();
}
+ private void registerSettingObserver() {
+ final ContentResolver resolver = mContext.getContentResolver();
+
+ // This observer provides a one directional mapping from Global.PRIV_APP_OOB_ENABLED to
+ // pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
+ // it is done.
+ ContentObserver privAppOobObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
+ SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
+ oobEnabled == 1 ? "true" : "false");
+ }
+ };
+ resolver.registerContentObserver(
+ Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
+ UserHandle.USER_SYSTEM);
+ // At boot, restore the value from the setting, which persists across reboot.
+ privAppOobObserver.onChange(true);
+
+ ContentObserver privAppOobListObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ String oobList = Global.getString(resolver, Global.PRIV_APP_OOB_LIST);
+ if (oobList == null) {
+ oobList = "ALL";
+ }
+ SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, oobList);
+ }
+ };
+ resolver.registerContentObserver(
+ Global.getUriFor(Global.PRIV_APP_OOB_LIST), false, privAppOobListObserver,
+ UserHandle.USER_SYSTEM);
+ // At boot, restore the value from the setting, which persists across reboot.
+ privAppOobListObserver.onChange(true);
+ }
+
+ /**
+ * Returns whether the given package is in the list of privilaged apps that should run out of
+ * box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that when
+ * the the OOB list is empty, all priv apps will run in OOB mode.
+ */
+ public static boolean isPackageSelectedToRunOob(String packageName) {
+ return isPackageSelectedToRunOob(Arrays.asList(packageName));
+ }
+
+ /**
+ * Returns whether any of the given packages are in the list of privilaged apps that should run
+ * out of box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that
+ * when the the OOB list is empty, all priv apps will run in OOB mode.
+ */
+ public static boolean isPackageSelectedToRunOob(Collection<String> packageNamesInSameProcess) {
+ if (!SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
+ return false;
+ }
+ String oobListProperty = SystemProperties.get(
+ PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL");
+ if ("ALL".equals(oobListProperty)) {
+ return true;
+ }
+ for (String oobPkgName : oobListProperty.split(",")) {
+ if (packageNamesInSameProcess.contains(oobPkgName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Generates package related log if the package has code stored in unexpected way.
+ */
+ public static void maybeLogUnexpectedPackageDetails(PackageParser.Package pkg) {
+ if (!Build.IS_DEBUGGABLE) {
+ return;
+ }
+
+ if (pkg.isPrivileged() && isPackageSelectedToRunOob(pkg.packageName)) {
+ logIfPackageHasUncompressedCode(pkg);
+ }
+ }
+
+ /**
+ * Generates log if the APKs in the given package have uncompressed dex file and so
+ * files that can be direclty mapped.
+ */
+ private static void logIfPackageHasUncompressedCode(PackageParser.Package pkg) {
+ logIfApkHasUncompressedCode(pkg.baseCodePath);
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+ logIfApkHasUncompressedCode(pkg.splitCodePaths[i]);
+ }
+ }
+ }
+
+ /**
+ * Generates log if the archive located at {@code fileName} has uncompressed dex file and so
+ * files that can be direclty mapped.
+ */
+ private static void logIfApkHasUncompressedCode(String fileName) {
+ StrictJarFile jarFile = null;
+ try {
+ jarFile = new StrictJarFile(fileName,
+ false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
+ Iterator<ZipEntry> it = jarFile.iterator();
+ while (it.hasNext()) {
+ ZipEntry entry = it.next();
+ if (entry.getName().endsWith(".dex")) {
+ if (entry.getMethod() != ZipEntry.STORED) {
+ Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
+ entry.getName());
+ } else if ((entry.getDataOffset() & 0x3) != 0) {
+ Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
+ entry.getName());
+ }
+ } else if (entry.getName().endsWith(".so")) {
+ if (entry.getMethod() != ZipEntry.STORED) {
+ Slog.w(TAG, "APK " + fileName + " has compressed native code " +
+ entry.getName());
+ } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
+ Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
+ entry.getName());
+ }
+ }
+ }
+ } catch (IOException ignore) {
+ Slog.wtf(TAG, "Error when parsing APK " + fileName);
+ } finally {
+ try {
+ if (jarFile != null) {
+ jarFile.close();
+ }
+ } catch (IOException ignore) {}
+ }
+ }
+
public static class RegisterDexModuleResult {
public RegisterDexModuleResult() {
this(false, null);
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 d3526f7..36fc120 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -449,9 +449,10 @@
userId) == PackageManager.PERMISSION_GRANTED) {
EventLog.writeEvent(0x534e4554, "72710897",
newPackage.applicationInfo.uid,
- "Revoking permission", permissionName, "from package",
- packageName, "as the group changed from",
- oldPermissionGroupName, "to", newPermissionGroupName);
+ "Revoking permission " + permissionName +
+ " from package " + packageName +
+ " as the group changed from " + oldPermissionGroupName +
+ " to " + newPermissionGroupName);
try {
revokeRuntimePermission(permissionName, packageName, false,
@@ -620,9 +621,8 @@
enforcePermissionCapLocked(info, tree);
bp = new BasePermission(info.name, tree.getSourcePackageName(),
BasePermission.TYPE_DYNAMIC);
- } else if (bp.isDynamic()) {
- // TODO: switch this back to SecurityException
- Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
+ } else if (!bp.isDynamic()) {
+ throw new SecurityException("Not allowed to modify non-dynamic permission "
+ info.name);
}
changed = bp.addToTree(fixedLevel, info, tree);
diff --git a/services/core/java/com/android/server/policy/IconUtilities.java b/services/core/java/com/android/server/policy/IconUtilities.java
index b196dec..884d7d4 100644
--- a/services/core/java/com/android/server/policy/IconUtilities.java
+++ b/services/core/java/com/android/server/policy/IconUtilities.java
@@ -16,6 +16,8 @@
package com.android.server.policy;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
@@ -38,24 +40,17 @@
* Various utilities shared amongst the Launcher's classes.
*/
public final class IconUtilities {
- private static final String TAG = "IconUtilities";
-
- private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
private int mIconWidth = -1;
private int mIconHeight = -1;
private int mIconTextureWidth = -1;
private int mIconTextureHeight = -1;
- private final Paint mPaint = new Paint();
- private final Paint mBlurPaint = new Paint();
- private final Paint mGlowColorPressedPaint = new Paint();
- private final Paint mGlowColorFocusedPaint = new Paint();
private final Rect mOldBounds = new Rect();
private final Canvas mCanvas = new Canvas();
private final DisplayMetrics mDisplayMetrics;
- private int mColorIndex = 0;
+ private ColorFilter mDisabledColorFilter;
public IconUtilities(Context context) {
final Resources resources = context.getResources();
@@ -65,39 +60,10 @@
mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
-
- mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL));
-
- TypedValue value = new TypedValue();
- mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute(
- android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300);
- mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
- mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute(
- android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00);
- mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
-
- ColorMatrix cm = new ColorMatrix();
- cm.setSaturation(0.2f);
-
mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
Paint.FILTER_BITMAP_FLAG));
}
- public Drawable createIconDrawable(Drawable src) {
- Bitmap scaled = createIconBitmap(src);
-
- StateListDrawable result = new StateListDrawable();
-
- result.addState(new int[] { android.R.attr.state_focused },
- new BitmapDrawable(createSelectedBitmap(scaled, false)));
- result.addState(new int[] { android.R.attr.state_pressed },
- new BitmapDrawable(createSelectedBitmap(scaled, true)));
- result.addState(new int[0], new BitmapDrawable(scaled));
-
- result.setBounds(0, 0, mIconTextureWidth, mIconTextureHeight);
- return result;
- }
-
/**
* Returns a bitmap suitable for the all apps view. The bitmap will be a power
* of two sized ARGB_8888 bitmap that can be used as a gl texture.
@@ -150,15 +116,6 @@
final int left = (textureWidth-width) / 2;
final int top = (textureHeight-height) / 2;
- if (false) {
- // draw a big box for the icon for debugging
- canvas.drawColor(sColors[mColorIndex]);
- if (++mColorIndex >= sColors.length) mColorIndex = 0;
- Paint debugPaint = new Paint();
- debugPaint.setColor(0xffcccc00);
- canvas.drawRect(left, top, left+width, top+height, debugPaint);
- }
-
mOldBounds.set(icon.getBounds());
icon.setBounds(left, top, left+width, top+height);
icon.draw(canvas);
@@ -167,24 +124,28 @@
return bitmap;
}
- private Bitmap createSelectedBitmap(Bitmap src, boolean pressed) {
- final Bitmap result = Bitmap.createBitmap(mIconTextureWidth, mIconTextureHeight,
- Bitmap.Config.ARGB_8888);
- final Canvas dest = new Canvas(result);
+ public ColorFilter getDisabledColorFilter() {
+ if (mDisabledColorFilter != null) {
+ return mDisabledColorFilter;
+ }
+ ColorMatrix brightnessMatrix = new ColorMatrix();
+ float brightnessF = 0.5f;
+ int brightnessI = (int) (255 * brightnessF);
+ // Brightness: C-new = C-old*(1-amount) + amount
+ float scale = 1f - brightnessF;
+ float[] mat = brightnessMatrix.getArray();
+ mat[0] = scale;
+ mat[6] = scale;
+ mat[12] = scale;
+ mat[4] = brightnessI;
+ mat[9] = brightnessI;
+ mat[14] = brightnessI;
- dest.drawColor(0, PorterDuff.Mode.CLEAR);
+ ColorMatrix filterMatrix = new ColorMatrix();
+ filterMatrix.setSaturation(0);
+ filterMatrix.preConcat(brightnessMatrix);
- int[] xy = new int[2];
- Bitmap mask = src.extractAlpha(mBlurPaint, xy);
-
- dest.drawBitmap(mask, xy[0], xy[1],
- pressed ? mGlowColorPressedPaint : mGlowColorFocusedPaint);
-
- mask.recycle();
-
- dest.drawBitmap(src, 0, 0, mPaint);
- dest.setBitmap(null);
-
- return result;
+ mDisabledColorFilter = new ColorMatrixColorFilter(filterMatrix);
+ return mDisabledColorFilter;
}
}
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index cfce5cf..c04c1fb 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -310,6 +310,11 @@
return R.string.config_batterySaverDeviceSpecificConfig;
}
+ @VisibleForTesting
+ boolean isAccessibilityEnabled() {
+ return mAccessibilityManager.isEnabled();
+ }
+
@Override
public void onChange(boolean selfChange, Uri uri) {
refreshSettings();
@@ -403,7 +408,7 @@
parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
// Update the effective policy.
- mAccessibilityEnabled = mAccessibilityManager.isEnabled();
+ mAccessibilityEnabled = isAccessibilityEnabled();
mVibrationDisabledEffective = mVibrationDisabledConfig
&& !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 966ca41..ee03aff 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
@@ -31,9 +32,12 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static android.view.WindowManager.TRANSIT_UNSET;
+import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -1684,12 +1688,24 @@
}
}
+ private boolean shouldAnimate(int transit) {
+ final boolean isSplitScreenPrimary =
+ getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+ final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
+
+ // We animate always if it's not split screen primary, and only some special cases in split
+ // screen primary because it causes issues with stack clipping when we run an un-minimize
+ // animation at the same time.
+ return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
+ }
+
boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction) {
- if (mService.mDisableTransitionAnimation) {
+ if (mService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- Slog.v(TAG_WM, "applyAnimation: transition animation is disabled. atoken=" + this);
+ Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped."
+ + " atoken=" + this);
}
cancelAnimation();
return false;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 553b4fe..9da6917 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -426,9 +426,13 @@
removeAnimation(taskAdapter);
}
+ // Clear any pending failsafe runnables
+ mService.mH.removeCallbacks(mFailsafeRunnable);
+
// Clear references to the runner
unlinkToDeathOfRunner();
mRunner = null;
+ mCanceled = true;
// Clear associated input consumers
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ab93a8a..729dba5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5525,9 +5525,11 @@
// If there is a profile owner, redirect to that; otherwise query the device owner.
ComponentName aliasChooser = getProfileOwner(caller.getIdentifier());
if (aliasChooser == null && caller.isSystem()) {
- ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
- if (deviceOwnerAdmin != null) {
- aliasChooser = deviceOwnerAdmin.info.getComponent();
+ synchronized (getLockObject()) {
+ final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
+ if (deviceOwnerAdmin != null) {
+ aliasChooser = deviceOwnerAdmin.info.getComponent();
+ }
}
}
if (aliasChooser == null) {
@@ -5906,35 +5908,41 @@
private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
wtfIfInLock();
-
- if (wipeExtRequested) {
- StorageManager sm = (StorageManager) mContext.getSystemService(
- Context.STORAGE_SERVICE);
- sm.wipeAdoptableDisks();
- }
+ boolean success = false;
try {
+ if (wipeExtRequested) {
+ StorageManager sm = (StorageManager) mContext.getSystemService(
+ Context.STORAGE_SERVICE);
+ sm.wipeAdoptableDisks();
+ }
mInjector.recoverySystemRebootWipeUserData(
- /*shutdown=*/ false, reason, /*force=*/ true, /*wipeEuicc=*/ wipeEuicc);
+ /*shutdown=*/ false, reason, /*force=*/ true, /*wipeEuicc=*/ wipeEuicc);
+ success = true;
} catch (IOException | SecurityException e) {
Slog.w(LOG_TAG, "Failed requesting data wipe", e);
+ } finally {
+ if (!success) SecurityLog.writeEvent(SecurityLog.TAG_WIPE_FAILURE);
}
}
private void forceWipeUser(int userId, String wipeReasonForUser) {
+ boolean success = false;
try {
IActivityManager am = mInjector.getIActivityManager();
if (am.getCurrentUser().id == userId) {
am.switchUser(UserHandle.USER_SYSTEM);
}
- boolean userRemoved = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
- if (!userRemoved) {
+ success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
+ if (!success) {
Slog.w(LOG_TAG, "Couldn't remove user " + userId);
} else if (isManagedProfile(userId)) {
sendWipeProfileNotification(wipeReasonForUser);
}
} catch (RemoteException re) {
// Shouldn't happen
+ } finally {
+ if (!success) SecurityLog.writeEvent(SecurityLog.TAG_WIPE_FAILURE);
}
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 2bf6e92..a7209a0 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -429,9 +429,13 @@
try {
mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
synchronized(this) {
- // Clear APF memory.
- byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
- mIpClientCallback.installPacketFilter(zeroes);
+ // Clear the APF memory to reset all counters upon connecting to the first AP
+ // in an SSID. This is limited to APFv4 devices because this large write triggers
+ // a crash on some older devices (b/78905546).
+ if (mApfCapabilities.hasDataAccess()) {
+ byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
+ mIpClientCallback.installPacketFilter(zeroes);
+ }
// Install basic filters
installNewProgramLocked();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
index a14b950..b4b34c5 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
@@ -40,6 +40,7 @@
import android.support.test.filters.SmallTest;
import android.testing.DexmakerShareClassLoaderRule;
+import com.android.internal.app.SuspendedAppActivity;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.server.LocalServices;
import com.android.server.pm.PackageManagerService;
@@ -150,6 +151,28 @@
}
@Test
+ public void testSuspendedPackage() {
+ mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
+ final String suspendingPackage = "com.test.suspending.package";
+ final String dialogMessage = "Test Message";
+ when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(suspendingPackage);
+ when(mPackageManagerInternal.getSuspendedDialogMessage(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(dialogMessage);
+ // THEN calling intercept returns true
+ assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
+
+ // Check intent parameters
+ assertEquals(dialogMessage,
+ mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE));
+ assertEquals(suspendingPackage,
+ mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_SUSPENDING_PACKAGE));
+ assertEquals(TEST_PACKAGE_NAME,
+ mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_SUSPENDED_PACKAGE));
+ assertEquals(TEST_USER_ID, mInterceptor.mIntent.getIntExtra(Intent.EXTRA_USER_ID, -1000));
+ }
+
+ @Test
public void testInterceptQuietProfile() {
// GIVEN that the user the activity is starting as is currently in quiet mode
when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 36d0c8b..147347d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -111,7 +111,8 @@
DELEGATE_LAST_CLASS_LOADER_NAME);
mDexManager = new DexManager(
- mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock, mListener);
+ /*Context*/ null, mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock,
+ mListener);
// Foo and Bar are available to user0.
// Only Bar is available to user1;
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 20cf733..761c1f1 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.power;
+import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Handler;
@@ -41,7 +42,8 @@
private static final float DEFAULT_BRIGHTNESS_FACTOR = 0.5f;
private static final float PRECISION = 0.001f;
private static final int GPS_MODE = 0;
- private static final int DEFAULT_GPS_MODE = 0;
+ private static final int DEFAULT_GPS_MODE =
+ PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
private static final String BATTERY_SAVER_CONSTANTS = "vibration_disabled=true,"
+ "animation_disabled=false,"
+ "soundtrigger_disabled=true,"
@@ -69,6 +71,10 @@
return mDeviceSpecificConfigResId;
}
+ @Override
+ boolean isAccessibilityEnabled() {
+ return mMockAccessibilityEnabled;
+ }
@VisibleForTesting
void onChange() {
@@ -83,11 +89,15 @@
private final ArrayMap<String, String> mMockGlobalSettings = new ArrayMap<>();
private int mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
+ private boolean mMockAccessibilityEnabled;
+
public void setUp() throws Exception {
super.setUp();
MockitoAnnotations.initMocks(this);
mBatterySaverPolicy = new BatterySaverPolicyForTest(mHandler);
mBatterySaverPolicy.systemReady(getContext());
+
+ mMockAccessibilityEnabled = false;
}
@SmallTest
@@ -101,6 +111,12 @@
}
@SmallTest
+ public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() {
+ mMockAccessibilityEnabled = true;
+ testServiceDefaultValue_unchanged(ServiceType.VIBRATION);
+ }
+
+ @SmallTest
public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() {
testServiceDefaultValue(ServiceType.SOUND);
}
@@ -117,7 +133,7 @@
@SmallTest
public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() {
- testServiceDefaultValue(ServiceType.ANIMATION);
+ testServiceDefaultValue_unchanged(ServiceType.ANIMATION);
}
@SmallTest
@@ -144,11 +160,7 @@
@SmallTest
public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
- testServiceDefaultValue(ServiceType.SCREEN_BRIGHTNESS);
-
- PowerSaveState stateOn =
- mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS, true);
- assertThat(stateOn.brightnessFactor).isWithin(PRECISION).of(DEFAULT_BRIGHTNESS_FACTOR);
+ testServiceDefaultValue_unchanged(ServiceType.SCREEN_BRIGHTNESS);
}
@SmallTest
@@ -222,6 +234,17 @@
assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
}
+ private void testServiceDefaultValue_unchanged(@ServiceType int type) {
+ mBatterySaverPolicy.updateConstantsLocked("", "");
+ final PowerSaveState batterySaverStateOn =
+ mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
+ assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
+
+ final PowerSaveState batterySaverStateOff =
+ mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
+ assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
+ }
+
public void testDeviceSpecific() {
mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
mMockGlobalSettings.put(Global.BATTERY_SAVER_CONSTANTS, "");
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index fbf6691..a2af9b8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -19,6 +19,9 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
@@ -82,6 +85,25 @@
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
}
+ @Test
+ public void testCancelAfterRemove_expectIgnored() throws Exception {
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ AnimationAdapter adapter = mController.addAnimation(appWindow.getTask(),
+ false /* isRecentTaskInvisible */);
+ adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+
+ // Remove the app window so that the animation target can not be created
+ appWindow.removeImmediately();
+ mController.startAnimation();
+ mController.cleanupAnimation(REORDER_KEEP_IN_PLACE);
+ try {
+ mController.cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "test");
+ } catch (Exception e) {
+ fail("Unexpected failure when canceling animation after finishing it");
+ }
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f4bb32d..bafb0a2 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -828,7 +828,12 @@
// internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
private void internalClearGlobalStateLocked() {
// Unregister from call state changes.
- mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ long token = Binder.clearCallingIdentity();
+ try {
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
// Unregister from power save mode changes.
if (mPowerSaveModeListener != null) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a9389be..ece646c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1016,6 +1016,8 @@
if (iSub != null) {
// FIXME: This returns 1 on success, 0 on error should should we return it?
iSub.addSubInfoRecord(iccId, slotIndex);
+ } else {
+ logd("[addSubscriptionInfoRecord]- ISub service is null");
}
} catch (RemoteException ex) {
// ignore it
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 00bf33a..b185a26 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -435,9 +435,10 @@
if (!file.getName().endsWith(".properties")) {
continue;
}
- try {
+
+ try (FileInputStream in = new FileInputStream(file)) {
Properties properties = new Properties();
- properties.load(new FileInputStream(file));
+ properties.load(in);
createModelInfo(properties);
loadedModel = true;
} catch (Exception e) {
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 026b54f..280afade 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -109,23 +109,3 @@
],
static_libs: ["libstatssocket"],
}
-
-cc_library_static {
- name: "libstatssocket",
- srcs: [
- "stats_event_list.c",
- "statsd_writer.c",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- "-DLIBLOG_LOG_TAG=1006",
- "-DWRITE_TO_STATSD=1",
- "-DWRITE_TO_LOGD=0",
- ],
- export_include_dirs: ["include"],
- shared_libs: [
- "liblog",
- ],
-}
-
diff --git a/tools/stats_log_api_gen/include/stats_event_list.h b/tools/stats_log_api_gen/include/stats_event_list.h
deleted file mode 100644
index c198d97..0000000
--- a/tools/stats_log_api_gen/include/stats_event_list.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2018, 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.
- */
-
-#ifndef ANDROID_STATS_LOG_STATS_EVENT_LIST_H
-#define ANDROID_STATS_LOG_STATS_EVENT_LIST_H
-
-#include <log/log_event_list.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-void reset_log_context(android_log_context ctx);
-int write_to_logger(android_log_context context, log_id_t id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-/**
- * A copy of android_log_event_list class.
- *
- * android_log_event_list is going to be deprecated soon, so copy it here to
- * avoid creating dependency on upstream code. TODO(b/78304629): Rewrite this
- * code.
- */
-class stats_event_list {
-private:
- android_log_context ctx;
- int ret;
-
- stats_event_list(const stats_event_list&) = delete;
- void operator=(const stats_event_list&) = delete;
-
-public:
- explicit stats_event_list(int tag) : ret(0) {
- ctx = create_android_logger(static_cast<uint32_t>(tag));
- }
- explicit stats_event_list(log_msg& log_msg) : ret(0) {
- ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
- log_msg.entry.len - sizeof(uint32_t));
- }
- ~stats_event_list() { android_log_destroy(&ctx); }
-
- int close() {
- int retval = android_log_destroy(&ctx);
- if (retval < 0) {
- ret = retval;
- }
- return retval;
- }
-
- /* To allow above C calls to use this class as parameter */
- operator android_log_context() const { return ctx; }
-
- /* return errors or transmit status */
- int status() const { return ret; }
-
- int begin() {
- int retval = android_log_write_list_begin(ctx);
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
- int end() {
- int retval = android_log_write_list_end(ctx);
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
-
- stats_event_list& operator<<(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(uint32_t value) {
- int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(bool value) {
- int retval = android_log_write_int32(ctx, value ? 1 : 0);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(uint64_t value) {
- int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
-#if defined(_USING_LIBCXX)
- stats_event_list& operator<<(const std::string& value) {
- int retval = android_log_write_string8_len(ctx, value.data(),
- value.length());
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-#endif
-
- stats_event_list& operator<<(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- int write(log_id_t id = LOG_ID_EVENTS) {
- /* facilitate -EBUSY retry */
- if ((ret == -EBUSY) || (ret > 0)) {
- ret = 0;
- }
- int retval = write_to_logger(ctx, id);
- /* existing errors trump transmission errors */
- if (!ret) {
- ret = retval;
- }
- return ret;
- }
-
- /*
- * Append<Type> methods removes any integer promotion
- * confusion, and adds access to string with length.
- * Append methods are also added for all types for
- * convenience.
- */
-
- bool AppendInt(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendLong(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendString(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendString(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
-#if defined(_USING_LIBCXX)
- bool AppendString(const std::string& value) {
- int retval = android_log_write_string8_len(ctx, value.data(),
- value.length());
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
-
- bool Append(const std::string& value) {
- int retval = android_log_write_string8_len(ctx, value.data(),
- value.length());
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
-#endif
-
- bool AppendFloat(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- template <typename Tvalue>
- bool Append(Tvalue value) {
- *this << value;
- return ret >= 0;
- }
-
- bool Append(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- android_log_list_element read() { return android_log_read_next(ctx); }
- android_log_list_element peek() { return android_log_peek_next(ctx); }
-};
-
-#endif
-#endif // ANDROID_STATS_LOG_STATS_EVENT_LIST_H
diff --git a/tools/stats_log_api_gen/stats_event_list.c b/tools/stats_log_api_gen/stats_event_list.c
deleted file mode 100644
index 0a342a8..0000000
--- a/tools/stats_log_api_gen/stats_event_list.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2018, 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.
- */
-
-#include "include/stats_event_list.h"
-
-#include <string.h>
-#include "statsd_writer.h"
-
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
-typedef struct {
- uint32_t tag;
- unsigned pos; /* Read/write position into buffer */
- unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
- unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
- unsigned list_nest_depth;
- unsigned len; /* Length or raw buffer. */
- bool overflow;
- bool list_stop; /* next call decrement list_nest_depth and issue a stop */
- enum {
- kAndroidLoggerRead = 1,
- kAndroidLoggerWrite = 2,
- } read_write_flag;
- uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
-} android_log_context_internal;
-
-extern struct android_log_transport_write statsdLoggerWrite;
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr);
-static int (*write_to_statsd)(struct iovec* vec,
- size_t nr) = __write_to_statsd_init;
-
-// Similar to create_android_logger(), but instead of allocation a new buffer,
-// this function resets the buffer for resuse.
-void reset_log_context(android_log_context ctx) {
- if (!ctx) {
- return;
- }
- android_log_context_internal* context =
- (android_log_context_internal*)(ctx);
- uint32_t tag = context->tag;
- memset(context, 0, sizeof(android_log_context_internal));
-
- context->tag = tag;
- context->read_write_flag = kAndroidLoggerWrite;
- size_t needed = sizeof(uint8_t) + sizeof(uint8_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- }
- /* Everything is a list */
- context->storage[context->pos + 0] = EVENT_TYPE_LIST;
- context->list[0] = context->pos + 1;
- context->pos += needed;
-}
-
-int stats_write_list(android_log_context ctx) {
- android_log_context_internal* context;
- const char* msg;
- ssize_t len;
-
- context = (android_log_context_internal*)(ctx);
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
-
- if (context->list_nest_depth) {
- return -EIO;
- }
-
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char*)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
-
- struct iovec vec[2];
- vec[0].iov_base = &context->tag;
- vec[0].iov_len = sizeof(context->tag);
- vec[1].iov_base = (void*)msg;
- vec[1].iov_len = len;
- return write_to_statsd(vec, 2);
-}
-
-int write_to_logger(android_log_context ctx, log_id_t id) {
- int retValue = 0;
-
- if (WRITE_TO_LOGD) {
- retValue = android_log_write_list(ctx, id);
- }
-
- if (WRITE_TO_STATSD) {
- // log_event_list's cast operator is overloaded.
- int ret = stats_write_list(ctx);
- // In debugging phase, we may write to both logd and statsd. Prefer to
- // return statsd socket write error code here.
- if (ret < 0) {
- retValue = ret;
- }
- }
-
- return retValue;
-}
-
-/* log_init_lock assumed */
-static int __write_to_statsd_initialize_locked() {
- if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
- if (statsdLoggerWrite.close) {
- (*statsdLoggerWrite.close)();
- return -ENODEV;
- }
- }
- return 1;
-}
-
-static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
- int ret, save_errno;
- struct timespec ts;
- size_t len, i;
-
- for (len = i = 0; i < nr; ++i) {
- len += vec[i].iov_len;
- }
- if (!len) {
- return -EINVAL;
- }
-
- save_errno = errno;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- ret = 0;
-
- ssize_t retval;
- retval = (*statsdLoggerWrite.write)(&ts, vec, nr);
- if (ret >= 0) {
- ret = retval;
- }
-
- errno = save_errno;
- return ret;
-}
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
- int ret, save_errno = errno;
-
- statsd_writer_init_lock();
-
- if (write_to_statsd == __write_to_statsd_init) {
- ret = __write_to_statsd_initialize_locked();
- if (ret < 0) {
- statsd_writer_init_unlock();
- errno = save_errno;
- return ret;
- }
-
- write_to_statsd = __write_to_stats_daemon;
- }
-
- statsd_writer_init_unlock();
-
- ret = write_to_statsd(vec, nr);
- errno = save_errno;
- return ret;
-}
\ No newline at end of file
diff --git a/tools/stats_log_api_gen/statsd_writer.c b/tools/stats_log_api_gen/statsd_writer.c
deleted file mode 100644
index 3e10358..0000000
--- a/tools/stats_log_api_gen/statsd_writer.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2018, 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.
- */
-#include "statsd_writer.h"
-
-#include <cutils/sockets.h>
-#include <endian.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-/* branchless on many architectures. */
-#define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
-
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-
-void statsd_writer_init_lock() {
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- pthread_mutex_lock(&log_init_lock);
-}
-
-int statd_writer_trylock() {
- return pthread_mutex_trylock(&log_init_lock);
-}
-
-void statsd_writer_init_unlock() {
- pthread_mutex_unlock(&log_init_lock);
-}
-
-static int statsdAvailable();
-static int statsdOpen();
-static void statsdClose();
-static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
-
-struct android_log_transport_write statsdLoggerWrite = {
- .name = "statsd",
- .sock = -EBADF,
- .available = statsdAvailable,
- .open = statsdOpen,
- .close = statsdClose,
- .write = statsdWrite,
-};
-
-/* log_init_lock assumed */
-static int statsdOpen() {
- int i, ret = 0;
-
- i = atomic_load(&statsdLoggerWrite.sock);
- if (i < 0) {
- int sock = TEMP_FAILURE_RETRY(
- socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
- if (sock < 0) {
- ret = -errno;
- } else {
- struct sockaddr_un un;
- memset(&un, 0, sizeof(struct sockaddr_un));
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/statsdw");
-
- if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un,
- sizeof(struct sockaddr_un))) < 0) {
- ret = -errno;
- switch (ret) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- i = atomic_exchange(&statsdLoggerWrite.sock, ret);
- /* FALLTHRU */
- default:
- break;
- }
- close(sock);
- } else {
- ret = atomic_exchange(&statsdLoggerWrite.sock, sock);
- if ((ret >= 0) && (ret != sock)) {
- close(ret);
- }
- ret = 0;
- }
- }
- }
-
- return ret;
-}
-
-static void __statsdClose(int negative_errno) {
- int sock = atomic_exchange(&statsdLoggerWrite.sock, negative_errno);
- if (sock >= 0) {
- close(sock);
- }
-}
-
-static void statsdClose() {
- __statsdClose(-EBADF);
-}
-
-static int statsdAvailable() {
- if (atomic_load(&statsdLoggerWrite.sock) < 0) {
- if (access("/dev/socket/statsdw", W_OK) == 0) {
- return 0;
- }
- return -EBADF;
- }
- return 1;
-}
-
-static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
- ssize_t ret;
- int sock;
- static const unsigned headerLength = 1;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- size_t i, payloadSize;
- static atomic_int dropped;
-
- sock = atomic_load(&statsdLoggerWrite.sock);
- if (sock < 0)
- switch (sock) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- break;
- default:
- return -EBADF;
- }
- /*
- * struct {
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
-
- newVec[0].iov_base = (unsigned char*)&header;
- newVec[0].iov_len = sizeof(header);
-
- // If we dropped events before, try to tell statsd.
- if (sock >= 0) {
- int32_t snapshot =
- atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
- if (snapshot) {
- android_log_event_int_t buffer;
- header.id = LOG_ID_STATS;
- buffer.header.tag = htole32(LIBLOG_LOG_TAG);
- buffer.payload.type = EVENT_TYPE_INT;
- buffer.payload.data = htole32(snapshot);
-
- newVec[headerLength].iov_base = &buffer;
- newVec[headerLength].iov_len = sizeof(buffer);
-
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
- if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
- atomic_fetch_add_explicit(&dropped, snapshot,
- memory_order_relaxed);
- }
- }
- }
-
- header.id = LOG_ID_STATS;
-
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- break;
- }
- }
-
- /*
- * The write below could be lost, but will never block.
- *
- * ENOTCONN occurs if statsd has died.
- * ENOENT occurs if statsd is not running and socket is missing.
- * ECONNREFUSED occurs if we can not reconnect to statsd.
- * EAGAIN occurs if statsd is overloaded.
- */
- if (sock < 0) {
- ret = sock;
- } else {
- ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
- }
- switch (ret) {
- case -ENOTCONN:
- case -ECONNREFUSED:
- case -ENOENT:
- if (statd_writer_trylock()) {
- return ret; /* in a signal handler? try again when less stressed
- */
- }
- __statsdClose(ret);
- ret = statsdOpen();
- statsd_writer_init_unlock();
-
- if (ret < 0) {
- return ret;
- }
-
- ret = TEMP_FAILURE_RETRY(
- writev(atomic_load(&statsdLoggerWrite.sock), newVec, i));
- if (ret < 0) {
- ret = -errno;
- }
- /* FALLTHRU */
- default:
- break;
- }
-
- if (ret > (ssize_t)sizeof(header)) {
- ret -= sizeof(header);
- } else if (ret == -EAGAIN) {
- atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
- }
-
- return ret;
-}
diff --git a/tools/stats_log_api_gen/statsd_writer.h b/tools/stats_log_api_gen/statsd_writer.h
deleted file mode 100644
index 1043afb..0000000
--- a/tools/stats_log_api_gen/statsd_writer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018, 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.
- */
-
-#ifndef ANDROID_STATS_LOG_STATS_WRITER_H
-#define ANDROID_STATS_LOG_STATS_WRITER_H
-
-#include <pthread.h>
-#include <stdatomic.h>
-#include <sys/socket.h>
-
-/**
- * Internal lock should not be exposed. This is bad design.
- * TODO: rewrite it in c++ code and encapsulate the functionality in a
- * StatsdWriter class.
- */
-void statsd_writer_init_lock();
-int statsd_writer_init_trylock();
-void statsd_writer_init_unlock();
-
-struct android_log_transport_write {
- const char* name; /* human name to describe the transport */
- atomic_int sock;
- int (*available)(); /* Does not cause resources to be taken */
- int (*open)(); /* can be called multiple times, reusing current resources */
- void (*close)(); /* free up resources */
- /* write log to transport, returns number of bytes propagated, or -errno */
- int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
-};
-
-
-#endif // ANDROID_STATS_LOG_STATS_WRITER_H