Merge changes Ib03aafe9,Ia51a6db6
* changes:
Abstract content binding into an interface
Move control logic out of NotificationContentInflater
diff --git a/api/current.txt b/api/current.txt
index 5d12f81..8c1d248 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3812,6 +3812,7 @@
method public void onPerformDirectAction(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>);
method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
method @Deprecated public void onPictureInPictureModeChanged(boolean);
+ method public void onPictureInPictureRequested();
method @CallSuper protected void onPostCreate(@Nullable android.os.Bundle);
method public void onPostCreate(@Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
method @CallSuper protected void onPostResume();
@@ -5102,6 +5103,7 @@
method public void callActivityOnDestroy(android.app.Activity);
method public void callActivityOnNewIntent(android.app.Activity, android.content.Intent);
method public void callActivityOnPause(android.app.Activity);
+ method public void callActivityOnPictureInPictureRequested(@NonNull android.app.Activity);
method public void callActivityOnPostCreate(@NonNull android.app.Activity, @Nullable android.os.Bundle);
method public void callActivityOnPostCreate(@NonNull android.app.Activity, @Nullable android.os.Bundle, @Nullable android.os.PersistableBundle);
method public void callActivityOnRestart(android.app.Activity);
@@ -9973,6 +9975,7 @@
field public static final String DOWNLOAD_SERVICE = "download";
field public static final String DROPBOX_SERVICE = "dropbox";
field public static final String EUICC_SERVICE = "euicc";
+ field public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
field public static final String FINGERPRINT_SERVICE = "fingerprint";
field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final String INPUT_METHOD_SERVICE = "input_method";
@@ -41389,6 +41392,11 @@
method public android.security.ConfirmationPrompt.Builder setPromptText(CharSequence);
}
+ public final class FileIntegrityManager {
+ method public boolean isApkVeritySupported();
+ method @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public boolean isAppSourceCertificateTrusted(@NonNull java.security.cert.X509Certificate) throws java.security.cert.CertificateEncodingException;
+ }
+
public final class KeyChain {
ctor public KeyChain();
method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable String, int, @Nullable String);
diff --git a/api/system-current.txt b/api/system-current.txt
index f2433de..1cd0798 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -777,6 +777,7 @@
method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
+ method public boolean hasDeviceIdentifierAccess(@NonNull String, int, int);
method public boolean isDeviceManaged();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
diff --git a/api/test-current.txt b/api/test-current.txt
index 08a2160..3bf2a85 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -105,6 +105,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean moveTopActivityToPinnedStack(int, android.graphics.Rect);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException;
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void requestPictureInPictureMode(@NonNull android.os.IBinder);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeDockedStack(android.graphics.Rect, android.graphics.Rect);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizePinnedStack(int, android.graphics.Rect, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void resizeTask(int, android.graphics.Rect);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9e0c2fc..3f01299 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2837,6 +2837,17 @@
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
}
+ /**
+ * Called by the system when picture in picture mode should be entered if supported.
+ */
+ public void onPictureInPictureRequested() {
+ // Previous recommendation was for apps to enter picture-in-picture in onUserLeaveHint()
+ // which is sent after onPause(). This new method allows the system to request the app to
+ // go into picture-in-picture decoupling it from life cycle events. For backwards
+ // compatibility we schedule the life cycle events if the app didn't override this method.
+ mMainThread.schedulePauseAndReturnToCurrentState(mToken);
+ }
+
void dispatchMovedToDisplay(int displayId, Configuration config) {
updateDisplay(displayId);
onMovedToDisplay(displayId, config);
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 122004c..dd9a2bc 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -433,4 +434,18 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Requests that an activity should enter picture-in-picture mode if possible.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void requestPictureInPictureMode(@NonNull IBinder token) {
+ try {
+ getService().requestPictureInPictureMode(token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index be14556..08f8734 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -41,8 +41,10 @@
import android.app.servertransaction.ActivityResultItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.PendingTransactionActions;
import android.app.servertransaction.PendingTransactionActions.StopInfo;
+import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.TransactionExecutor;
import android.app.servertransaction.TransactionExecutorHelper;
import android.compat.annotation.UnsupportedAppUsage;
@@ -522,6 +524,8 @@
boolean startsNotResumed;
public final boolean isForward;
int pendingConfigChanges;
+ // Whether we are in the process of performing on user leaving.
+ boolean mIsUserLeaving;
Window mPendingRemoveWindow;
WindowManager mPendingRemoveWindowManager;
@@ -3763,6 +3767,66 @@
}
}
+ @Override
+ public void handlePictureInPictureRequested(IBinder token) {
+ final ActivityClientRecord r = mActivities.get(token);
+ if (r == null) {
+ Log.w(TAG, "Activity to request PIP to no longer exists");
+ return;
+ }
+
+ r.activity.onPictureInPictureRequested();
+ }
+
+ /**
+ * Cycle activity through onPause and onUserLeaveHint so that PIP is entered if supported, then
+ * return to its previous state. This allows activities that rely on onUserLeaveHint instead of
+ * onPictureInPictureRequested to enter picture-in-picture.
+ */
+ public void schedulePauseAndReturnToCurrentState(IBinder token) {
+ final ActivityClientRecord r = mActivities.get(token);
+ if (r == null) {
+ Log.w(TAG, "Activity to request pause with user leaving hint to no longer exists");
+ return;
+ }
+
+ if (r.mIsUserLeaving) {
+ // The activity is about to perform user leaving, so there's no need to cycle ourselves.
+ return;
+ }
+
+ final int prevState = r.getLifecycleState();
+ if (prevState != ON_RESUME && prevState != ON_PAUSE) {
+ return;
+ }
+
+ switch (prevState) {
+ case ON_RESUME:
+ // Schedule a PAUSE then return to RESUME.
+ schedulePauseWithUserLeavingHint(r);
+ scheduleResume(r);
+ break;
+ case ON_PAUSE:
+ // Schedule a RESUME then return to PAUSE.
+ scheduleResume(r);
+ schedulePauseWithUserLeavingHint(r);
+ break;
+ }
+ }
+
+ private void schedulePauseWithUserLeavingHint(ActivityClientRecord r) {
+ final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token);
+ transaction.setLifecycleStateRequest(PauseActivityItem.obtain(r.activity.isFinishing(),
+ /* userLeaving */ true, r.activity.mConfigChangeFlags, /* dontReport */ false));
+ executeTransaction(transaction);
+ }
+
+ private void scheduleResume(ActivityClientRecord r) {
+ final ClientTransaction transaction = ClientTransaction.obtain(this.mAppThread, r.token);
+ transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(/* isForward */ false));
+ executeTransaction(transaction);
+ }
+
private void handleLocalVoiceInteractionStarted(IBinder token, IVoiceInteractor interactor) {
final ActivityClientRecord r = mActivities.get(token);
if (r != null) {
@@ -4483,6 +4547,7 @@
if (r != null) {
if (userLeaving) {
performUserLeavingActivity(r);
+ r.mIsUserLeaving = false;
}
r.activity.mConfigChangeFlags |= configChanges;
@@ -4497,6 +4562,8 @@
}
final void performUserLeavingActivity(ActivityClientRecord r) {
+ r.mIsUserLeaving = true;
+ mInstrumentation.callActivityOnPictureInPictureRequested(r.activity);
mInstrumentation.callActivityOnUserLeaving(r.activity);
}
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index d308adc..f9a689a 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -158,6 +158,9 @@
public abstract void handlePictureInPictureModeChanged(IBinder token, boolean isInPipMode,
Configuration overrideConfig);
+ /** Request that an activity enter picture-in-picture. */
+ public abstract void handlePictureInPictureRequested(IBinder token);
+
/** Update window visibility. */
public abstract void handleWindowVisibility(IBinder token, boolean show);
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index df5d6c7..700b3c1 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -333,6 +333,7 @@
boolean isInPictureInPictureMode(in IBinder token);
boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
+ void requestPictureInPictureMode(in IBinder token);
int getMaxNumPictureInPictureActions(in IBinder token);
IBinder getUriPermissionOwnerForActivity(in IBinder activityToken);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 9e552e6..62c905d 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1519,6 +1519,16 @@
public void callActivityOnUserLeaving(Activity activity) {
activity.performUserLeaving();
}
+
+ /**
+ * Perform calling of an activity's {@link Activity#onPictureInPictureRequested} method.
+ * The default implementation simply calls through to that method.
+ *
+ * @param activity The activity being notified that picture-in-picture is being requested.
+ */
+ public void callActivityOnPictureInPictureRequested(@NonNull Activity activity) {
+ activity.onPictureInPictureRequested();
+ }
/*
* Starts allocation counting. This triggers a gc and resets the counts.
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index b5e7f41..31c73b9 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -162,6 +162,8 @@
import android.permission.PermissionManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.security.FileIntegrityManager;
+import android.security.IFileIntegrityService;
import android.service.oemlock.IOemLockService;
import android.service.oemlock.OemLockManager;
import android.service.persistentdata.IPersistentDataBlockService;
@@ -1214,6 +1216,7 @@
return new DynamicSystemManager(
IDynamicSystemService.Stub.asInterface(b));
}});
+
registerService(Context.BATTERY_STATS_SERVICE, BatteryStatsManager.class,
new CachedServiceFetcher<BatteryStatsManager>() {
@Override
@@ -1247,6 +1250,17 @@
return new IncrementalManager(
IIncrementalManagerNative.Stub.asInterface(b));
}});
+
+ registerService(Context.FILE_INTEGRITY_SERVICE, FileIntegrityManager.class,
+ new CachedServiceFetcher<FileIntegrityManager>() {
+ @Override
+ public FileIntegrityManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(
+ Context.FILE_INTEGRITY_SERVICE);
+ return new FileIntegrityManager(
+ IFileIntegrityService.Stub.asInterface(b));
+ }});
//CHECKSTYLE:ON IndentationCheck
registerService(Context.APP_INTEGRITY_SERVICE, AppIntegrityManager.class,
new CachedServiceFetcher<AppIntegrityManager>() {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 11fecca..acdf919 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6764,8 +6764,9 @@
*
* @hide
*/
- public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
- throwIfParentInstance("checkDeviceIdentifierAccess");
+ @SystemApi
+ public boolean hasDeviceIdentifierAccess(@NonNull String packageName, int pid, int uid) {
+ throwIfParentInstance("hasDeviceIdentifierAccess");
if (packageName == null) {
return false;
}
diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java
index 4d2e9a5..3d04437 100644
--- a/core/java/android/app/servertransaction/ClientTransaction.java
+++ b/core/java/android/app/servertransaction/ClientTransaction.java
@@ -77,8 +77,9 @@
/** Get the list of callbacks. */
@Nullable
+ @VisibleForTesting
@UnsupportedAppUsage
- List<ClientTransactionItem> getCallbacks() {
+ public List<ClientTransactionItem> getCallbacks() {
return mActivityCallbacks;
}
diff --git a/core/java/android/app/servertransaction/EnterPipRequestedItem.java b/core/java/android/app/servertransaction/EnterPipRequestedItem.java
new file mode 100644
index 0000000..b2a1276
--- /dev/null
+++ b/core/java/android/app/servertransaction/EnterPipRequestedItem.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 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 android.app.servertransaction;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+
+/**
+ * Request an activity to enter picture-in-picture mode.
+ * @hide
+ */
+public final class EnterPipRequestedItem extends ClientTransactionItem {
+
+ @Override
+ public void execute(ClientTransactionHandler client, IBinder token,
+ PendingTransactionActions pendingActions) {
+ client.handlePictureInPictureRequested(token);
+ }
+
+ // ObjectPoolItem implementation
+
+ private EnterPipRequestedItem() {}
+
+ /** Obtain an instance initialized with provided params. */
+ public static EnterPipRequestedItem obtain() {
+ EnterPipRequestedItem instance = ObjectPool.obtain(EnterPipRequestedItem.class);
+ if (instance == null) {
+ instance = new EnterPipRequestedItem();
+ }
+ return instance;
+ }
+
+ @Override
+ public void recycle() {
+ ObjectPool.recycle(this);
+ }
+
+ // Parcelable implementation
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) { }
+
+ public static final @android.annotation.NonNull Creator<EnterPipRequestedItem> CREATOR =
+ new Creator<EnterPipRequestedItem>() {
+ public EnterPipRequestedItem createFromParcel(Parcel in) {
+ return new EnterPipRequestedItem();
+ }
+
+ public EnterPipRequestedItem[] newArray(int size) {
+ return new EnterPipRequestedItem[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ @Override
+ public String toString() {
+ return "EnterPipRequestedItem{}";
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 483bf3f..4815d78 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5045,6 +5045,14 @@
public static final String INCREMENTAL_SERVICE = "incremental_service";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.security.FileIntegrityManager}.
+ * @see #getSystemService(String)
+ * @see android.security.FileIntegrityManager
+ */
+ public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index ba4042d..39ddcb2 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -90,6 +90,15 @@
throw new RemoteException();
}
+ public void registerClientCallback(String name, IBinder service, IClientCallback cb)
+ throws RemoteException {
+ throw new RemoteException();
+ }
+
+ public void tryUnregisterService(String name, IBinder service) throws RemoteException {
+ throw new RemoteException();
+ }
+
/**
* Same as mServiceManager but used by apps.
*
diff --git a/core/java/android/security/FileIntegrityManager.java b/core/java/android/security/FileIntegrityManager.java
new file mode 100644
index 0000000..cdd6584
--- /dev/null
+++ b/core/java/android/security/FileIntegrityManager.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 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 android.security;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+/**
+ * This class provides access to file integrity related operations.
+ */
+@SystemService(Context.FILE_INTEGRITY_SERVICE)
+public final class FileIntegrityManager {
+ @NonNull private final IFileIntegrityService mService;
+
+ /** @hide */
+ public FileIntegrityManager(@NonNull IFileIntegrityService service) {
+ mService = service;
+ }
+
+ /**
+ * Returns true if APK Verity is supported on the device. When supported, an APK can be
+ * installed with a fs-verity signature (if verified with trusted App Source Certificate) for
+ * continuous on-access verification.
+ */
+ public boolean isApkVeritySupported() {
+ try {
+ // Go through the service just to avoid exposing the vendor controlled system property
+ // to all apps.
+ return mService.isApkVeritySupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether the given certificate can be used to prove app's install source. Always
+ * return false if the feature is not supported.
+ *
+ * <p>A store can use this API to decide if a signature file needs to be downloaded. Also, if a
+ * store has shipped different certificates before (e.g. with stronger and weaker key), it can
+ * also use this API to download the best signature on the running device.
+ *
+ * @return whether the certificate is trusted in the system
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.INSTALL_PACKAGES,
+ android.Manifest.permission.REQUEST_INSTALL_PACKAGES
+ })
+ public boolean isAppSourceCertificateTrusted(@NonNull X509Certificate certificate)
+ throws CertificateEncodingException {
+ try {
+ return mService.isAppSourceCertificateTrusted(certificate.getEncoded());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/security/IFileIntegrityService.aidl b/core/java/android/security/IFileIntegrityService.aidl
new file mode 100644
index 0000000..ebb8bcb
--- /dev/null
+++ b/core/java/android/security/IFileIntegrityService.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019 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 android.security;
+
+/**
+ * Binder interface to communicate with FileIntegrityService.
+ * @hide
+ */
+interface IFileIntegrityService {
+ boolean isApkVeritySupported();
+ boolean isAppSourceCertificateTrusted(in byte[] certificateBytes);
+}
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index b2a19cf..3006e98 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2517,4 +2517,14 @@
// OS: R
DIALOG_MAGNIFICATION_CAPABILITY = 1816;
+ // OPEN: Settings > Accessibility > Color inversion
+ // CATEGORY: SETTINGS
+ // OS: R
+ ACCESSIBILITY_COLOR_INVERSION_SETTINGS = 1817;
+
+ // OPEN: Settings > Accessibility > Color inversion > Edit shortcut dialog
+ // CATEGORY: SETTINGS
+ // OS: R
+ DIALOG_COLOR_INVERSION_EDIT_SHORTCUT = 1818;
+
}
diff --git a/core/proto/android/util/quotatracker.proto b/core/proto/android/util/quotatracker.proto
index 0dea853..5d022ed 100644
--- a/core/proto/android/util/quotatracker.proto
+++ b/core/proto/android/util/quotatracker.proto
@@ -34,17 +34,25 @@
// Current elapsed realtime.
optional int64 elapsed_realtime = 3;
- message AlarmListener {
+ message InQuotaAlarmListener {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- // Whether the listener is waiting for an alarm or not.
- optional bool is_waiting = 1;
- // The time at which the alarm should go off, in the elapsed realtime timebase. Only
- // valid if is_waiting is true.
- optional int64 trigger_time_elapsed = 2;
- }
+ // The time at which the alarm is set to go off, in the elapsed realtime timebase.
+ optional int64 trigger_time_elapsed = 1;
- // Next tag: 4
+ message Alarm {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional UptcProto uptc = 1;
+
+ // The time at which the UPTC will be in quota, in the elapsed realtime timebase.
+ optional int64 in_quota_time_elapsed = 2;
+ }
+ repeated Alarm alarms = 2;
+ }
+ optional InQuotaAlarmListener in_quota_alarm_listener = 4;
+
+ // Next tag: 5
}
// A com.android.util.quota.Category object.
@@ -118,8 +126,6 @@
repeated Event events = 3;
repeated ExecutionStats execution_stats = 4;
-
- optional QuotaTrackerProto.AlarmListener in_quota_alarm_listener = 5;
}
repeated UptcStats uptc_stats = 3;
@@ -195,8 +201,6 @@
repeated TimingSession saved_sessions = 4;
repeated ExecutionStats execution_stats = 5;
-
- optional QuotaTrackerProto.AlarmListener in_quota_alarm_listener = 6;
}
repeated UptcStats uptc_stats = 3;
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index c7e54f3..1aea98a 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1399,6 +1399,7 @@
</activity>
<activity android:name="android.app.activity.ActivityThreadTest$TestActivity"
+ android:supportsPictureInPicture="true"
android:exported="true">
</activity>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index c50cbe3..beaaa37 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -25,10 +25,12 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.IApplicationThread;
+import android.app.PictureInPictureParams;
import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ActivityRelaunchItem;
import android.app.servertransaction.ClientTransaction;
@@ -332,6 +334,50 @@
assertThat(activity.isResumed()).isTrue();
}
+ @Test
+ public void testHandlePictureInPictureRequested_overriddenToEnter() {
+ final Intent startIntent = new Intent();
+ startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_ENTER, true);
+ final TestActivity activity = mActivityTestRule.launchActivity(startIntent);
+ final ActivityThread activityThread = activity.getActivityThread();
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ activityThread.handlePictureInPictureRequested(activity.getActivityToken());
+ });
+
+ assertTrue(activity.pipRequested());
+ assertTrue(activity.enteredPip());
+ }
+
+ @Test
+ public void testHandlePictureInPictureRequested_overriddenToSkip() {
+ final Intent startIntent = new Intent();
+ startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_SKIP, true);
+ final TestActivity activity = mActivityTestRule.launchActivity(startIntent);
+ final ActivityThread activityThread = activity.getActivityThread();
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ activityThread.handlePictureInPictureRequested(activity.getActivityToken());
+ });
+
+ assertTrue(activity.pipRequested());
+ assertTrue(activity.enterPipSkipped());
+ }
+
+ @Test
+ public void testHandlePictureInPictureRequested_notOverridden() {
+ final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
+ final ActivityThread activityThread = activity.getActivityThread();
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ activityThread.handlePictureInPictureRequested(activity.getActivityToken());
+ });
+
+ assertTrue(activity.pipRequested());
+ assertFalse(activity.enteredPip());
+ assertFalse(activity.enterPipSkipped());
+ }
+
/**
* Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)}
* to try to push activity configuration to the activity for the given sequence number.
@@ -428,9 +474,16 @@
// Test activity
public static class TestActivity extends Activity {
+ static final String PIP_REQUESTED_OVERRIDE_ENTER = "pip_requested_override_enter";
+ static final String PIP_REQUESTED_OVERRIDE_SKIP = "pip_requested_override_skip";
+
int mNumOfConfigChanges;
final Configuration mConfig = new Configuration();
+ private boolean mPipRequested;
+ private boolean mPipEntered;
+ private boolean mPipEnterSkipped;
+
/**
* A latch used to notify tests that we're about to wait for configuration latch. This
* is used to notify test code that preExecute phase for activity configuration change
@@ -460,5 +513,29 @@
}
}
}
+
+ @Override
+ public void onPictureInPictureRequested() {
+ mPipRequested = true;
+ if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_ENTER, false)) {
+ enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
+ mPipEntered = true;
+ } else if (getIntent().getBooleanExtra(PIP_REQUESTED_OVERRIDE_SKIP, false)) {
+ mPipEnterSkipped = true;
+ }
+ super.onPictureInPictureRequested();
+ }
+
+ boolean pipRequested() {
+ return mPipRequested;
+ }
+
+ boolean enteredPip() {
+ return mPipEntered;
+ }
+
+ boolean enterPipSkipped() {
+ return mPipEnterSkipped;
+ }
}
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 20395fb..1d3a399 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -28,6 +28,13 @@
}
prebuilt_etc {
+ name: "preinstalled-packages-platform-overlays.xml",
+ product_specific: true,
+ sub_dir: "sysconfig",
+ src: "preinstalled-packages-platform-overlays.xml",
+}
+
+prebuilt_etc {
name: "hiddenapi-package-whitelist.xml",
sub_dir: "sysconfig",
src: "hiddenapi-package-whitelist.xml",
diff --git a/data/etc/preinstalled-packages-platform-overlays.xml b/data/etc/preinstalled-packages-platform-overlays.xml
new file mode 100644
index 0000000..1724715
--- /dev/null
+++ b/data/etc/preinstalled-packages-platform-overlays.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<!-- System packages to preinstall on all devices with frameworks-base-overlays, per user type.
+ Documentation at frameworks/base/data/etc/preinstalled-packages-platform.xml
+-->
+<config>
+ <install-in-user-type package="com.android.internal.display.cutout.emulation.corner">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.display.cutout.emulation.double">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.display.cutout.emulation.tall">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.gestural">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.gestural_extra_wide_back">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.gestural_narrow_back">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.gestural_wide_back">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.threebutton">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.twobutton">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
+</config>
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index 604b407..efab27f 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -106,4 +106,7 @@
<install-in user-type="FULL" />
<install-in user-type="PROFILE" />
</install-in-user-type>
+ <install-in-user-type package="com.android.wallpaperbackup">
+ <install-in user-type="FULL" />
+ </install-in-user-type>
</config>
diff --git a/media/java/android/media/tv/tuner/ScanMessage.java b/media/java/android/media/tv/tuner/ScanMessage.java
new file mode 100644
index 0000000..35f54f8
--- /dev/null
+++ b/media/java/android/media/tv/tuner/ScanMessage.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2019 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 android.media.tv.tuner;
+
+import android.media.tv.tuner.TunerConstants.ScanMessageType;
+
+/**
+ * Message from frontend during scan operations.
+ *
+ * @hide
+ */
+public class ScanMessage {
+ private final int mType;
+ private final Object mValue;
+
+ private ScanMessage(int type, Object value) {
+ mType = type;
+ mValue = value;
+ }
+
+ /** Gets scan message type. */
+ @ScanMessageType
+ public int getMessageType() {
+ return mType;
+ }
+ /** Message indicates whether frontend is locked or not. */
+ public boolean getIsLocked() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_LOCKED) {
+ throw new IllegalStateException();
+ }
+ return (Boolean) mValue;
+ }
+ /** Message indicates whether the scan has reached the end or not. */
+ public boolean getIsEnd() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_END) {
+ throw new IllegalStateException();
+ }
+ return (Boolean) mValue;
+ }
+ /** Progress message in percent. */
+ public int getProgressPercent() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_PROGRESS_PERCENT) {
+ throw new IllegalStateException();
+ }
+ return (Integer) mValue;
+ }
+ /** Gets frequency. */
+ public int getFrequency() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_FREQUENCY) {
+ throw new IllegalStateException();
+ }
+ return (Integer) mValue;
+ }
+ /** Gets symbol rate. */
+ public int getSymbolRate() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_SYMBOL_RATE) {
+ throw new IllegalStateException();
+ }
+ return (Integer) mValue;
+ }
+ /** Gets PLP IDs. */
+ public int[] getPlpIds() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_PLP_IDS) {
+ throw new IllegalStateException();
+ }
+ return (int[]) mValue;
+ }
+ /** Gets group IDs. */
+ public int[] getGroupIds() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_GROUP_IDS) {
+ throw new IllegalStateException();
+ }
+ return (int[]) mValue;
+ }
+ /** Gets Input stream IDs. */
+ public int[] getInputStreamIds() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS) {
+ throw new IllegalStateException();
+ }
+ return (int[]) mValue;
+ }
+ /** Gets the DVB-T or DVB-S standard. */
+ public int getStandard() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_STANDARD) {
+ throw new IllegalStateException();
+ }
+ return (int) mValue;
+ }
+
+ /** Gets PLP information for ATSC3. */
+ public Atsc3PlpInfo[] getAtsc3PlpInfos() {
+ if (mType != TunerConstants.SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO) {
+ throw new IllegalStateException();
+ }
+ return (Atsc3PlpInfo[]) mValue;
+ }
+
+ /** PLP information for ATSC3. */
+ public static class Atsc3PlpInfo {
+ private final int mPlpId;
+ private final boolean mLlsFlag;
+
+ private Atsc3PlpInfo(int plpId, boolean llsFlag) {
+ mPlpId = plpId;
+ mLlsFlag = llsFlag;
+ }
+
+ /** Gets PLP IDs. */
+ public int getPlpId() {
+ return mPlpId;
+ }
+ /** Gets LLS flag. */
+ public boolean getLlsFlag() {
+ return mLlsFlag;
+ }
+ }
+}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 62d069d..f02c4aa 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -24,6 +24,7 @@
import android.media.tv.tuner.TunerConstants.DemuxPidType;
import android.media.tv.tuner.TunerConstants.FilterSubtype;
import android.media.tv.tuner.TunerConstants.FilterType;
+import android.media.tv.tuner.TunerConstants.FrontendScanType;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -100,9 +101,9 @@
private native Frontend nativeOpenFrontendById(int id);
private native int nativeTune(int type, FrontendSettings settings);
private native int nativeStopTune();
+ private native int nativeScan(int settingsType, FrontendSettings settings, int scanType);
private native int nativeSetLnb(int lnbId);
private native int nativeSetLna(boolean enable);
-
private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
private native List<Integer> nativeGetLnbIds();
@@ -123,6 +124,12 @@
* Invoked when there is a frontend event.
*/
void onEvent(int frontendEventType);
+
+ /**
+ * Invoked when there is a scan message.
+ * @param msg
+ */
+ void onScanMessage(ScanMessage msg);
}
/**
@@ -266,6 +273,14 @@
}
/**
+ * Scan channels.
+ * @hide
+ */
+ public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType) {
+ return nativeScan(settings.getType(), settings, scanType);
+ }
+
+ /**
* Sets Low-Noise Block downconverter (LNB) for satellite frontend.
*
* This assigns a hardware LNB resource to the satellite tuner. It can be
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index 4973b05..2c6d850 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -75,6 +75,7 @@
public static final int DEMUX_T_PID = 1;
public static final int DEMUX_MMPT_PID = 2;
+ @Retention(RetentionPolicy.SOURCE)
@IntDef({FRONTEND_SETTINGS_ANALOG, FRONTEND_SETTINGS_ATSC, FRONTEND_SETTINGS_ATSC3,
FRONTEND_SETTINGS_DVBS, FRONTEND_SETTINGS_DVBC, FRONTEND_SETTINGS_DVBT,
FRONTEND_SETTINGS_ISDBS, FRONTEND_SETTINGS_ISDBS3, FRONTEND_SETTINGS_ISDBT})
@@ -127,6 +128,50 @@
public static final int FILTER_SUBTYPE_PTP = 16;
@Retention(RetentionPolicy.SOURCE)
+ @IntDef({FRONTEND_SCAN_UNDEFINED, FRONTEND_SCAN_AUTO, FRONTEND_SCAN_BLIND})
+ public @interface FrontendScanType {}
+
+ public static final int FRONTEND_SCAN_UNDEFINED = Constants.FrontendScanType.SCAN_UNDEFINED;
+ public static final int FRONTEND_SCAN_AUTO = Constants.FrontendScanType.SCAN_AUTO;
+ public static final int FRONTEND_SCAN_BLIND = Constants.FrontendScanType.SCAN_BLIND;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SCAN_MESSAGE_TYPE_LOCKED, SCAN_MESSAGE_TYPE_END, SCAN_MESSAGE_TYPE_PROGRESS_PERCENT,
+ SCAN_MESSAGE_TYPE_FREQUENCY, SCAN_MESSAGE_TYPE_SYMBOL_RATE, SCAN_MESSAGE_TYPE_PLP_IDS,
+ SCAN_MESSAGE_TYPE_GROUP_IDS, SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS,
+ SCAN_MESSAGE_TYPE_STANDARD, SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO})
+ public @interface ScanMessageType {}
+
+ public static final int SCAN_MESSAGE_TYPE_LOCKED = Constants.FrontendScanMessageType.LOCKED;
+ public static final int SCAN_MESSAGE_TYPE_END = Constants.FrontendScanMessageType.END;
+ public static final int SCAN_MESSAGE_TYPE_PROGRESS_PERCENT =
+ Constants.FrontendScanMessageType.PROGRESS_PERCENT;
+ public static final int SCAN_MESSAGE_TYPE_FREQUENCY =
+ Constants.FrontendScanMessageType.FREQUENCY;
+ public static final int SCAN_MESSAGE_TYPE_SYMBOL_RATE =
+ Constants.FrontendScanMessageType.SYMBOL_RATE;
+ public static final int SCAN_MESSAGE_TYPE_PLP_IDS = Constants.FrontendScanMessageType.PLP_IDS;
+ public static final int SCAN_MESSAGE_TYPE_GROUP_IDS =
+ Constants.FrontendScanMessageType.GROUP_IDS;
+ public static final int SCAN_MESSAGE_TYPE_INPUT_STREAM_IDS =
+ Constants.FrontendScanMessageType.INPUT_STREAM_IDS;
+ public static final int SCAN_MESSAGE_TYPE_STANDARD =
+ Constants.FrontendScanMessageType.STANDARD;
+ public static final int SCAN_MESSAGE_TYPE_ATSC3_PLP_INFO =
+ Constants.FrontendScanMessageType.ATSC3_PLP_INFO;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV,
+ FILTER_SETTINGS_ALP})
+ public @interface FilterSettingsType {}
+
+ public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS;
+ public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP;
+ public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP;
+ public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV;
+ public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP;
+
+ @Retention(RetentionPolicy.SOURCE)
@IntDef({DVR_SETTINGS_RECORD, DVR_SETTINGS_PLAYBACK})
public @interface DvrSettingsType {}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 4a2baed..0cac2af 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -312,6 +312,15 @@
return (int)result;
}
+int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType) {
+ if (mFe == NULL) {
+ ALOGE("frontend is not initialized");
+ return (int)Result::INVALID_STATE;
+ }
+ Result result = mFe->scan(settings, scanType);
+ return (int)result;
+}
+
bool JTuner::openDemux() {
if (mTuner == nullptr) {
return false;
@@ -604,6 +613,13 @@
return 0;
}
+static int android_media_tv_Tuner_scan(
+ JNIEnv *env, jobject thiz, jint settingsType, jobject settings, jint scanType) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->scan(getFrontendSettings(
+ env, settingsType, settings), static_cast<FrontendScanType>(scanType));
+}
+
static int android_media_tv_Tuner_set_lnb(JNIEnv, jobject, jint) {
return 0;
}
@@ -863,6 +879,8 @@
{ "nativeTune", "(ILandroid/media/tv/tuner/FrontendSettings;)I",
(void *)android_media_tv_Tuner_tune },
{ "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune },
+ { "nativeScan", "(ILandroid/media/tv/tuner/FrontendSettings;I)I",
+ (void *)android_media_tv_Tuner_scan },
{ "nativeSetLnb", "(I)I", (void *)android_media_tv_Tuner_set_lnb },
{ "nativeSetLna", "(Z)I", (void *)android_media_tv_Tuner_set_lna },
{ "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 9f9fb27..d37a2d9 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -39,6 +39,7 @@
using ::android::hardware::tv::tuner::V1_0::FrontendId;
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
+using ::android::hardware::tv::tuner::V1_0::FrontendScanType;
using ::android::hardware::tv::tuner::V1_0::FrontendSettings;
using ::android::hardware::tv::tuner::V1_0::IDemux;
using ::android::hardware::tv::tuner::V1_0::IDescrambler;
@@ -122,6 +123,7 @@
jobject getFrontendIds();
jobject openFrontendById(int id);
int tune(const FrontendSettings& settings);
+ int scan(const FrontendSettings& settings, FrontendScanType scanType);
jobject getLnbIds();
jobject openLnbById(int id);
jobject openFilter(DemuxFilterType type, int bufferSize);
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 867100f..0cb3dbd 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -57,6 +57,7 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
+import com.android.systemui.InitController;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
@@ -319,6 +320,7 @@
ShadeController shadeController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
+ InitController initController,
DismissCallbackRegistry dismissCallbackRegistry,
/* Car Settings injected components. */
CarServiceProvider carServiceProvider,
@@ -399,6 +401,7 @@
superStatusBarViewFactory,
statusBarKeyguardViewManager,
viewMediatorCallback,
+ initController,
dismissCallbackRegistry);
mScrimController = scrimController;
mLockscreenLockIconController = lockscreenLockIconController;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index e3bb293..640aeb7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -25,6 +25,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.InitController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.bubbles.BubbleController;
@@ -189,6 +190,7 @@
ShadeController shadeController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
+ InitController initController,
DismissCallbackRegistry dismissCallbackRegistry,
CarServiceProvider carServiceProvider,
Lazy<PowerManagerHelper> powerManagerHelperLazy,
@@ -267,6 +269,7 @@
shadeController,
statusBarKeyguardViewManager,
viewMediatorCallback,
+ initController,
dismissCallbackRegistry,
carServiceProvider,
powerManagerHelperLazy,
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a9ca04b..eecc54c 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -267,7 +267,6 @@
@Inject Lazy<KeyguardEnvironment> mKeyguardEnvironment;
@Inject Lazy<ShadeController> mShadeController;
@Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback;
- @Inject Lazy<InitController> mInitController;
@Inject Lazy<AppOpsController> mAppOpsController;
@Inject Lazy<NavigationBarController> mNavigationBarController;
@Inject Lazy<StatusBarStateController> mStatusBarStateController;
@@ -456,8 +455,6 @@
mProviders.put(NotificationRemoteInputManager.Callback.class,
mNotificationRemoteInputManagerCallback::get);
- mProviders.put(InitController.class, mInitController::get);
-
mProviders.put(AppOpsController.class, mAppOpsController::get);
mProviders.put(NavigationBarController.class, mNavigationBarController::get);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index e08de39..1315152 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -56,6 +56,7 @@
private SystemUI[] mServices;
private boolean mServicesStarted;
private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
+ private SystemUIRootComponent mRootComponent;
public SystemUIApplication() {
super();
@@ -72,9 +73,9 @@
Trace.TRACE_TAG_APP);
log.traceBegin("DependencyInjection");
mContextAvailableCallback.onContextAvailable(this);
- SystemUIRootComponent root = SystemUIFactory.getInstance().getRootComponent();
- mComponentHelper = root.getContextComponentHelper();
- mBootCompleteCache = root.provideBootCacheImpl();
+ mRootComponent = SystemUIFactory.getInstance().getRootComponent();
+ mComponentHelper = mRootComponent.getContextComponentHelper();
+ mBootCompleteCache = mRootComponent.provideBootCacheImpl();
log.traceEnd();
// Set the application theme that is inherited by all services. Note that setting the
@@ -209,7 +210,7 @@
mServices[i].onBootCompleted();
}
}
- Dependency.get(InitController.class).executePostInitTasks();
+ mRootComponent.getInitController().executePostInitTasks();
log.traceEnd();
mServicesStarted = true;
@@ -218,11 +219,7 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mServicesStarted) {
- SystemUIFactory
- .getInstance()
- .getRootComponent()
- .getConfigurationController()
- .onConfigurationChanged(newConfig);
+ mRootComponent.getConfigurationController().onConfigurationChanged(newConfig);
int len = mServices.length;
for (int i = 0; i < len; i++) {
if (mServices[i] != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index e50e0fe0..e14581f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -22,6 +22,7 @@
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.Dependency;
+import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.fragments.FragmentService;
@@ -77,6 +78,13 @@
@Singleton
FragmentService.FragmentCreator createFragmentCreator();
+
+ /**
+ * Creates a InitController.
+ */
+ @Singleton
+ InitController getInitController();
+
/**
* ViewCreator generates all Views that need injection.
*/
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 aaed610..a7084da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -384,6 +384,7 @@
private final ShadeController mShadeController;
private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
private final LightsOutNotifController mLightsOutNotifController;
+ private final InitController mInitController;
private final DismissCallbackRegistry mDismissCallbackRegistry;
// expanded notifications
@@ -681,6 +682,7 @@
SuperStatusBarViewFactory superStatusBarViewFactory,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
+ InitController initController,
DismissCallbackRegistry dismissCallbackRegistry) {
super(context);
mFeatureFlags = featureFlags;
@@ -754,6 +756,7 @@
mLightsOutNotifController = lightsOutNotifController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardViewMediatorCallback = viewMediatorCallback;
+ mInitController = initController;
mDismissCallbackRegistry = dismissCallbackRegistry;
mBubbleExpandListener =
@@ -903,7 +906,7 @@
// set the initial view visibility
int disabledFlags1 = result.mDisabledFlags1;
int disabledFlags2 = result.mDisabledFlags2;
- Dependency.get(InitController.class).addPostInitTask(
+ mInitController.addPostInitTask(
() -> setUpDisableFlags(disabledFlags1, disabledFlags2));
mPluginManager.addPluginListener(
@@ -1232,7 +1235,7 @@
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
mNotificationAlertingManager, rowBinder, mKeyguardStateController,
mKeyguardIndicationController,
- this /* statusBar */, mShadeController, mCommandQueue);
+ this /* statusBar */, mShadeController, mCommandQueue, mInitController);
mNotificationListController =
new NotificationListController(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index ce56381..9824d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -27,6 +27,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.InitController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.bubbles.BubbleController;
@@ -169,6 +170,7 @@
SuperStatusBarViewFactory superStatusBarViewFactory,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
ViewMediatorCallback viewMediatorCallback,
+ InitController initController,
DismissCallbackRegistry dismissCallbackRegistry) {
return new StatusBar(
context,
@@ -243,6 +245,7 @@
superStatusBarViewFactory,
statusBarKeyguardViewManager,
viewMediatorCallback,
+ initController,
dismissCallbackRegistry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 8fc624d..beb4579 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -146,7 +146,8 @@
KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
ShadeController shadeController,
- CommandQueue commandQueue) {
+ CommandQueue commandQueue,
+ InitController initController) {
mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
@@ -193,7 +194,7 @@
Dependency.get(StatusBarWindowController.class));
NotificationListContainer notifListContainer = (NotificationListContainer) stackScroller;
- Dependency.get(InitController.class).addPostInitTask(() -> {
+ initController.addPostInitTask(() -> {
NotificationEntryListener notificationEntryListener = new NotificationEntryListener() {
@Override
public void onEntryRemoved(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index e67aa69..bb9c14b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -26,7 +26,6 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
-import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -86,7 +85,6 @@
Dependency.get(NotificationLockscreenUserManager.class);
NotificationViewHierarchyManager viewHierarchyManager =
Dependency.get(NotificationViewHierarchyManager.class);
- Dependency.get(InitController.class).executePostInitTasks();
entryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
entryManager.addNotificationEntryListener(mEntryListener);
gutsManager.setUpWithPresenter(mPresenter, mListContainer,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 1b05216..c97813d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -38,8 +38,6 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.Dependency;
-import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -107,7 +105,6 @@
mock(KeyguardBypassController.class),
mock(BubbleController.class),
mock(DynamicPrivacyController.class));
- Dependency.get(InitController.class).executePostInitTasks();
mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 7f5105e..f55ea4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -62,7 +62,6 @@
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -233,7 +232,6 @@
mock(PeopleNotificationIdentifier.class)),
mEnvironment
);
- Dependency.get(InitController.class).executePostInitTasks();
mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(mEntryListener);
mEntryManager.setNotificationRemoveInterceptor(mRemoveInterceptor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index deca51f..77a6a26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -47,9 +47,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.ActivityStarterDelegate;
-import com.android.systemui.Dependency;
import com.android.systemui.ExpandHelper;
-import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -170,7 +168,6 @@
),
mock(NotificationEntryManager.KeyguardEnvironment.class));
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
- Dependency.get(InitController.class).executePostInitTasks();
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index f6ed4e6..1296a97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -77,6 +77,7 @@
private FakeMetricsLogger mMetricsLogger;
private ShadeController mShadeController = mock(ShadeController.class);
private StatusBar mStatusBar = mock(StatusBar.class);
+ private InitController mInitController = new InitController();
@Before
public void setup() {
@@ -100,7 +101,6 @@
mDependency.injectMockDependency(VisualStabilityManager.class);
mDependency.injectMockDependency(NotificationGutsManager.class);
mDependency.injectMockDependency(StatusBarWindowController.class);
- mDependency.injectMockDependency(InitController.class);
NotificationEntryManager entryManager =
mDependency.injectMockDependency(NotificationEntryManager.class);
when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
@@ -115,7 +115,7 @@
mock(NotificationAlertingManager.class),
mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class),
mock(KeyguardIndicationController.class),
- mStatusBar, mock(ShadeControllerImpl.class), mCommandQueue);
+ mStatusBar, mock(ShadeControllerImpl.class), mCommandQueue, mInitController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index ca229c9..6ee58bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -74,7 +74,6 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.Dependency;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -247,6 +246,7 @@
mStatusBarNotificationActivityStarterBuilder;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+ private InitController mInitController = new InitController();
@Before
public void setup() throws Exception {
@@ -395,6 +395,7 @@
mSuperStatusBarViewFactory,
mStatusBarKeyguardViewManager,
mViewMediatorCallback,
+ mInitController,
mDismissCallbackRegistry);
when(mStatusBarWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
@@ -419,7 +420,7 @@
mStatusBar.mBarService = mBarService;
mStatusBar.mStackScroller = mStackScroller;
mStatusBar.startKeyguard();
- Dependency.get(InitController.class).executePostInitTasks();
+ mInitController.executePostInitTasks();
notificationLogger.setUpWithContainer(mStackScroller);
}
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index eecc101..8a3ac94 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -51,7 +51,8 @@
NavigationBarModeGesturalOverlay \
NavigationBarModeGesturalOverlayNarrowBack \
NavigationBarModeGesturalOverlayWideBack \
- NavigationBarModeGesturalOverlayExtraWideBack
+ NavigationBarModeGesturalOverlayExtraWideBack \
+ preinstalled-packages-platform-overlays.xml
include $(BUILD_PHONY_PACKAGE)
include $(CLEAR_VARS)
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
new file mode 100644
index 0000000..acf3f79
--- /dev/null
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -0,0 +1,45 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsBatterySavingTestCases",
+ "options": [
+ {"exclude-annotation": "androidx.test.filters.LargeTest"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+ ]
+ },
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {"include-filter": "com.android.server.power"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"}
+ ]
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {"include-filter": "com.android.server.power"},
+ {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+ {
+ "exclude-filter": "com.android.server.power.PowerManagerServiceTest#testWakefulnessAwake_ShouldWakeUpWhenPluggedIn"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsBatterySavingTestCases"
+ },
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {"include-filter": "com.android.server.power"}
+ ]
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {"include-filter": "com.android.server.power"}
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
new file mode 100644
index 0000000..0bbb179
--- /dev/null
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.SystemProperties;
+import android.security.Credentials;
+import android.security.IFileIntegrityService;
+import android.security.KeyStore;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * A {@link SystemService} that provides file integrity related operations.
+ * @hide
+ */
+public class FileIntegrityService extends SystemService {
+ private static final String TAG = "FileIntegrityService";
+
+ private static CertificateFactory sCertFactory;
+
+ private Collection<X509Certificate> mTrustedCertificates = new ArrayList<X509Certificate>();
+
+ private final IBinder mService = new IFileIntegrityService.Stub() {
+ @Override
+ public boolean isApkVeritySupported() {
+ return SystemProperties.getInt("ro.apk_verity.mode", 0) == 2;
+ }
+
+ @Override
+ public boolean isAppSourceCertificateTrusted(byte[] certificateBytes) {
+ enforceAnyCallingPermissions(
+ android.Manifest.permission.REQUEST_INSTALL_PACKAGES,
+ android.Manifest.permission.INSTALL_PACKAGES);
+ try {
+ if (!isApkVeritySupported()) {
+ return false;
+ }
+
+ return mTrustedCertificates.contains(toCertificate(certificateBytes));
+ } catch (CertificateException e) {
+ Slog.e(TAG, "Failed to convert the certificate: " + e);
+ return false;
+ }
+ }
+
+ private void enforceAnyCallingPermissions(String ...permissions) {
+ for (String permission : permissions) {
+ if (getContext().checkCallingPermission(permission)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ }
+ throw new SecurityException("Insufficient permission");
+ }
+ };
+
+ public FileIntegrityService(final Context context) {
+ super(context);
+ try {
+ sCertFactory = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ Slog.wtf(TAG, "Cannot get an instance of X.509 certificate factory");
+ }
+ }
+
+ @Override
+ public void onStart() {
+ loadAllCertificates();
+ publishBinderService(Context.FILE_INTEGRITY_SERVICE, mService);
+ }
+
+ private void loadAllCertificates() {
+ // A better alternative to load certificates would be to read from .fs-verity kernel
+ // keyring, which fsverity_init loads to during earlier boot time from the same sources
+ // below. But since the read operation from keyring is not provided in kernel, we need to
+ // duplicate the same loading logic here.
+
+ // Load certificates trusted by the device manufacturer.
+ loadCertificatesFromDirectory("/product/etc/security/fsverity");
+
+ // Load certificates trusted by the device owner.
+ loadCertificatesFromKeystore(KeyStore.getInstance());
+ }
+
+ private void loadCertificatesFromDirectory(String path) {
+ try {
+ File[] files = new File(path).listFiles();
+ if (files == null) {
+ return;
+ }
+
+ for (File cert : files) {
+ collectCertificate(Files.readAllBytes(cert.toPath()));
+ }
+ } catch (IOException e) {
+ Slog.wtf(TAG, "Failed to load fs-verity certificate from " + path, e);
+ }
+ }
+
+ private void loadCertificatesFromKeystore(KeyStore keystore) {
+ for (final String alias : keystore.list(Credentials.APP_SOURCE_CERTIFICATE,
+ Process.FSVERITY_CERT_UID)) {
+ byte[] certificateBytes = keystore.get(Credentials.APP_SOURCE_CERTIFICATE + alias,
+ Process.FSVERITY_CERT_UID, false /* suppressKeyNotFoundWarning */);
+ if (certificateBytes == null) {
+ Slog.w(TAG, "The retrieved fs-verity certificate is null, ignored " + alias);
+ continue;
+ }
+ collectCertificate(certificateBytes);
+ }
+ }
+
+ /**
+ * Tries to convert {@code bytes} into an X.509 certificate and store in memory.
+ * Errors need to be surpressed in order fo the next certificates to still be collected.
+ */
+ private void collectCertificate(@Nullable byte[] bytes) {
+ try {
+ mTrustedCertificates.add(toCertificate(bytes));
+ } catch (CertificateException | AssertionError e) {
+ Slog.e(TAG, "Invalid certificate, ignored: " + e);
+ }
+ }
+
+ /**
+ * Converts byte array into one X.509 certificate. If multiple certificate is defined, ignore
+ * the rest. The rational is to make it harder to smuggle.
+ */
+ @NonNull
+ private static X509Certificate toCertificate(@Nullable byte[] bytes)
+ throws CertificateException {
+ Certificate certificate = sCertFactory.generateCertificate(new ByteArrayInputStream(bytes));
+ if (!(certificate instanceof X509Certificate)) {
+ throw new CertificateException("Expected to contain an X.509 certificate");
+ }
+ return (X509Certificate) certificate;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 60f051c..331386f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -156,6 +156,8 @@
import android.app.admin.DevicePolicyCache;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.EnterPipRequestedItem;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -4959,6 +4961,44 @@
}
}
+ /**
+ * Requests that an activity should enter picture-in-picture mode if possible.
+ */
+ @Override
+ public void requestPictureInPictureMode(IBinder token) throws RemoteException {
+ mAmInternal.enforceCallingPermission(Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "requestPictureInPictureMode");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final ActivityRecord activity = ActivityRecord.forTokenLocked(token);
+ if (activity == null) {
+ return;
+ }
+
+ final boolean canEnterPictureInPicture = activity.checkEnterPictureInPictureState(
+ "requestPictureInPictureMode", /* beforeStopping */ false);
+ if (!canEnterPictureInPicture) {
+ throw new IllegalStateException(
+ "Requested PIP on an activity that doesn't support it");
+ }
+
+ try {
+ final ClientTransaction transaction = ClientTransaction.obtain(
+ activity.app.getThread(),
+ activity.token);
+ transaction.addCallback(EnterPipRequestedItem.obtain());
+ getLifecycleManager().scheduleTransaction(transaction);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to send enter pip requested item: "
+ + activity.intent.getComponent(), e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
void dumpLastANRLocked(PrintWriter pw) {
pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
if (mLastANRState == null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 50ae376..cfe1318 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -146,6 +146,7 @@
import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.role.RoleManagerService;
import com.android.server.rollback.RollbackManagerService;
+import com.android.server.security.FileIntegrityService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
import com.android.server.signedconfig.SignedConfigService;
@@ -673,6 +674,13 @@
AppCompatCallbacks.install(new long[0]);
t.traceEnd();
+ // FileIntegrityService responds to requests from apps and the system. It needs to run after
+ // the source (i.e. keystore) is ready, and before the apps (or the first customer in the
+ // system) run.
+ t.traceBegin("StartFileIntegrityService");
+ mSystemServiceManager.startService(FileIntegrityService.class);
+ t.traceEnd();
+
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 81fb0ec..13643a0 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -62,6 +62,7 @@
import android.os.PowerSaveState;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.platform.test.annotations.FlakyTest;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.view.Display;
@@ -734,6 +735,7 @@
assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
}
+ @FlakyTest
@Test
public void testInattentiveSleep_goesToSleepWithWakeLock() throws Exception {
final String pkg = mContextSpy.getOpPackageName();
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
index 89c7dd4..ecdc58e 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/FileUpdaterTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
+import android.platform.test.annotations.FlakyTest;
import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
@@ -328,6 +329,7 @@
veriryWtf(0);
}
+ @FlakyTest
@Test
public void testAll() throws Exception {
// Run multiple tests on the single target instance.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index f1de6e9..438de78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -20,20 +20,30 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.PictureInPictureParams;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.EnterPipRequestedItem;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.RemoteException;
import android.view.IDisplayWindowListener;
import android.view.WindowContainerTransaction;
@@ -42,6 +52,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.MockitoSession;
import java.util.ArrayList;
@@ -56,6 +67,9 @@
@RunWith(WindowTestRunner.class)
public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
+ private final ArgumentCaptor<ClientTransaction> mClientTransactionCaptor =
+ ArgumentCaptor.forClass(ClientTransaction.class);
+
@Before
public void setUp() throws Exception {
doReturn(false).when(mService).isBooting();
@@ -78,6 +92,39 @@
}
@Test
+ public void testOnPictureInPictureRequested() throws RemoteException {
+ final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
+ final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
+ ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+ doNothing().when(lifecycleManager).scheduleTransaction(any());
+ doReturn(true).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
+
+ mService.requestPictureInPictureMode(activity.token);
+
+ verify(lifecycleManager).scheduleTransaction(mClientTransactionCaptor.capture());
+ final ClientTransaction transaction = mClientTransactionCaptor.getValue();
+ // Check that only an enter pip request item callback was scheduled.
+ assertEquals(1, transaction.getCallbacks().size());
+ assertTrue(transaction.getCallbacks().get(0) instanceof EnterPipRequestedItem);
+ // Check the activity lifecycle state remains unchanged.
+ assertNull(transaction.getLifecycleStateRequest());
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testOnPictureInPictureRequested_cannotEnterPip() throws RemoteException {
+ final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
+ final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
+ ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+ doNothing().when(lifecycleManager).scheduleTransaction(any());
+ doReturn(false).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
+
+ mService.requestPictureInPictureMode(activity.token);
+
+ // Check enter no transactions with enter pip requests are made.
+ verify(lifecycleManager, times(0)).scheduleTransaction(any());
+ }
+
+ @Test
public void testTaskTransaction() {
removeGlobalMinSizeRestriction();
final ActivityStack stack = new StackBuilder(mRootActivityContainer)
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index fbb1380..80a55b2 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -344,7 +344,7 @@
DevicePolicyManager devicePolicyManager =
(DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
- if (devicePolicyManager != null && devicePolicyManager.checkDeviceIdentifierAccess(
+ if (devicePolicyManager != null && devicePolicyManager.hasDeviceIdentifierAccess(
callingPackage, pid, uid)) {
return true;
}