Merge "Forcefully set system window tokens to fullscreen"
diff --git a/Android.mk b/Android.mk
index 46529eb..d9e202c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,6 +15,14 @@
#
LOCAL_PATH := $(call my-dir)
+$(eval $(call declare-1p-copy-files,frameworks/base,.ogg))
+$(eval $(call declare-1p-copy-files,frameworks/base,.kl))
+$(eval $(call declare-1p-copy-files,frameworks/base,.kcm))
+$(eval $(call declare-1p-copy-files,frameworks/base,.idc))
+$(eval $(call declare-1p-copy-files,frameworks/base,dirty-image-objects))
+$(eval $(call declare-1p-copy-files,frameworks/base/config,))
+$(eval $(call declare-1p-copy-files,frameworks/native/data,))
+
# Load framework-specific path mappings used later in the build.
include $(LOCAL_PATH)/pathmap.mk
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 1c82597..e1b7829 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -134,19 +134,19 @@
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
- R::overlay::integer::int1)),
+ R::overlay::integer::int1)),
std::string::npos)
<< result->stdout_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
- R::overlay::string::str1)),
+ R::overlay::string::str1)),
std::string::npos)
<< result->stdout_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
- R::overlay::string::str3)),
+ R::overlay::string::str3)),
std::string::npos)
<< result->stdout_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
- R::overlay::string::str4)),
+ R::overlay::string::str4)),
std::string::npos)
<< result->stdout_str;
diff --git a/core/api/current.txt b/core/api/current.txt
index 4d1e280..5c3f077 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -631,6 +631,7 @@
field public static final int elevation = 16843840; // 0x1010440
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
+ field public static final int enableOnBackInvokedCallback;
field public static final int enableVrMode = 16844069; // 0x1010525
field public static final int enabled = 16842766; // 0x101000e
field public static final int end = 16843996; // 0x10104dc
@@ -6639,6 +6640,8 @@
method @NonNull public android.app.PictureInPictureParams.Builder setExpandedAspectRatio(@Nullable android.util.Rational);
method @NonNull public android.app.PictureInPictureParams.Builder setSeamlessResizeEnabled(boolean);
method public android.app.PictureInPictureParams.Builder setSourceRectHint(android.graphics.Rect);
+ method @NonNull public android.app.PictureInPictureParams.Builder setSubtitle(@Nullable CharSequence);
+ method @NonNull public android.app.PictureInPictureParams.Builder setTitle(@Nullable CharSequence);
}
public final class PictureInPictureUiState implements android.os.Parcelable {
@@ -39604,7 +39607,7 @@
public class SpeechRecognizer {
method @MainThread public void cancel();
- method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull android.speech.RecognitionSupportCallback);
+ method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull java.util.concurrent.Executor, @NonNull android.speech.RecognitionSupportCallback);
method @MainThread @NonNull public static android.speech.SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull android.content.Context);
method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context);
method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context, android.content.ComponentName);
@@ -47676,15 +47679,11 @@
public final class Choreographer {
method public static android.view.Choreographer getInstance();
- method public void postExtendedFrameCallback(@NonNull android.view.Choreographer.ExtendedFrameCallback);
method public void postFrameCallback(android.view.Choreographer.FrameCallback);
method public void postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long);
- method public void removeExtendedFrameCallback(@Nullable android.view.Choreographer.ExtendedFrameCallback);
+ method public void postVsyncCallback(@NonNull android.view.Choreographer.VsyncCallback);
method public void removeFrameCallback(android.view.Choreographer.FrameCallback);
- }
-
- public static interface Choreographer.ExtendedFrameCallback {
- method public void onVsync(@NonNull android.view.Choreographer.FrameData);
+ method public void removeVsyncCallback(@Nullable android.view.Choreographer.VsyncCallback);
}
public static interface Choreographer.FrameCallback {
@@ -47699,10 +47698,14 @@
public static class Choreographer.FrameTimeline {
method public long getDeadlineNanos();
- method public long getExpectedPresentTimeNanos();
+ method public long getExpectedPresentationTimeNanos();
method public long getVsyncId();
}
+ public static interface Choreographer.VsyncCallback {
+ method public void onVsync(@NonNull android.view.Choreographer.FrameData);
+ }
+
public interface CollapsibleActionView {
method public void onActionViewCollapsed();
method public void onActionViewExpanded();
@@ -49254,6 +49257,7 @@
method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl);
method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer);
+ method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence);
method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int);
method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b1f0b54..273f59c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1656,8 +1656,8 @@
method @NonNull public android.os.Bundle getSearchConstraints();
method @NonNull public String getSource();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "IS_PRESUBMIT_SUGGESTION";
- field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "SEARCH_PROVIDER_FILTER";
+ field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "android.app.cloudsearch.IS_PRESUBMIT_SUGGESTION";
+ field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "android.app.cloudsearch.SEARCH_PROVIDER_FILTER";
field @NonNull public static final android.os.Parcelable.Creator<android.app.cloudsearch.SearchRequest> CREATOR;
}
@@ -1699,23 +1699,23 @@
method @NonNull public String getTitle();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.cloudsearch.SearchResult> CREATOR;
- field public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "ACTION_BUTTON_IMAGE";
- field public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "ACTION_BUTTON_TEXT";
- field public static final String EXTRAINFO_APP_BADGES = "APP_BADGES";
- field public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER = "APP_CONTAINS_ADS_DISCLAIMER";
- field public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER = "APP_CONTAINS_IAP_DISCLAIMER";
- field public static final String EXTRAINFO_APP_DEVELOPER_NAME = "APP_DEVELOPER_NAME";
- field public static final String EXTRAINFO_APP_DOMAIN_URL = "APP_DOMAIN_URL";
- field public static final String EXTRAINFO_APP_IARC = "APP_IARC";
- field public static final String EXTRAINFO_APP_ICON = "APP_ICON";
- field public static final String EXTRAINFO_APP_REVIEW_COUNT = "APP_REVIEW_COUNT";
- field public static final String EXTRAINFO_APP_SIZE_BYTES = "APP_SIZE_BYTES";
- field public static final String EXTRAINFO_APP_STAR_RATING = "APP_STAR_RATING";
- field public static final String EXTRAINFO_LONG_DESCRIPTION = "LONG_DESCRIPTION";
- field public static final String EXTRAINFO_SCREENSHOTS = "SCREENSHOTS";
- field public static final String EXTRAINFO_SHORT_DESCRIPTION = "SHORT_DESCRIPTION";
- field public static final String EXTRAINFO_WEB_ICON = "WEB_ICON";
- field public static final String EXTRAINFO_WEB_URL = "WEB_URL";
+ field public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
+ field public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_TEXT";
+ field public static final String EXTRAINFO_APP_BADGES = "android.app.cloudsearch.APP_BADGES";
+ field public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_ADS_DISCLAIMER";
+ field public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_IAP_DISCLAIMER";
+ field public static final String EXTRAINFO_APP_DEVELOPER_NAME = "android.app.cloudsearch.APP_DEVELOPER_NAME";
+ field public static final String EXTRAINFO_APP_DOMAIN_URL = "android.app.cloudsearch.APP_DOMAIN_URL";
+ field public static final String EXTRAINFO_APP_IARC = "android.app.cloudsearch.APP_IARC";
+ field public static final String EXTRAINFO_APP_ICON = "android.app.cloudsearch.APP_ICON";
+ field public static final String EXTRAINFO_APP_REVIEW_COUNT = "android.app.cloudsearch.APP_REVIEW_COUNT";
+ field public static final String EXTRAINFO_APP_SIZE_BYTES = "android.app.cloudsearch.APP_SIZE_BYTES";
+ field public static final String EXTRAINFO_APP_STAR_RATING = "android.app.cloudsearch.APP_STAR_RATING";
+ field public static final String EXTRAINFO_LONG_DESCRIPTION = "android.app.cloudsearch.LONG_DESCRIPTION";
+ field public static final String EXTRAINFO_SCREENSHOTS = "android.app.cloudsearch.SCREENSHOTS";
+ field public static final String EXTRAINFO_SHORT_DESCRIPTION = "android.app.cloudsearch.SHORT_DESCRIPTION";
+ field public static final String EXTRAINFO_WEB_ICON = "android.app.cloudsearch.WEB_ICON";
+ field public static final String EXTRAINFO_WEB_URL = "android.app.cloudsearch.WEB_URL";
}
public static final class SearchResult.Builder {
@@ -5318,9 +5318,9 @@
method public int getCurrentDataRole();
method public int getCurrentMode();
method public int getCurrentPowerRole();
- method public int getPowerBrickStatus();
+ method public int getPowerBrickConnectionStatus();
method public int getSupportedRoleCombinations();
- method @Nullable public int[] getUsbDataStatus();
+ method public int getUsbDataStatus();
method public boolean isConnected();
method public boolean isPowerTransferLimited();
method public boolean isRoleCombinationSupported(int, int);
@@ -5329,6 +5329,13 @@
field public static final int DATA_ROLE_DEVICE = 2; // 0x2
field public static final int DATA_ROLE_HOST = 1; // 0x1
field public static final int DATA_ROLE_NONE = 0; // 0x0
+ field public static final int DATA_STATUS_DISABLED_CONTAMINANT = 4; // 0x4
+ field public static final int DATA_STATUS_DISABLED_DEBUG = 32; // 0x20
+ field public static final int DATA_STATUS_DISABLED_DOCK = 8; // 0x8
+ field public static final int DATA_STATUS_DISABLED_FORCE = 16; // 0x10
+ field public static final int DATA_STATUS_DISABLED_OVERHEAT = 2; // 0x2
+ field public static final int DATA_STATUS_ENABLED = 1; // 0x1
+ field public static final int DATA_STATUS_UNKNOWN = 0; // 0x0
field public static final int MODE_AUDIO_ACCESSORY = 4; // 0x4
field public static final int MODE_DEBUG_ACCESSORY = 8; // 0x8
field public static final int MODE_DFP = 2; // 0x2
@@ -5340,13 +5347,6 @@
field public static final int POWER_ROLE_NONE = 0; // 0x0
field public static final int POWER_ROLE_SINK = 2; // 0x2
field public static final int POWER_ROLE_SOURCE = 1; // 0x1
- field public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3; // 0x3
- field public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6; // 0x6
- field public static final int USB_DATA_STATUS_DISABLED_DOCK = 4; // 0x4
- field public static final int USB_DATA_STATUS_DISABLED_FORCE = 5; // 0x5
- field public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2; // 0x2
- field public static final int USB_DATA_STATUS_ENABLED = 1; // 0x1
- field public static final int USB_DATA_STATUS_UNKNOWN = 0; // 0x0
}
}
@@ -15621,7 +15621,7 @@
public interface WindowManager extends android.view.ViewManager {
method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
- method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull android.window.TaskFpsCallback);
+ method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback);
method public default void unregisterTaskFpsCallback(@NonNull android.window.TaskFpsCallback);
}
@@ -16213,12 +16213,9 @@
package android.window {
- public final class TaskFpsCallback {
- ctor public TaskFpsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback.OnFpsCallbackListener);
- }
-
- public static interface TaskFpsCallback.OnFpsCallbackListener {
- method public void onFpsReported(float);
+ public abstract class TaskFpsCallback {
+ ctor public TaskFpsCallback();
+ method public abstract void onFpsReported(float);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5c5321c..2f8878e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -107,6 +107,8 @@
method public final boolean addDumpable(@NonNull android.util.Dumpable);
method public void dumpInternal(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
method public void onMovedToDisplay(int, android.content.res.Configuration);
+ field public static final String DUMP_ARG_DUMP_DUMPABLE = "--dump-dumpable";
+ field public static final String DUMP_ARG_LIST_DUMPABLES = "--list-dumpables";
}
public class ActivityManager {
@@ -270,9 +272,12 @@
}
public class DreamManager {
+ method public boolean areDreamsSupported();
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isDreaming();
+ method public boolean isScreensaverEnabled();
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setActiveDream(@Nullable android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setDreamOverlay(@Nullable android.content.ComponentName);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setScreensaverEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream(@NonNull android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
}
@@ -354,6 +359,8 @@
method public float getAspectRatio();
method public float getExpandedAspectRatio();
method public android.graphics.Rect getSourceRectHint();
+ method @Nullable public CharSequence getSubtitle();
+ method @Nullable public CharSequence getTitle();
method public boolean isSeamlessResizeEnabled();
}
@@ -2982,6 +2989,7 @@
field public static final String DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE = "max_buffer_size";
field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled";
field public static final String DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY = "text_change_flush_frequency";
+ field public static final String DUMPABLE_NAME = "ContentCaptureManager";
field public static final int LOGGING_LEVEL_DEBUG = 1; // 0x1
field public static final int LOGGING_LEVEL_OFF = 0; // 0x0
field public static final int LOGGING_LEVEL_VERBOSE = 2; // 0x2
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index eaf79b4..2b2f08f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -814,6 +814,13 @@
Dialog mDialog;
Bundle mArgs;
}
+
+ /** @hide */ public static final String DUMP_ARG_AUTOFILL = "--autofill";
+ /** @hide */ public static final String DUMP_ARG_CONTENT_CAPTURE = "--contentcapture";
+ /** @hide */ public static final String DUMP_ARG_TRANSLATION = "--translation";
+ /** @hide */ @TestApi public static final String DUMP_ARG_LIST_DUMPABLES = "--list-dumpables";
+ /** @hide */ @TestApi public static final String DUMP_ARG_DUMP_DUMPABLE = "--dump-dumpable";
+
private SparseArray<ManagedDialog> mManagedDialogs;
// set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.
@@ -1649,7 +1656,10 @@
}
mRestoredFromBundle = savedInstanceState != null;
mCalled = true;
- if (!WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+
+ boolean aheadOfTimeBack = WindowOnBackInvokedDispatcher
+ .isOnBackInvokedCallbackEnabled(this);
+ if (aheadOfTimeBack) {
// Add onBackPressed as default back behavior.
mDefaultBackCallback = new OnBackInvokedCallback() {
@Override
@@ -7367,25 +7377,30 @@
boolean isSpecialCase = true;
// Handle special cases
switch (arg) {
- case "--autofill":
- dumpAutofillManager(prefix, writer, args);
- break;
- case "--contentcapture":
- dumpContentCaptureManager(prefix, writer);
- break;
- case "--translation":
- dumpUiTranslation(prefix, writer);
- break;
- case "--list-dumpables":
+ case DUMP_ARG_AUTOFILL:
+ dumpLegacyDumpable(prefix, writer, arg,
+ AutofillClientController.DUMPABLE_NAME);
+ return;
+ case DUMP_ARG_CONTENT_CAPTURE:
+ dumpLegacyDumpable(prefix, writer, arg,
+ ContentCaptureManager.DUMPABLE_NAME);
+ return;
+ case DUMP_ARG_TRANSLATION:
+ dumpLegacyDumpable(prefix, writer, arg,
+ UiTranslationController.DUMPABLE_NAME);
+ return;
+ case DUMP_ARG_LIST_DUMPABLES:
if (mDumpableContainer == null) {
writer.print(prefix); writer.println("No dumpables");
} else {
mDumpableContainer.listDumpables(prefix, writer);
}
- break;
- case "--dump-dumpable":
+ mDumpableContainer.listDumpables(prefix, writer);
+ return;
+ case DUMP_ARG_DUMP_DUMPABLE:
if (args.length == 1) {
- writer.println("--dump-dumpable requires the dumpable name");
+ writer.print(DUMP_ARG_DUMP_DUMPABLE);
+ writer.println(" requires the dumpable name");
} else if (mDumpableContainer == null) {
writer.println("no dumpables");
} else {
@@ -7452,25 +7467,10 @@
}
}
- private void dumpContentCaptureManager(String prefix, PrintWriter writer) {
- dumpLegacyDumpable(prefix, writer, ContentCaptureManager.DUMPABLE_NAME, /* args= */ null);
- }
-
- private void dumpUiTranslation(String prefix, PrintWriter writer) {
- dumpLegacyDumpable(prefix, writer, UiTranslationController.DUMPABLE_NAME, /* args= */ null);
- }
-
- private void dumpAutofillManager(String prefix, PrintWriter writer, String[] args) {
- dumpLegacyDumpable(prefix, writer, AutofillClientController.DUMPABLE_NAME, args);
- }
-
- private void dumpLegacyDumpable(@NonNull String prefix, @NonNull PrintWriter writer,
- @NonNull String dumpableName, @Nullable String[] args) {
- if (mDumpableContainer == null) {
- writer.print(prefix); writer.print("no "); writer.println(dumpableName);
- return;
- }
- mDumpableContainer.dumpOneDumpable(prefix, writer, dumpableName, args);
+ private void dumpLegacyDumpable(String prefix, PrintWriter writer, String legacyOption,
+ String dumpableName) {
+ writer.printf("%s%s option deprecated. Use %s %s instead\n", prefix, legacyOption,
+ DUMP_ARG_DUMP_DUMPABLE, dumpableName);
}
/**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d29d3d4..9fe8e79 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -831,4 +831,9 @@
* Restart android.
*/
public abstract void restart();
+
+ /**
+ * Returns some summary statistics of the current PendingIntent queue - sizes and counts.
+ */
+ public abstract List<PendingIntentStats> getPendingIntentStats();
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index aa6c184..569fda9 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -456,7 +456,8 @@
*/
protected void onStart() {
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
- if (mContext != null && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ if (mContext != null
+ && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// Add onBackPressed as default back behavior.
mDefaultBackCallback = new OnBackInvokedCallback() {
@Override
@@ -703,7 +704,7 @@
if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
&& event.isTracking()
&& !event.isCanceled()
- && WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ && !WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
onBackPressed();
return true;
}
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index 34ae08fd..00af1c02 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -26,6 +28,8 @@
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
@@ -48,6 +52,40 @@
}
/**
+ * Returns whether Settings.Secure.SCREENSAVER_ENABLED is enabled.
+ *
+ * @hide
+ */
+ @TestApi
+ public boolean isScreensaverEnabled() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 0, UserHandle.USER_CURRENT) != 0;
+ }
+
+ /**
+ * Sets whether Settings.Secure.SCREENSAVER_ENABLED is enabled.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(WRITE_SECURE_SETTINGS)
+ public void setScreensaverEnabled(boolean enabled) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, enabled ? 1 : 0, UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Returns whether dreams are supported.
+ *
+ * @hide
+ */
+ @TestApi
+ public boolean areDreamsSupported() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsSupported);
+ }
+
+ /**
* Starts dream service with name "name".
*
* <p>This is only used for testing the dream service APIs.
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 55afed2..2242224b 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -73,6 +73,7 @@
* @param nightModeCustomType
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
void setNightModeCustomType(int nightModeCustomType);
/**
@@ -82,6 +83,7 @@
* {@link #MODE_NIGHT_CUSTOM_TYPE_UNKNOWN}.
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
int getNightModeCustomType();
/**
@@ -113,6 +115,7 @@
* {@code nightModeCustomType}.
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
boolean setNightModeActivatedForCustomMode(int nightModeCustom, boolean active);
/**
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/app/PendingIntentStats.java
similarity index 63%
copy from core/java/android/window/IOnFpsCallbackListener.aidl
copy to core/java/android/app/PendingIntentStats.java
index 3091df3..111db3c 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/core/java/android/app/PendingIntentStats.java
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package android.window;
+package android.app;
/**
+ * Data about pending intents - size and count, per UID that sent the intent.
* @hide
*/
-oneway interface IOnFpsCallbackListener {
+public class PendingIntentStats {
+ public final int uid;
+ public final int count;
+ public final int sizeKb;
- /**
- * Reports the fps from the registered task
- * @param fps The frame rate per second of the task that has the registered task id
- * and its children.
- */
- void onFpsReported(in float fps);
+ public PendingIntentStats(int uid, int count, int sizeKb) {
+ this.uid = uid;
+ this.count = count;
+ this.sizeKb = sizeKb;
+ }
}
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 18343fd..0a74bba 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -57,13 +57,16 @@
private Boolean mSeamlessResizeEnabled;
+ private CharSequence mTitle;
+
+ private CharSequence mSubtitle;
+
/**
* Sets the aspect ratio. This aspect ratio is defined as the desired width / height, and
* does not change upon device rotation.
*
* @param aspectRatio the new aspect ratio for the activity in picture-in-picture, must be
- * between 2.39:1 and 1:2.39 (inclusive).
- *
+ * between 2.39:1 and 1:2.39 (inclusive).
* @return this builder instance.
*/
public Builder setAspectRatio(Rational aspectRatio) {
@@ -168,6 +171,36 @@
}
/**
+ * Sets a title for the picture-in-picture window, which may be displayed by the system to
+ * give the user information about what this PIP is generally being used for.
+ *
+ * @param title General information about the PIP content
+ * @return this builder instance.
+ */
+ @NonNull
+ public Builder setTitle(@Nullable CharSequence title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets a subtitle for the picture-in-picture window, which may be displayed by the system
+ * to give the user more detailed information about what this PIP is displaying.<br/>
+ *
+ * Setting a title via {@link PictureInPictureParams.Builder#setTitle(CharSequence)} should
+ * be prioritized.
+ *
+ * @param subtitle Details about the PIP content.
+ * @return this builder instance
+ */
+ @NonNull
+ public Builder setSubtitle(@Nullable CharSequence subtitle) {
+ mSubtitle = subtitle;
+ return this;
+ }
+
+
+ /**
* @return an immutable {@link PictureInPictureParams} to be used when entering or updating
* the activity in picture-in-picture.
*
@@ -177,7 +210,7 @@
public PictureInPictureParams build() {
PictureInPictureParams params = new PictureInPictureParams(mAspectRatio,
mExpandedAspectRatio, mUserActions,
- mSourceRectHint, mAutoEnterEnabled, mSeamlessResizeEnabled);
+ mSourceRectHint, mAutoEnterEnabled, mSeamlessResizeEnabled, mTitle, mSubtitle);
return params;
}
}
@@ -221,6 +254,18 @@
*/
private Boolean mSeamlessResizeEnabled;
+ /**
+ * Title of the picture-in-picture window to be displayed to the user.
+ */
+ @Nullable
+ private CharSequence mTitle;
+
+ /**
+ * Subtitle for the picture-in-picture window to be displayed to the user.
+ */
+ @Nullable
+ private CharSequence mSubtitle;
+
/** {@hide} */
PictureInPictureParams() {
}
@@ -242,18 +287,26 @@
if (in.readInt() != 0) {
mSeamlessResizeEnabled = in.readBoolean();
}
+ if (in.readInt() != 0) {
+ mTitle = in.readCharSequence();
+ }
+ if (in.readInt() != 0) {
+ mSubtitle = in.readCharSequence();
+ }
}
/** {@hide} */
PictureInPictureParams(Rational aspectRatio, Rational expandedAspectRatio,
List<RemoteAction> actions, Rect sourceRectHint, Boolean autoEnterEnabled,
- Boolean seamlessResizeEnabled) {
+ Boolean seamlessResizeEnabled, CharSequence title, CharSequence subtitle) {
mAspectRatio = aspectRatio;
mExpandedAspectRatio = expandedAspectRatio;
mUserActions = actions;
mSourceRectHint = sourceRectHint;
mAutoEnterEnabled = autoEnterEnabled;
mSeamlessResizeEnabled = seamlessResizeEnabled;
+ mTitle = title;
+ mSubtitle = subtitle;
}
/**
@@ -263,7 +316,8 @@
public PictureInPictureParams(PictureInPictureParams other) {
this(other.mAspectRatio, other.mExpandedAspectRatio, other.mUserActions,
other.hasSourceBoundsHint() ? new Rect(other.getSourceRectHint()) : null,
- other.mAutoEnterEnabled, other.mSeamlessResizeEnabled);
+ other.mAutoEnterEnabled, other.mSeamlessResizeEnabled, other.mTitle,
+ other.mSubtitle);
}
/**
@@ -290,6 +344,12 @@
if (otherArgs.mSeamlessResizeEnabled != null) {
mSeamlessResizeEnabled = otherArgs.mSeamlessResizeEnabled;
}
+ if (otherArgs.hasSetTitle()) {
+ mTitle = otherArgs.mTitle;
+ }
+ if (otherArgs.hasSetSubtitle()) {
+ mSubtitle = otherArgs.mSubtitle;
+ }
}
/**
@@ -399,13 +459,50 @@
}
/**
+ * @return whether a title was set.
+ * @hide
+ */
+ public boolean hasSetTitle() {
+ return mTitle != null;
+ }
+
+ /**
+ * @return title of the pip.
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * @return whether a subtitle was set.
+ * @hide
+ */
+ public boolean hasSetSubtitle() {
+ return mSubtitle != null;
+ }
+
+ /**
+ * @return subtitle of the pip.
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public CharSequence getSubtitle() {
+ return mSubtitle;
+ }
+
+ /**
* @return True if no parameters are set
* @hide
*/
public boolean empty() {
return !hasSourceBoundsHint() && !hasSetActions() && !hasSetAspectRatio()
&& !hasSetExpandedAspectRatio() && mAutoEnterEnabled != null
- && mSeamlessResizeEnabled != null;
+ && mSeamlessResizeEnabled != null && !hasSetTitle()
+ && !hasSetSubtitle();
}
@Override
@@ -418,13 +515,15 @@
&& Objects.equals(mAspectRatio, that.mAspectRatio)
&& Objects.equals(mExpandedAspectRatio, that.mExpandedAspectRatio)
&& Objects.equals(mUserActions, that.mUserActions)
- && Objects.equals(mSourceRectHint, that.mSourceRectHint);
+ && Objects.equals(mSourceRectHint, that.mSourceRectHint)
+ && Objects.equals(mTitle, that.mTitle)
+ && Objects.equals(mSubtitle, that.mSubtitle);
}
@Override
public int hashCode() {
return Objects.hash(mAspectRatio, mExpandedAspectRatio, mUserActions, mSourceRectHint,
- mAutoEnterEnabled, mSeamlessResizeEnabled);
+ mAutoEnterEnabled, mSeamlessResizeEnabled, mTitle, mSubtitle);
}
@Override
@@ -460,6 +559,18 @@
} else {
out.writeInt(0);
}
+ if (mTitle != null) {
+ out.writeInt(1);
+ out.writeCharSequence(mTitle);
+ } else {
+ out.writeInt(0);
+ }
+ if (mSubtitle != null) {
+ out.writeInt(1);
+ out.writeCharSequence(mSubtitle);
+ } else {
+ out.writeInt(0);
+ }
}
private void writeRationalToParcel(Rational rational, Parcel out) {
@@ -488,6 +599,8 @@
+ " hasSetActions=" + hasSetActions()
+ " isAutoPipEnabled=" + isAutoEnterEnabled()
+ " isSeamlessResizeEnabled=" + isSeamlessResizeEnabled()
+ + " title=" + getTitle()
+ + " subtitle=" + getSubtitle()
+ ")";
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index cfaffb1..ecab37d 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -244,7 +244,18 @@
public static final int MODE_NIGHT_YES = 2;
/**
- * Granular types for {@link MODE_NIGHT_CUSTOM_TYPE_BEDTIME}
+ * Granular types for {@link #setNightModeCustomType(int)}
+ * @hide
+ */
+ @IntDef(prefix = { "MODE_NIGHT_CUSTOM_TYPE_" }, value = {
+ MODE_NIGHT_CUSTOM_TYPE_SCHEDULE,
+ MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NightModeCustomType {}
+
+ /**
+ * Granular types for {@link #getNightModeCustomType()}
* @hide
*/
@IntDef(prefix = { "MODE_NIGHT_CUSTOM_TYPE_" }, value = {
@@ -253,7 +264,7 @@
MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface NightModeCustomType {}
+ public @interface NightModeCustomReturnType {}
/**
* A granular type for {@link #MODE_NIGHT_CUSTOM} which is unknown.
@@ -539,6 +550,8 @@
* {@code nightModeCustomType}.
*
* @param nightModeCustomType
+ * @throws IllegalArgumentException if passed an unsupported type to
+ * {@code nightModeCustomType}.
* @hide
*/
@SystemApi
@@ -562,7 +575,7 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
- public int getNightModeCustomType() {
+ public @NightModeCustomReturnType int getNightModeCustomType() {
if (mService != null) {
try {
return mService.getNightModeCustomType();
diff --git a/core/java/android/app/cloudsearch/SearchRequest.java b/core/java/android/app/cloudsearch/SearchRequest.java
index ef66c0c..4d6507a 100644
--- a/core/java/android/app/cloudsearch/SearchRequest.java
+++ b/core/java/android/app/cloudsearch/SearchRequest.java
@@ -83,11 +83,13 @@
* presubmit is the input before the user finishes the entire query, i.e. push "ENTER" or
* "SEARCH" button. After the user finishes the entire query, the behavior is postsubmit.
*/
- public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "IS_PRESUBMIT_SUGGESTION";
+ public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION =
+ "android.app.cloudsearch.IS_PRESUBMIT_SUGGESTION";
/** The target search provider list of package names(separated by ;), String value expected.
* If this is not provided or its value is empty, then no filter will be applied.
*/
- public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "SEARCH_PROVIDER_FILTER";
+ public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER =
+ "android.app.cloudsearch.SEARCH_PROVIDER_FILTER";
@NonNull
private Bundle mSearchConstraints;
diff --git a/core/java/android/app/cloudsearch/SearchResult.java b/core/java/android/app/cloudsearch/SearchResult.java
index 3403ab0..af8adac 100644
--- a/core/java/android/app/cloudsearch/SearchResult.java
+++ b/core/java/android/app/cloudsearch/SearchResult.java
@@ -75,47 +75,54 @@
EXTRAINFO_WEB_ICON})
public @interface SearchResultExtraInfoKey {}
/** This App developer website's domain URL, String value expected. */
- public static final String EXTRAINFO_APP_DOMAIN_URL = "APP_DOMAIN_URL";
+ public static final String EXTRAINFO_APP_DOMAIN_URL = "android.app.cloudsearch.APP_DOMAIN_URL";
/** This App icon, android.graphics.drawable.Icon expected. */
- public static final String EXTRAINFO_APP_ICON = "APP_ICON";
+ public static final String EXTRAINFO_APP_ICON = "android.app.cloudsearch.APP_ICON";
/** This App developer's name, String value expected. */
- public static final String EXTRAINFO_APP_DEVELOPER_NAME = "APP_DEVELOPER_NAME";
+ public static final String EXTRAINFO_APP_DEVELOPER_NAME =
+ "android.app.cloudsearch.APP_DEVELOPER_NAME";
/** This App's pkg size in bytes, Double value expected. */
- public static final String EXTRAINFO_APP_SIZE_BYTES = "APP_SIZE_BYTES";
+ public static final String EXTRAINFO_APP_SIZE_BYTES = "android.app.cloudsearch.APP_SIZE_BYTES";
/** This App developer's name, Double value expected. */
- public static final String EXTRAINFO_APP_STAR_RATING = "APP_STAR_RATING";
+ public static final String EXTRAINFO_APP_STAR_RATING =
+ "android.app.cloudsearch.APP_STAR_RATING";
/** This App's IARC rating, String value expected.
* IARC (International Age Rating Coalition) is partnered globally with major
* content rating organizations to provide a centralized and one-stop-shop for
* rating content on a global scale.
*/
- public static final String EXTRAINFO_APP_IARC = "APP_IARC";
+ public static final String EXTRAINFO_APP_IARC = "android.app.cloudsearch.APP_IARC";
/** This App's review count, Double value expected. */
- public static final String EXTRAINFO_APP_REVIEW_COUNT = "APP_REVIEW_COUNT";
+ public static final String EXTRAINFO_APP_REVIEW_COUNT =
+ "android.app.cloudsearch.APP_REVIEW_COUNT";
/** If this App contains the Ads Disclaimer, Boolean value expected. */
public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER =
- "APP_CONTAINS_ADS_DISCLAIMER";
+ "android.app.cloudsearch.APP_CONTAINS_ADS_DISCLAIMER";
/** If this App contains the IAP Disclaimer, Boolean value expected. */
public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER =
- "APP_CONTAINS_IAP_DISCLAIMER";
+ "android.app.cloudsearch.APP_CONTAINS_IAP_DISCLAIMER";
/** This App's short description, String value expected. */
- public static final String EXTRAINFO_SHORT_DESCRIPTION = "SHORT_DESCRIPTION";
+ public static final String EXTRAINFO_SHORT_DESCRIPTION =
+ "android.app.cloudsearch.SHORT_DESCRIPTION";
/** This App's long description, String value expected. */
- public static final String EXTRAINFO_LONG_DESCRIPTION = "LONG_DESCRIPTION";
- /** This App's screenshots, List<ImageLoadingBundle> value expected. */
- public static final String EXTRAINFO_SCREENSHOTS = "SCREENSHOTS";
- /** Editor's choices for this App, ArrayList<String> value expected. */
- public static final String EXTRAINFO_APP_BADGES = "APP_BADGES";
+ public static final String EXTRAINFO_LONG_DESCRIPTION =
+ "android.app.cloudsearch.LONG_DESCRIPTION";
+ /** This App's screenshots, {@code List<ImageLoadingBundle>} value expected. */
+ public static final String EXTRAINFO_SCREENSHOTS = "android.app.cloudsearch.SCREENSHOTS";
+ /** Editor's choices for this App, {@code ArrayList<String>} value expected. */
+ public static final String EXTRAINFO_APP_BADGES = "android.app.cloudsearch.APP_BADGES";
/** Pre-registration game's action button text, String value expected. */
@SuppressLint("IntentName")
- public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "ACTION_BUTTON_TEXT";
+ public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING =
+ "android.app.cloudsearch.ACTION_BUTTON_TEXT";
/** Pre-registration game's action button image, ImageLoadingBundle value expected. */
@SuppressLint("IntentName")
- public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "ACTION_BUTTON_IMAGE";
+ public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING =
+ "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
/** Web content's URL, String value expected. */
- public static final String EXTRAINFO_WEB_URL = "WEB_URL";
+ public static final String EXTRAINFO_WEB_URL = "android.app.cloudsearch.WEB_URL";
/** Web content's domain icon, android.graphics.drawable.Icon expected. */
- public static final String EXTRAINFO_WEB_ICON = "WEB_ICON";
+ public static final String EXTRAINFO_WEB_ICON = "android.app.cloudsearch.WEB_ICON";
@NonNull
private Bundle mExtraInfos;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0fed733..8f82a0a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3525,7 +3525,7 @@
public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
/**
- * Connect to an application service, creating it if needed. This defines
+ * Connects to an application service, creating it if needed. This defines
* a dependency between your application and the service. The given
* <var>conn</var> will receive the service object when it is created and be
* told if it dies and restarts. The service will be considered required
@@ -3540,11 +3540,8 @@
* will be invoked instead of
* {@link ServiceConnection#onServiceConnected(ComponentName, IBinder) onServiceConnected()}.
*
- * <p>This method will throw {@link SecurityException} if the calling app does not
- * have permission to bind to the given service.
- *
- * <p class="note">Note: this method <em>cannot be called from a
- * {@link BroadcastReceiver} component</em>. A pattern you can use to
+ * <p class="note"><b>Note:</b> This method <em>cannot</em> be called from a
+ * {@link BroadcastReceiver} component. A pattern you can use to
* communicate from a BroadcastReceiver to a Service is to call
* {@link #startService} with the arguments containing the command to be
* sent, with the service calling its
@@ -3559,33 +3556,34 @@
* specify an explicit component name.
* @param conn Receives information as the service is started and stopped.
* This must be a valid ServiceConnection object; it must not be null.
- * @param flags Operation options for the binding. May be 0,
- * {@link #BIND_AUTO_CREATE}, {@link #BIND_DEBUG_UNBIND},
- * {@link #BIND_NOT_FOREGROUND}, {@link #BIND_ABOVE_CLIENT},
- * {@link #BIND_ALLOW_OOM_MANAGEMENT}, {@link #BIND_WAIVE_PRIORITY}.
- * {@link #BIND_IMPORTANT}, {@link #BIND_ADJUST_WITH_ACTIVITY},
- * {@link #BIND_NOT_PERCEPTIBLE}, or {@link #BIND_INCLUDE_CAPABILITIES}.
- * @return {@code true} if the system is in the process of bringing up a
+ * @param flags Operation options for the binding. Can be:
+ * <ul>
+ * <li>0
+ * <li>{@link #BIND_AUTO_CREATE}
+ * <li>{@link #BIND_DEBUG_UNBIND}
+ * <li>{@link #BIND_NOT_FOREGROUND}
+ * <li>{@link #BIND_ABOVE_CLIENT}
+ * <li>{@link #BIND_ALLOW_OOM_MANAGEMENT}
+ * <li>{@link #BIND_WAIVE_PRIORITY}
+ * <li>{@link #BIND_IMPORTANT}
+ * <li>{@link #BIND_ADJUST_WITH_ACTIVITY}
+ * <li>{@link #BIND_NOT_PERCEPTIBLE}
+ * <li>{@link #BIND_INCLUDE_CAPABILITIES}
+ * </ul>
+ *
+ * @return {@code true} if the system is in the process of bringing up a
* service that your client has permission to bind to; {@code false}
* if the system couldn't find the service or if your client doesn't
* have permission to bind to it. You should call {@link #unbindService}
* to release the connection even if this method returned {@code false}.
*
- * @throws SecurityException If the caller does not have permission to access the service
- * or the service can not be found.
+ * @throws SecurityException If the caller does not have permission to
+ * access the service or the service cannot be found. Call
+ * {@link #unbindService} to release the connection when this exception
+ * is thrown.
*
* @see #unbindService
* @see #startService
- * @see #BIND_AUTO_CREATE
- * @see #BIND_DEBUG_UNBIND
- * @see #BIND_NOT_FOREGROUND
- * @see #BIND_ABOVE_CLIENT
- * @see #BIND_ALLOW_OOM_MANAGEMENT
- * @see #BIND_WAIVE_PRIORITY
- * @see #BIND_IMPORTANT
- * @see #BIND_ADJUST_WITH_ACTIVITY
- * @see #BIND_NOT_PERCEPTIBLE
- * @see #BIND_INCLUDE_CAPABILITIES
*/
public abstract boolean bindService(@RequiresPermission Intent service,
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e5cffb1..0aa25ef 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -9209,6 +9209,16 @@
}
/**
+ * Returns the total size of the extras in bytes, or 0 if no extras are present.
+ * @hide
+ */
+ public int getExtrasTotalSize() {
+ return (mExtras != null)
+ ? mExtras.getSize()
+ : 0;
+ }
+
+ /**
* @return Whether {@link #maybeStripForHistory} will return an lightened intent or
* return itself as-is.
* @hide
diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java
index 21398f6..660a7f0 100644
--- a/core/java/android/content/ServiceConnection.java
+++ b/core/java/android/content/ServiceConnection.java
@@ -63,8 +63,12 @@
* happen, for example, if the application hosting the service it is bound to
* has been updated.
*
- * @param name The concrete component name of the service whose
- * connection is dead.
+ * <p class="note"><b>Note:</b> The app that requested the binding must call
+ * {@link Context#unbindService(ServiceConnection)} to release the tracking
+ * resources associated with this ServiceConnection even if this callback was
+ * invoked following {@link Context#bindService Context.bindService() bindService()}.
+ *
+ * @param name The concrete component name of the service whose connection is dead.
*/
default void onBindingDied(ComponentName name) {
}
@@ -72,10 +76,10 @@
/**
* Called when the service being bound has returned {@code null} from its
* {@link android.app.Service#onBind(Intent) onBind()} method. This indicates
- * that the attempting service binding represented by this ServiceConnection
+ * that the attempted service binding represented by this ServiceConnection
* will never become usable.
*
- * <p class="note">The app which requested the binding must still call
+ * <p class="note"><b>Note:</b> The app that requested the binding must still call
* {@link Context#unbindService(ServiceConnection)} to release the tracking
* resources associated with this ServiceConnection even if this callback was
* invoked following {@link Context#bindService Context.bindService() bindService()}.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2528e16..be58ba7 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -39,6 +39,7 @@
import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.view.OnBackInvokedCallback;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Parcelling;
@@ -801,11 +802,24 @@
*/
public static final int PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE = 1 << 2;
+
+ /**
+ * If false, {@link android.view.KeyEvent#KEYCODE_BACK} related events will be forwarded to
+ * the Activities, Dialogs and Views and {@link android.app.Activity#onBackPressed()},
+ * {@link android.app.Dialog#onBackPressed} will be called. Otherwise, those events will be
+ * replaced by a call to {@link OnBackInvokedCallback#onBackInvoked()} on the focused window.
+ *
+ * @hide
+ * @see android.R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
+ */
+ public static final int PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK = 1 << 3;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
PRIVATE_FLAG_EXT_PROFILEABLE,
PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION,
PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE,
+ PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlagsExt {}
@@ -1683,6 +1697,7 @@
pw.println(prefix + "localeConfigRes=0x"
+ Integer.toHexString(localeConfigRes));
}
+ pw.println(prefix + "enableOnBackInvokedCallback=" + isOnBackInvokedCallbackEnabled());
}
pw.println(prefix + "createTimestamp=" + createTimestamp);
if (mKnownActivityEmbeddingCerts != null) {
@@ -2566,6 +2581,17 @@
}
/**
+ * Returns whether the application will use the {@link android.view.OnBackInvokedCallback}
+ * navigation system instead of the {@link android.view.KeyEvent#KEYCODE_BACK} and related
+ * callbacks.
+ *
+ * @hide
+ */
+ public boolean isOnBackInvokedCallbackEnabled() {
+ return ((privateFlagsExt & PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)) != 0;
+ }
+
+ /**
* @hide
*/
@Override protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index dc79ee6..a162c41 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8035,6 +8035,7 @@
return PackageParser.generatePackageInfo(pkg, null, (int) flagsBits, 0, 0, null,
FrameworkPackageUserState.DEFAULT);
} catch (PackageParser.PackageParserException e) {
+ Log.w(TAG, "Failure to parse package archive", e);
return null;
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 98cc8f6..e914432 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -59,6 +59,7 @@
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
@@ -2417,9 +2418,28 @@
Slog.i(TAG, newPermsMsg.toString());
}
- final List<PermissionManager.SplitPermissionInfo> splitPermissions =
- ActivityThread.currentApplication().getSystemService(PermissionManager.class)
- .getSplitPermissions();
+ // Must build permission info manually for legacy code, which can be called before
+ // Appication is available through the app process, so the normal API doesn't work.
+ List<SplitPermissionInfoParcelable> splitPermissionParcelables;
+ try {
+ splitPermissionParcelables = ActivityThread.getPermissionManager()
+ .getSplitPermissions();
+ } catch (RemoteException e) {
+ splitPermissionParcelables = Collections.emptyList();
+ }
+
+ int splitPermissionsSize = splitPermissionParcelables.size();
+ List<PermissionManager.SplitPermissionInfo> splitPermissions =
+ new ArrayList<>(splitPermissionsSize);
+ for (int index = 0; index < splitPermissionsSize; index++) {
+ SplitPermissionInfoParcelable splitPermissionParcelable =
+ splitPermissionParcelables.get(index);
+ splitPermissions.add(new PermissionManager.SplitPermissionInfo(
+ splitPermissionParcelable.getSplitPermission(),
+ splitPermissionParcelable.getNewPermissions(),
+ splitPermissionParcelable.getTargetSdk()
+ ));
+ }
final int listSize = splitPermissions.size();
for (int is = 0; is < listSize; is++) {
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index ecd240d..24ae31e 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -199,6 +199,7 @@
certs.add(certsList);
}
}
+ typedArray.recycle();
}
return new ProviderResourceEntry(
authority,
diff --git a/core/java/android/hardware/ISensorPrivacyListener.aidl b/core/java/android/hardware/ISensorPrivacyListener.aidl
index 5d40265..2ac21d2 100644
--- a/core/java/android/hardware/ISensorPrivacyListener.aidl
+++ b/core/java/android/hardware/ISensorPrivacyListener.aidl
@@ -24,6 +24,6 @@
// the ones in
// frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
// =============== Beginning of transactions used on native side as well ======================
- void onSensorPrivacyChanged(boolean enabled);
+ void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
// =============== End of transactions used on native side as well ============================
}
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index 5571165..a392afd 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -24,34 +24,31 @@
// the ones in
// frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
// =============== Beginning of transactions used on native side as well ======================
- boolean supportsSensorToggle(int sensor);
+ boolean supportsSensorToggle(int toggleType, int sensor);
void addSensorPrivacyListener(in ISensorPrivacyListener listener);
- void addIndividualSensorPrivacyListener(int userId, int sensor,
- in ISensorPrivacyListener listener);
+ void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
- void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+ void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
boolean isSensorPrivacyEnabled();
- boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
+ boolean isCombinedToggleSensorPrivacyEnabled(int sensor);
+
+ boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor);
void setSensorPrivacy(boolean enable);
- void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);
- void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
// =============== End of transactions used on native side as well ============================
- void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token,
+ void suppressToggleSensorPrivacyReminders(int userId, int sensor, IBinder token,
boolean suppress);
- void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
-
- void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
-
void showSensorUseDialog(int sensor);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 47659a9..dec424c 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -639,7 +639,7 @@
/**
* Unregisters a listener for the sensors with which it is registered.
*
- * <p class="note"></p>
+ * <p class="note">
* Note: Don't use this method with a one shot trigger sensor such as
* {@link Sensor#TYPE_SIGNIFICANT_MOTION}.
* Use {@link #cancelTriggerSensor(TriggerEventListener, Sensor)} instead.
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index 79153d7..4399af9 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -36,7 +36,6 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
-import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -73,8 +72,6 @@
public static final String EXTRA_ALL_SENSORS = SensorPrivacyManager.class.getName()
+ ".extra.all_sensors";
- private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>();
-
/**
* Sensor constants which are used in {@link SensorPrivacyManager}
*/
@@ -241,8 +238,55 @@
void onSensorPrivacyChanged(int sensor, boolean enabled);
}
+ /**
+ * A class implementing this interface can register with the {@link
+ * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy
+ * state changes.
+ *
+ * @hide
+ */
+ public interface OnToggleSensorPrivacyChangedListener {
+
+ /**
+ * A class containing information about what the sensor privacy state has changed to.
+ */
+ class SensorPrivacyChangedParams {
+
+ private int mToggleType;
+ private int mSensor;
+ private boolean mEnabled;
+
+ private SensorPrivacyChangedParams(int toggleType, int sensor, boolean enabled) {
+ mToggleType = toggleType;
+ mSensor = sensor;
+ mEnabled = enabled;
+ }
+
+ public @ToggleTypes.ToggleType int getToggleType() {
+ return mToggleType;
+ }
+
+ public @Sensors.Sensor int getSensor() {
+ return mSensor;
+ }
+
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+ }
+
+ /**
+ * Callback invoked when the sensor privacy state changes.
+ *
+ * @param params Parameters describing the new state
+ */
+ void onSensorPrivacyChanged(@NonNull SensorPrivacyChangedParams params);
+ }
+
private static final Object sInstanceLock = new Object();
+ private final Object mLock = new Object();
+
@GuardedBy("sInstanceLock")
private static SensorPrivacyManager sInstance;
@@ -252,12 +296,46 @@
@NonNull
private final ISensorPrivacyManager mService;
+ @GuardedBy("mLock")
+ private final ArrayMap<Pair<Integer, Integer>, Boolean> mToggleSupportCache = new ArrayMap<>();
+
@NonNull
private final ArrayMap<OnAllSensorPrivacyChangedListener, ISensorPrivacyListener> mListeners;
+ /** Registered listeners */
+ @GuardedBy("mLock")
@NonNull
- private final ArrayMap<Pair<OnSensorPrivacyChangedListener, Integer>, ISensorPrivacyListener>
- mIndividualListeners;
+ private final ArrayMap<OnToggleSensorPrivacyChangedListener, Executor> mToggleListeners =
+ new ArrayMap<>();
+
+ /** Listeners registered using the deprecated APIs and which
+ * OnToggleSensorPrivacyChangedListener they're using. */
+ @GuardedBy("mLock")
+ @NonNull
+ private final ArrayMap<Pair<Integer, OnSensorPrivacyChangedListener>,
+ OnToggleSensorPrivacyChangedListener> mLegacyToggleListeners = new ArrayMap<>();
+
+ /** The singleton ISensorPrivacyListener for IPC which will be used to dispatch to local
+ * listeners */
+ @NonNull
+ private final ISensorPrivacyListener mIToggleListener = new ISensorPrivacyListener.Stub() {
+ @Override
+ public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) {
+ synchronized (mLock) {
+ for (int i = 0; i < mToggleListeners.size(); i++) {
+ OnToggleSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i);
+ mToggleListeners.valueAt(i).execute(() -> listener
+ .onSensorPrivacyChanged(new OnToggleSensorPrivacyChangedListener
+ .SensorPrivacyChangedParams(toggleType, sensor, enabled)));
+ }
+ }
+ }
+ };
+
+ /** Whether the singleton ISensorPrivacyListener has been registered */
+ @GuardedBy("mLock")
+ @NonNull
+ private boolean mToggleListenerRegistered = false;
/**
* Private constructor to ensure only a single instance is created.
@@ -266,7 +344,6 @@
mContext = context;
mService = service;
mListeners = new ArrayMap<>();
- mIndividualListeners = new ArrayMap<>();
}
/**
@@ -295,25 +372,43 @@
* @return whether the toggle for the sensor is supported on this device.
*/
public boolean supportsSensorToggle(@Sensors.Sensor int sensor) {
+ return supportsSensorToggle(ToggleTypes.SOFTWARE, sensor);
+ }
+
+ /**
+ * Checks if the given toggle is supported on this device
+ * @param sensor The sensor to check
+ * @return whether the toggle for the sensor is supported on this device.
+ *
+ * @hide
+ */
+ public boolean supportsSensorToggle(@ToggleTypes.ToggleType int toggleType,
+ @Sensors.Sensor int sensor) {
try {
- Boolean val = mToggleSupportCache.get(sensor);
- if (val == null) {
- val = mService.supportsSensorToggle(sensor);
- mToggleSupportCache.put(sensor, val);
+ Pair key = new Pair(toggleType, sensor);
+ synchronized (mLock) {
+ Boolean val = mToggleSupportCache.get(key);
+ if (val == null) {
+ val = mService.supportsSensorToggle(toggleType, sensor);
+ mToggleSupportCache.put(key, val);
+ }
+ return val;
}
- return val;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
* @param sensor the sensor to listen to changes to
* @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
- * privacy changes.
+ * privacy changes.
+ *
+ * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
*
* @hide
*/
@@ -325,6 +420,7 @@
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
@@ -333,22 +429,27 @@
* @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
* privacy changes.
*
+ * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
+ *
* @hide
*/
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
- public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
+ public void addSensorPrivacyListener(@Sensors.Sensor int sensor, int userId,
@NonNull OnSensorPrivacyChangedListener listener) {
- addSensorPrivacyListener(sensor, userId, mContext.getMainExecutor(), listener);
+ addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
* @param sensor the sensor to listen to changes to
* @param executor the executor to dispatch the callback on
* @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
- * privacy changes.
+ * privacy changes.
+ *
+ * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
*
* @hide
*/
@@ -356,61 +457,69 @@
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
@NonNull OnSensorPrivacyChangedListener listener) {
- Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor);
- synchronized (mIndividualListeners) {
- ISensorPrivacyListener iListener = mIndividualListeners.get(key);
- if (iListener == null) {
- iListener = new ISensorPrivacyListener.Stub() {
- @Override
- public void onSensorPrivacyChanged(boolean enabled) {
- executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
- }
- };
- mIndividualListeners.put(key, iListener);
- }
- try {
- mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
+ OnToggleSensorPrivacyChangedListener toggleListener = params -> {
+ if (params.getSensor() == sensor) {
+ listener.onSensorPrivacyChanged(params.getSensor(), params.isEnabled());
}
+ };
+
+ synchronized (mLock) {
+ mLegacyToggleListeners.put(pair, toggleListener);
+ addSensorPrivacyListenerLocked(executor, toggleListener);
}
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
- * @param sensor the sensor to listen to changes to
- * @param executor the executor to dispatch the callback on
- * @param userId the user's id
- * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
- * privacy changes.
+ * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of
+ * sensor privacy changes.
*
* @hide
*/
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
- public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
- @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) {
- synchronized (mIndividualListeners) {
- ISensorPrivacyListener iListener = mIndividualListeners.get(listener);
- if (iListener == null) {
- iListener = new ISensorPrivacyListener.Stub() {
- @Override
- public void onSensorPrivacyChanged(boolean enabled) {
- executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
- }
- };
- mIndividualListeners.put(new Pair<>(listener, sensor), iListener);
- }
+ public void addSensorPrivacyListener(@NonNull OnToggleSensorPrivacyChangedListener listener) {
+ addSensorPrivacyListener(mContext.getMainExecutor(), listener);
+ }
+ /**
+ *
+ * Registers a new listener to receive notification when the state of sensor privacy
+ * changes.
+ *
+ * @param executor the executor to dispatch the callback on
+ * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of
+ * sensor privacy changes.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@NonNull Executor executor,
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ addSensorPrivacyListenerLocked(executor, listener);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void addSensorPrivacyListenerLocked(@NonNull Executor executor,
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ if (!mToggleListenerRegistered) {
try {
- mService.addIndividualSensorPrivacyListener(userId, sensor,
- iListener);
+ mService.addToggleSensorPrivacyListener(mIToggleListener);
+ mToggleListenerRegistered = true;
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ e.rethrowFromSystemServer();
}
}
+ if (mToggleListeners.containsKey(listener)) {
+ throw new IllegalArgumentException("listener is already registered");
+ }
+ mToggleListeners.put(listener, executor);
}
/**
@@ -420,30 +529,60 @@
* @param listener the OnSensorPrivacyChangedListener to be unregistered from notifications when
* sensor privacy changes.
*
+ * {@link #removeSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} with
+ * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} or
+ * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
+ *
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void removeSensorPrivacyListener(@Sensors.Sensor int sensor,
@NonNull OnSensorPrivacyChangedListener listener) {
- synchronized (mListeners) {
- for (int i = 0; i < mIndividualListeners.size(); i++) {
- Pair<OnSensorPrivacyChangedListener, Integer> pair = mIndividualListeners.keyAt(i);
- if (pair.second == sensor && pair.first.equals(listener)) {
- try {
- mService.removeIndividualSensorPrivacyListener(sensor,
- mIndividualListeners.valueAt(i));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- mIndividualListeners.removeAt(i--);
- }
+ Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
+ synchronized (mLock) {
+ OnToggleSensorPrivacyChangedListener onToggleSensorPrivacyChangedListener =
+ mLegacyToggleListeners.remove(pair);
+ if (onToggleSensorPrivacyChangedListener != null) {
+ removeSensorPrivacyListenerLocked(onToggleSensorPrivacyChangedListener);
}
}
}
/**
- * Returns whether sensor privacy is currently enabled for a specific sensor.
+ * Unregisters the specified listener from receiving notifications when the state of any sensor
+ * privacy changes.
+ *
+ * @param listener the {@link OnToggleSensorPrivacyChangedListener} to be unregistered from
+ * notifications when sensor privacy changes.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void removeSensorPrivacyListener(
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ removeSensorPrivacyListenerLocked(listener);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void removeSensorPrivacyListenerLocked(
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ mToggleListeners.remove(listener);
+ if (mToggleListeners.size() == 0) {
+ try {
+ mService.removeToggleSensorPrivacyListener(mIToggleListener);
+ mToggleListenerRegistered = false;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns whether sensor privacy is currently enabled by software control for a specific
+ * sensor.
*
* @return true if sensor privacy is currently enabled, false otherwise.
*
@@ -452,7 +591,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
- return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT);
+ return isSensorPrivacyEnabled(ToggleTypes.SOFTWARE, sensor);
}
/**
@@ -463,9 +602,27 @@
* @hide
*/
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
- public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor, @UserIdInt int userId) {
+ public boolean isSensorPrivacyEnabled(@ToggleTypes.ToggleType int toggleType,
+ @Sensors.Sensor int sensor) {
try {
- return mService.isIndividualSensorPrivacyEnabled(userId, sensor);
+ return mService.isToggleSensorPrivacyEnabled(toggleType, sensor);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether sensor privacy is currently enabled for a specific sensor.
+ * Combines the state of the SW + HW toggles and returns the actual privacy state.
+ *
+ * @return true if sensor privacy is currently enabled, false otherwise.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public boolean isToggleSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
+ try {
+ return mService.isCombinedToggleSensorPrivacyEnabled(sensor);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -524,7 +681,7 @@
public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
boolean enable, @UserIdInt int userId) {
try {
- mService.setIndividualSensorPrivacy(userId, source, sensor, enable);
+ mService.setToggleSensorPrivacy(userId, source, sensor, enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -561,7 +718,7 @@
public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
@Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) {
try {
- mService.setIndividualSensorPrivacyForProfileGroup(userId, source, sensor, enable);
+ mService.setToggleSensorPrivacyForProfileGroup(userId, source, sensor, enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -592,7 +749,7 @@
public void suppressSensorPrivacyReminders(int sensor,
boolean suppress, @UserIdInt int userId) {
try {
- mService.suppressIndividualSensorPrivacyReminders(userId, sensor,
+ mService.suppressToggleSensorPrivacyReminders(userId, sensor,
token, suppress);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -667,7 +824,8 @@
if (iListener == null) {
iListener = new ISensorPrivacyListener.Stub() {
@Override
- public void onSensorPrivacyChanged(boolean enabled) {
+ public void onSensorPrivacyChanged(int toggleType, int sensor,
+ boolean enabled) {
listener.onAllSensorPrivacyChanged(enabled);
}
};
diff --git a/core/java/android/hardware/SensorPrivacyManagerInternal.java b/core/java/android/hardware/SensorPrivacyManagerInternal.java
index d12e9f8..f4de966 100644
--- a/core/java/android/hardware/SensorPrivacyManagerInternal.java
+++ b/core/java/android/hardware/SensorPrivacyManagerInternal.java
@@ -61,4 +61,9 @@
*/
public abstract void addSensorPrivacyListenerForAllUsers(int sensor,
OnUserSensorPrivacyChangedListener listener);
+
+ /**
+ * Set the HW toggle sensor value based on HW switch states, called from InputManagerService
+ */
+ public abstract void setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable);
}
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java
index 693cda7..99791ce 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -214,6 +214,16 @@
return CONTENTS_FILE_DESCRIPTOR;
}
+ /** @hide */
+ public Object getLock() {
+ return mCloser;
+ }
+
+ /** @hide */
+ public long getNativeFence() {
+ return mNativePtr;
+ }
+
/**
* Flatten this object into a Parcel.
*
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index a979725..7b695e7 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -39,13 +39,13 @@
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_ENABLED;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_OVERHEAT;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_CONTAMINANT;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DOCK;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_FORCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DEBUG;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_ENABLED;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
import android.Manifest;
import android.annotation.CheckResult;
@@ -400,7 +400,7 @@
}
/**
- * Enables Usb data when disabled due to {@link UsbPort#USB_DATA_STATUS_DISABLED_DOCK}
+ * Enables Usb data when disabled due to {@link UsbPort#DATA_STATUS_DISABLED_DOCK}
*
* @return {@link #ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS} when request completes successfully or
* {@link #ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL} when request fails due to
@@ -421,7 +421,8 @@
+ " callingUid:" + Binder.getCallingUid());
UsbPortStatus portStatus = getStatus();
if (portStatus != null &&
- !usbDataStatusToString(portStatus.getUsbDataStatus()).contains("disabled-dock")) {
+ (portStatus.getUsbDataStatus() & DATA_STATUS_DISABLED_DOCK) !=
+ DATA_STATUS_DISABLED_DOCK) {
return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED;
}
@@ -584,44 +585,43 @@
/** @hide */
public static String usbDataStatusToString(int usbDataStatus) {
- switch (usbDataStatus) {
- case USB_DATA_STATUS_UNKNOWN:
- return "unknown";
- case USB_DATA_STATUS_ENABLED:
- return "enabled";
- case USB_DATA_STATUS_DISABLED_OVERHEAT:
- return "disabled-overheat";
- case USB_DATA_STATUS_DISABLED_CONTAMINANT:
- return "disabled-contaminant";
- case USB_DATA_STATUS_DISABLED_DOCK:
- return "disabled-dock";
- case USB_DATA_STATUS_DISABLED_FORCE:
- return "disabled-force";
- case USB_DATA_STATUS_DISABLED_DEBUG:
- return "disabled-debug";
- default:
- return Integer.toString(usbDataStatus);
- }
- }
+ StringBuilder statusString = new StringBuilder();
- /** @hide */
- public static String usbDataStatusToString(int[] usbDataStatus) {
- StringBuilder modeString = new StringBuilder();
- if (usbDataStatus == null) {
+ if (usbDataStatus == DATA_STATUS_UNKNOWN) {
return "unknown";
}
- for (int i = 0; i < usbDataStatus.length; i++) {
- modeString.append(usbDataStatusToString(usbDataStatus[i]));
- if (i < usbDataStatus.length - 1) {
- modeString.append(", ");
- }
+
+ if ((usbDataStatus & DATA_STATUS_ENABLED) == DATA_STATUS_ENABLED) {
+ return "enabled";
}
- return modeString.toString();
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_OVERHEAT) == DATA_STATUS_DISABLED_OVERHEAT) {
+ statusString.append("disabled-overheat, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_CONTAMINANT)
+ == DATA_STATUS_DISABLED_CONTAMINANT) {
+ statusString.append("disabled-contaminant, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK) == DATA_STATUS_DISABLED_DOCK) {
+ statusString.append("disabled-dock, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_FORCE) == DATA_STATUS_DISABLED_FORCE) {
+ statusString.append("disabled-force, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_DEBUG) == DATA_STATUS_DISABLED_DEBUG) {
+ statusString.append("disabled-debug, ");
+ }
+
+ return statusString.toString().replaceAll(", $", "");
}
/** @hide */
- public static String powerBrickStatusToString(int powerBrickStatus) {
- switch (powerBrickStatus) {
+ public static String powerBrickConnectionStatusToString(int powerBrickConnectionStatus) {
+ switch (powerBrickConnectionStatus) {
case POWER_BRICK_STATUS_UNKNOWN:
return "unknown";
case POWER_BRICK_STATUS_CONNECTED:
@@ -629,7 +629,7 @@
case POWER_BRICK_STATUS_DISCONNECTED:
return "disconnected";
default:
- return Integer.toString(powerBrickStatus);
+ return Integer.toString(powerBrickConnectionStatus);
}
}
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index d1f4246..3221ec8 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -44,8 +44,8 @@
private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
private final boolean mPowerTransferLimited;
- private final @UsbDataStatus int[] mUsbDataStatus;
- private final @PowerBrickStatus int mPowerBrickStatus;
+ private final @UsbDataStatus int mUsbDataStatus;
+ private final @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
/**
* Power role: This USB port does not have a power role.
@@ -198,38 +198,38 @@
/**
* USB data status is not known.
*/
- public static final int USB_DATA_STATUS_UNKNOWN = 0;
+ public static final int DATA_STATUS_UNKNOWN = 0;
/**
* USB data is enabled.
*/
- public static final int USB_DATA_STATUS_ENABLED = 1;
+ public static final int DATA_STATUS_ENABLED = 1 << 0;
/**
* USB data is disabled as the port is too hot.
*/
- public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2;
+ public static final int DATA_STATUS_DISABLED_OVERHEAT = 1 << 1;
/**
* USB data is disabled due to contaminated port.
*/
- public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3;
+ public static final int DATA_STATUS_DISABLED_CONTAMINANT = 1 << 2;
/**
* USB data is disabled due to docking event.
*/
- public static final int USB_DATA_STATUS_DISABLED_DOCK = 4;
+ public static final int DATA_STATUS_DISABLED_DOCK = 1 << 3;
/**
* USB data is disabled by
* {@link UsbPort#enableUsbData UsbPort.enableUsbData}.
*/
- public static final int USB_DATA_STATUS_DISABLED_FORCE = 5;
+ public static final int DATA_STATUS_DISABLED_FORCE = 1 << 4;
/**
* USB data is disabled for debug.
*/
- public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6;
+ public static final int DATA_STATUS_DISABLED_DEBUG = 1 << 5;
/**
* Unknown whether a power brick is connected.
@@ -276,14 +276,14 @@
@interface UsbPortMode{}
/** @hide */
- @IntDef(prefix = { "USB_DATA_STATUS_" }, value = {
- USB_DATA_STATUS_UNKNOWN,
- USB_DATA_STATUS_ENABLED,
- USB_DATA_STATUS_DISABLED_OVERHEAT,
- USB_DATA_STATUS_DISABLED_CONTAMINANT,
- USB_DATA_STATUS_DISABLED_DOCK,
- USB_DATA_STATUS_DISABLED_FORCE,
- USB_DATA_STATUS_DISABLED_DEBUG
+ @IntDef(prefix = { "DATA_STATUS_" }, flag = true, value = {
+ DATA_STATUS_UNKNOWN,
+ DATA_STATUS_ENABLED,
+ DATA_STATUS_DISABLED_OVERHEAT,
+ DATA_STATUS_DISABLED_CONTAMINANT,
+ DATA_STATUS_DISABLED_DOCK,
+ DATA_STATUS_DISABLED_FORCE,
+ DATA_STATUS_DISABLED_DEBUG
})
@Retention(RetentionPolicy.SOURCE)
@interface UsbDataStatus{}
@@ -295,13 +295,14 @@
POWER_BRICK_STATUS_CONNECTED,
})
@Retention(RetentionPolicy.SOURCE)
- @interface PowerBrickStatus{}
+ @interface PowerBrickConnectionStatus{}
/** @hide */
public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus,
- int contaminantDetectionStatus, @UsbDataStatus int[] usbDataStatus,
- boolean powerTransferLimited, @PowerBrickStatus int powerBrickStatus) {
+ int contaminantDetectionStatus, @UsbDataStatus int usbDataStatus,
+ boolean powerTransferLimited,
+ @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
mCurrentMode = currentMode;
mCurrentPowerRole = currentPowerRole;
mCurrentDataRole = currentDataRole;
@@ -310,7 +311,7 @@
mContaminantDetectionStatus = contaminantDetectionStatus;
mUsbDataStatus = usbDataStatus;
mPowerTransferLimited = powerTransferLimited;
- mPowerBrickStatus = powerBrickStatus;
+ mPowerBrickConnectionStatus = powerBrickConnectionStatus;
}
/** @hide */
@@ -323,8 +324,8 @@
mSupportedRoleCombinations = supportedRoleCombinations;
mContaminantProtectionStatus = contaminantProtectionStatus;
mContaminantDetectionStatus = contaminantDetectionStatus;
- mUsbDataStatus = new int[]{USB_DATA_STATUS_UNKNOWN};
- mPowerBrickStatus = POWER_BRICK_STATUS_UNKNOWN;
+ mUsbDataStatus = DATA_STATUS_UNKNOWN;
+ mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
mPowerTransferLimited = false;
}
@@ -411,13 +412,13 @@
/**
* Returns UsbData status.
*
- * @return Current USB data status of the port: {@link #USB_DATA_STATUS_UNKNOWN}
- * or {@link #USB_DATA_STATUS_ENABLED} or {@link #USB_DATA_STATUS_DIASBLED_OVERHEAT}
- * or {@link #USB_DATA_STATUS_DISABLED_CONTAMINANT}
- * or {@link #USB_DATA_STATUS_DISABLED_DOCK} or {@link #USB_DATA_STATUS_DISABLED_FORCE}
- * or {@link #USB_DATA_STATUS_DISABLED_DEBUG}
+ * @return Current USB data status of the port with one or more of the following values
+ * {@link #DATA_STATUS_UNKNOWN}, {@link #DATA_STATUS_ENABLED},
+ * {@link #DATA_STATUS_DISABLED_OVERHEAT}, {@link #DATA_STATUS_DISABLED_CONTAMINANT},
+ * {@link #DATA_STATUS_DISABLED_DOCK}, {@link #DATA_STATUS_DISABLED_FORCE},
+ * {@link #DATA_STATUS_DISABLED_DEBUG}
*/
- public @UsbDataStatus @Nullable int[] getUsbDataStatus() {
+ public @UsbDataStatus int getUsbDataStatus() {
return mUsbDataStatus;
}
@@ -432,14 +433,14 @@
}
/**
- * Let's the caller know if a power brick is connected to the USB port.
+ * Returns the connection status of the power brick.
*
* @return {@link #POWER_BRICK_STATUS_UNKNOWN}
* or {@link #POWER_BRICK_STATUS_CONNECTED}
* or {@link #POWER_BRICK_STATUS_DISCONNECTED}
*/
- public @PowerBrickStatus int getPowerBrickStatus() {
- return mPowerBrickStatus;
+ public @PowerBrickConnectionStatus int getPowerBrickConnectionStatus() {
+ return mPowerBrickConnectionStatus;
}
@NonNull
@@ -459,8 +460,9 @@
+ UsbPort.usbDataStatusToString(getUsbDataStatus())
+ ", isPowerTransferLimited="
+ isPowerTransferLimited()
- +", powerBrickStatus="
- + UsbPort.powerBrickStatusToString(getPowerBrickStatus())
+ +", powerBrickConnectionStatus="
+ + UsbPort
+ .powerBrickConnectionStatusToString(getPowerBrickConnectionStatus())
+ "}";
}
@@ -477,10 +479,9 @@
dest.writeInt(mSupportedRoleCombinations);
dest.writeInt(mContaminantProtectionStatus);
dest.writeInt(mContaminantDetectionStatus);
- dest.writeInt(mUsbDataStatus.length);
- dest.writeIntArray(mUsbDataStatus);
+ dest.writeInt(mUsbDataStatus);
dest.writeBoolean(mPowerTransferLimited);
- dest.writeInt(mPowerBrickStatus);
+ dest.writeInt(mPowerBrickConnectionStatus);
}
public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -493,14 +494,13 @@
int supportedRoleCombinations = in.readInt();
int contaminantProtectionStatus = in.readInt();
int contaminantDetectionStatus = in.readInt();
- int[] usbDataStatus = new int[in.readInt()];
- in.readIntArray(usbDataStatus);
+ int usbDataStatus = in.readInt();
boolean powerTransferLimited = in.readBoolean();
- int powerBrickStatus = in.readInt();
+ int powerBrickConnectionStatus = in.readInt();
return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus, powerTransferLimited,
- powerBrickStatus);
+ powerBrickConnectionStatus);
}
@Override
@@ -508,4 +508,126 @@
return new UsbPortStatus[size];
}
};
+
+ /**
+ * Builder is used to create {@link UsbPortStatus} objects.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private @UsbPortMode int mCurrentMode;
+ private @UsbPowerRole int mCurrentPowerRole;
+ private @UsbDataRole int mCurrentDataRole;
+ private int mSupportedRoleCombinations;
+ private @ContaminantProtectionStatus int mContaminantProtectionStatus;
+ private @ContaminantDetectionStatus int mContaminantDetectionStatus;
+ private boolean mPowerTransferLimited;
+ private @UsbDataStatus int mUsbDataStatus;
+ private @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
+
+ public Builder() {
+ mCurrentMode = MODE_NONE;
+ mCurrentPowerRole = POWER_ROLE_NONE;
+ mCurrentDataRole = DATA_ROLE_NONE;
+ mContaminantProtectionStatus = CONTAMINANT_PROTECTION_NONE;
+ mContaminantDetectionStatus = CONTAMINANT_DETECTION_NOT_SUPPORTED;
+ mUsbDataStatus = DATA_STATUS_UNKNOWN;
+ mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
+ }
+
+ /**
+ * Sets the current mode of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setCurrentMode(@UsbPortMode int currentMode) {
+ mCurrentMode = currentMode;
+ return this;
+ }
+
+ /**
+ * Sets the current power role and data role of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setCurrentRoles(@UsbPowerRole int currentPowerRole,
+ @UsbDataRole int currentDataRole) {
+ mCurrentPowerRole = currentPowerRole;
+ mCurrentDataRole = currentDataRole;
+ return this;
+ }
+
+ /**
+ * Sets supported role combinations of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setSupportedRoleCombinations(int supportedRoleCombinations) {
+ mSupportedRoleCombinations = supportedRoleCombinations;
+ return this;
+ }
+
+ /**
+ * Sets current contaminant status of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setContaminantStatus(
+ @ContaminantProtectionStatus int contaminantProtectionStatus,
+ @ContaminantDetectionStatus int contaminantDetectionStatus) {
+ mContaminantProtectionStatus = contaminantProtectionStatus;
+ mContaminantDetectionStatus = contaminantDetectionStatus;
+ return this;
+ }
+
+ /**
+ * Sets power limit power transfer of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setPowerTransferLimited(boolean powerTransferLimited) {
+ mPowerTransferLimited = powerTransferLimited;
+ return this;
+ }
+
+ /**
+ * Sets the USB data status of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setUsbDataStatus(@UsbDataStatus int usbDataStatus) {
+ mUsbDataStatus = usbDataStatus;
+ return this;
+ }
+
+ /**
+ * Sets the power brick connection status of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setPowerBrickConnectionStatus(
+ @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
+ mPowerBrickConnectionStatus = powerBrickConnectionStatus;
+ return this;
+ }
+
+ /**
+ * Creates the {@link UsbPortStatus} object.
+ */
+ @NonNull
+ public UsbPortStatus build() {
+ UsbPortStatus status = new UsbPortStatus(mCurrentMode, mCurrentPowerRole,
+ mCurrentDataRole, mSupportedRoleCombinations, mContaminantProtectionStatus,
+ mContaminantDetectionStatus, mUsbDataStatus, mPowerTransferLimited,
+ mPowerBrickConnectionStatus);
+ return status;
+ }
+ };
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index adf2759..c3e3180 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -346,7 +346,7 @@
*/
@AnyThread
public static boolean canImeRenderGesturalNavButtons() {
- return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true);
+ return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
}
/**
@@ -989,24 +989,6 @@
public void changeInputMethodSubtype(InputMethodSubtype subtype) {
dispatchOnCurrentInputMethodSubtypeChanged(subtype);
}
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @Override
- public void setCurrentShowInputToken(IBinder showInputToken) {
- mCurShowInputToken = showInputToken;
- }
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @Override
- public void setCurrentHideInputToken(IBinder hideInputToken) {
- mCurHideInputToken = hideInputToken;
- }
}
/**
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 6f4fd76..19fa01d 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -45,7 +45,6 @@
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsController.Appearance;
-import android.view.WindowManagerPolicyConstants;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
@@ -138,7 +137,7 @@
private boolean mDestroyed = false;
- private boolean mRenderGesturalNavButtons;
+ private boolean mImeDrawsImeNavBar;
@Nullable
private NavigationBarFrame mNavigationBarFrame;
@@ -185,7 +184,7 @@
}
private void installNavigationBarFrameIfNecessary() {
- if (!mRenderGesturalNavButtons) {
+ if (!mImeDrawsImeNavBar) {
return;
}
if (mNavigationBarFrame != null) {
@@ -253,7 +252,7 @@
@Override
public void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
@NonNull ViewTreeObserver.InternalInsetsInfo dest) {
- if (!mRenderGesturalNavButtons || mNavigationBarFrame == null
+ if (!mImeDrawsImeNavBar || mNavigationBarFrame == null
|| mService.isExtractViewShown()) {
return;
}
@@ -360,13 +359,12 @@
});
}
- private boolean isGesturalNavigationEnabled() {
+ private boolean imeDrawsImeNavBar() {
final Resources resources = mService.getResources();
if (resources == null) {
return false;
}
- return resources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode)
- == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+ return resources.getBoolean(com.android.internal.R.bool.config_imeDrawsImeNavBar);
}
@Override
@@ -381,7 +379,7 @@
if (mDestroyed) {
return;
}
- mRenderGesturalNavButtons = isGesturalNavigationEnabled();
+ mImeDrawsImeNavBar = imeDrawsImeNavBar();
if (mSystemOverlayChangedReceiver == null) {
final IntentFilter intentFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
intentFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
@@ -392,8 +390,8 @@
if (mDestroyed) {
return;
}
- mRenderGesturalNavButtons = isGesturalNavigationEnabled();
- if (mRenderGesturalNavButtons) {
+ mImeDrawsImeNavBar = imeDrawsImeNavBar();
+ if (mImeDrawsImeNavBar) {
installNavigationBarFrameIfNecessary();
} else {
uninstallNavigationBarFrameIfNecessary();
@@ -423,7 +421,7 @@
@Override
public void onWindowShown() {
- if (mDestroyed || !mRenderGesturalNavButtons || mNavigationBarFrame == null) {
+ if (mDestroyed || !mImeDrawsImeNavBar || mNavigationBarFrame == null) {
return;
}
final Insets systemInsets = getSystemInsets();
@@ -546,7 +544,7 @@
@Override
public String toDebugString() {
- return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons
+ return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar
+ " mNavigationBarFrame=" + mNavigationBarFrame
+ " mShouldShowImeSwitcherWhenImeIsShown="
+ mShouldShowImeSwitcherWhenImeIsShown
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index b9252d6..7379443 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -104,6 +104,8 @@
public final class SystemClock {
private static final String TAG = "SystemClock";
+ private static volatile IAlarmManager sIAlarmManager;
+
/**
* This class is uninstantiable.
*/
@@ -151,8 +153,7 @@
* @return if the clock was successfully set to the specified time.
*/
public static boolean setCurrentTimeMillis(long millis) {
- final IAlarmManager mgr = IAlarmManager.Stub
- .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ final IAlarmManager mgr = getIAlarmManager();
if (mgr == null) {
Slog.e(TAG, "Unable to set RTC: mgr == null");
return false;
@@ -280,8 +281,7 @@
* @hide
*/
public static long currentNetworkTimeMillis() {
- final IAlarmManager mgr = IAlarmManager.Stub
- .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ final IAlarmManager mgr = getIAlarmManager();
if (mgr != null) {
try {
return mgr.currentNetworkTimeMillis();
@@ -296,6 +296,14 @@
}
}
+ private static IAlarmManager getIAlarmManager() {
+ if (sIAlarmManager == null) {
+ sIAlarmManager = IAlarmManager.Stub
+ .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ }
+ return sIAlarmManager;
+ }
+
/**
* Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC,
* synchronized using a remote network source outside the device.
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index d223a19..642c618 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -27,7 +27,7 @@
import java.util.Objects;
/**
- * A class to encapsulate a collection of attributes describing information about a vibration
+ * Encapsulates a collection of attributes describing information about a vibration.
*/
public final class VibrationAttributes implements Parcelable {
private static final String TAG = "VibrationAttributes";
@@ -174,7 +174,7 @@
FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
/** Creates a new {@link VibrationAttributes} instance with given usage. */
- public static @NonNull VibrationAttributes createForUsage(int usage) {
+ public static @NonNull VibrationAttributes createForUsage(@Usage int usage) {
return new VibrationAttributes.Builder().setUsage(usage).build();
}
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 21c6487..237f6ed 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -48,7 +48,7 @@
/**
* A VibrationEffect describes a haptic effect to be performed by a {@link Vibrator}.
*
- * These effects may be any number of things, from single shot vibrations to complex waveforms.
+ * <p>These effects may be any number of things, from single shot vibrations to complex waveforms.
*/
public abstract class VibrationEffect implements Parcelable {
// Stevens' coefficient to scale the perceived vibration intensity.
@@ -110,7 +110,7 @@
/**
* A texture effect meant to replicate soft ticks.
*
- * Unlike normal effects, texture effects are meant to be called repeatedly, generally in
+ * <p>Unlike normal effects, texture effects are meant to be called repeatedly, generally in
* response to some motion, in order to replicate the feeling of some texture underneath the
* user's fingers.
*
@@ -175,7 +175,7 @@
/**
* Create a one shot vibration.
*
- * One shot vibrations will vibrate constantly for the specified period of time at the
+ * <p>One shot vibrations will vibrate constantly for the specified period of time at the
* specified amplitude, and then stop.
*
* @param milliseconds The number of milliseconds to vibrate. This must be a positive number.
@@ -269,13 +269,13 @@
/**
* Create a predefined vibration effect.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
- * This will fallback to a generic pattern if one exists and there does not exist a
+ * <p>This will fallback to a generic pattern if one exists and there does not exist a
* hardware-specific implementation of the effect.
*
* @param effectId The ID of the effect to perform:
@@ -291,13 +291,13 @@
/**
* Get a predefined vibration effect.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
- * This will fallback to a generic pattern if one exists and there does not exist a
+ * <p>This will fallback to a generic pattern if one exists and there does not exist a
* hardware-specific implementation of the effect.
*
* @param effectId The ID of the effect to perform:
@@ -314,16 +314,16 @@
/**
* Get a predefined vibration effect.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
- * Some effects you may only want to play if there's a hardware specific implementation because
- * they may, for example, be too disruptive to the user without tuning. The {@code fallback}
- * parameter allows you to decide whether you want to fallback to the generic implementation or
- * only play if there's a tuned, hardware specific one available.
+ * <p>Some effects you may only want to play if there's a hardware specific implementation
+ * because they may, for example, be too disruptive to the user without tuning. The
+ * {@code fallback} parameter allows you to decide whether you want to fallback to the generic
+ * implementation or only play if there's a tuned, hardware specific one available.
*
* @param effectId The ID of the effect to perform:
* {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK}
@@ -344,9 +344,9 @@
/**
* Get a predefined vibration effect associated with a given URI.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
@@ -474,7 +474,7 @@
/**
* Gets the estimated duration of the vibration in milliseconds.
*
- * For effects without a defined end (e.g. a Waveform with a non-negative repeat index), this
+ * <p>For effects without a defined end (e.g. a Waveform with a non-negative repeat index), this
* returns Long.MAX_VALUE. For effects with an unknown duration (e.g. Prebaked effects where
* the length is device and potentially run-time dependent), this returns -1.
*
@@ -817,28 +817,26 @@
* effect that grows in intensity and then dies off, with a longer rising portion for emphasis
* and an extra tick 100ms after:
*
- * <code>
- * VibrationEffect effect = VibrationEffect.startComposition()
+ * <pre>
+ * {@code VibrationEffect effect = VibrationEffect.startComposition()
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE, 0.5f)
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL, 0.5f)
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1.0f, 100)
- * .compose();
- * </code>
+ * .compose();}</pre>
*
* <p>Composition elements can also be {@link VibrationEffect} instances, including other
* compositions, and off durations, which are periods of time when the vibrator will be
* turned off. Here is an example of a composition that "warms up" with a light tap,
* a stronger double tap, then repeats a vibration pattern indefinitely:
*
- * <code>
- * VibrationEffect repeatingEffect = VibrationEffect.startComposition()
+ * <pre>
+ * {@code VibrationEffect repeatingEffect = VibrationEffect.startComposition()
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK)
* .addOffDuration(Duration.ofMillis(10))
* .addEffect(VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK))
* .addOffDuration(Duration.ofMillis(50))
* .addEffect(VibrationEffect.createWaveform(pattern, repeatIndex))
- * .compose();
- * </code>
+ * .compose();}</pre>
*
* <p>When choosing to play a composed effect, you should check that individual components are
* supported by the device by using the appropriate vibrator method:
@@ -932,7 +930,7 @@
/**
* Adds a time duration to the current composition, during which the vibrator will be
- * turned off
+ * turned off.
*
* @param duration The length of time the vibrator should be off. Value must be non-negative
* and will be truncated to milliseconds.
@@ -1004,7 +1002,7 @@
/**
* Add a haptic primitive to the end of the current composition.
*
- * Similar to {@link #addPrimitive(int, float, int)}, but with no delay and a
+ * <p>Similar to {@link #addPrimitive(int, float, int)}, but with no delay and a
* default scale applied.
*
* @param primitiveId The primitive to add
@@ -1021,7 +1019,7 @@
/**
* Add a haptic primitive to the end of the current composition.
*
- * Similar to {@link #addPrimitive(int, float, int)}, but with no delay.
+ * <p>Similar to {@link #addPrimitive(int, float, int)}, but with no delay.
*
* @param primitiveId The primitive to add
* @param scale The scale to apply to the intensity of the primitive.
@@ -1081,9 +1079,9 @@
/**
* Compose all of the added primitives together into a single {@link VibrationEffect}.
*
- * The {@link Composition} object is still valid after this call, so you can continue adding
- * more primitives to it and generating more {@link VibrationEffect}s by calling this method
- * again.
+ * <p>The {@link Composition} object is still valid after this call, so you can continue
+ * adding more primitives to it and generating more {@link VibrationEffect}s by calling this
+ * method again.
*
* @return The {@link VibrationEffect} resulting from the composition of the primitives.
*/
@@ -1099,7 +1097,7 @@
}
/**
- * Convert the primitive ID to a human readable string for debugging
+ * Convert the primitive ID to a human readable string for debugging.
* @param id The ID to convert
* @return The ID in a human readable format.
* @hide
@@ -1139,16 +1137,15 @@
* <p>The following example ramps a vibrator turned off to full amplitude at 120Hz, over 100ms
* starting at 60Hz, then holds that state for 200ms and ramps back down again over 100ms:
*
- * <code>
- * import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
+ * <pre>
+ * {@code import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
* import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
*
* VibrationEffect effect = VibrationEffect.startWaveform(targetFrequency(60))
* .addTransition(Duration.ofMillis(100), targetAmplitude(1), targetFrequency(120))
* .addSustain(Duration.ofMillis(200))
* .addTransition(Duration.ofMillis(100), targetAmplitude(0), targetFrequency(60))
- * .build();
- * </code>
+ * .build();}</pre>
*
* <p>The initial state of the waveform can be set via
* {@link VibrationEffect#startWaveform(VibrationParameter)} or
@@ -1169,8 +1166,8 @@
* a {@link VibrationEffect.Composition}. The resulting effect will have a tick followed by a
* repeated beating effect with a rise that stretches out and a sharp finish.
*
- * <code>
- * VibrationEffect patternToBeRepeated = VibrationEffect.startWaveform(targetAmplitude(0.2f))
+ * <pre>
+ * {@code VibrationEffect patternToRepeat = VibrationEffect.startWaveform(targetAmplitude(0.2f))
* .addSustain(Duration.ofMillis(10))
* .addTransition(Duration.ofMillis(20), targetAmplitude(0.4f))
* .addSustain(Duration.ofMillis(30))
@@ -1182,16 +1179,15 @@
* VibrationEffect effect = VibrationEffect.startComposition()
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
* .addOffDuration(Duration.ofMillis(20))
- * .repeatEffectIndefinitely(patternToBeRepeated)
- * .compose();
- * </code>
+ * .repeatEffectIndefinitely(patternToRepeat)
+ * .compose();}</pre>
*
* <p>The amplitude step waveforms that can be created via
* {@link VibrationEffect#createWaveform(long[], int[], int)} can also be created with
* {@link WaveformBuilder} by adding zero duration transitions:
*
- * <code>
- * // These two effects are the same
+ * <pre>
+ * {@code // These two effects are the same
* VibrationEffect waveform = VibrationEffect.createWaveform(
* new long[] { 10, 20, 30 }, // timings in milliseconds
* new int[] { 51, 102, 204 }, // amplitudes in [0,255]
@@ -1203,8 +1199,7 @@
* .addSustain(Duration.ofMillis(20))
* .addTransition(Duration.ZERO, targetAmplitude(0.8f))
* .addSustain(Duration.ofMillis(30))
- * .build();
- * </code>
+ * .build();}</pre>
*
* @see VibrationEffect#startWaveform
*/
@@ -1307,7 +1302,7 @@
/**
* Build the waveform as a single {@link VibrationEffect}.
*
- * The {@link WaveformBuilder} object is still valid after this call, so you can
+ * <p>The {@link WaveformBuilder} object is still valid after this call, so you can
* continue adding more primitives to it and generating more {@link VibrationEffect}s by
* calling this method again.
*
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 78f1cb1..7f0d634 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -83,7 +83,7 @@
/**
* Vibration effect support: unknown
*
- * The hardware doesn't report it's supported effects, so we can't determine whether the
+ * <p>The hardware doesn't report its supported effects, so we can't determine whether the
* effect is supported or not.
*/
public static final int VIBRATION_EFFECT_SUPPORT_UNKNOWN = 0;
@@ -91,14 +91,14 @@
/**
* Vibration effect support: supported
*
- * This effect is supported by the underlying hardware.
+ * <p>This effect is supported by the underlying hardware.
*/
public static final int VIBRATION_EFFECT_SUPPORT_YES = 1;
/**
* Vibration effect support: unsupported
*
- * This effect is <b>not</b> natively supported by the underlying hardware, although
+ * <p>This effect is <b>not</b> natively supported by the underlying hardware, although
* the system may still play a fallback vibration.
*/
public static final int VIBRATION_EFFECT_SUPPORT_NO = 2;
@@ -317,7 +317,7 @@
/**
* Vibrate constantly for the specified period of time.
*
- * <p>The app should be in foreground for the vibration to happen.</p>
+ * <p>The app should be in the foreground for the vibration to happen.</p>
*
* @param milliseconds The number of milliseconds to vibrate.
* @deprecated Use {@link #vibrate(VibrationEffect)} instead.
@@ -331,7 +331,7 @@
/**
* Vibrate constantly for the specified period of time.
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param milliseconds The number of milliseconds to vibrate.
@@ -368,7 +368,7 @@
* to start the repeat, or -1 to disable repeating.
* </p>
*
- * <p>The app should be in foreground for the vibration to happen.</p>
+ * <p>The app should be in the foreground for the vibration to happen.</p>
*
* @param pattern an array of longs of times for which to turn the vibrator on or off.
* @param repeat the index into pattern at which to repeat, or -1 if
@@ -395,7 +395,7 @@
* to start the repeat, or -1 to disable repeating.
* </p>
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param pattern an array of longs of times for which to turn the vibrator on or off.
@@ -428,7 +428,7 @@
/**
* Vibrate with a given effect.
*
- * <p>The app should be in foreground for the vibration to happen.</p>
+ * <p>The app should be in the foreground for the vibration to happen.</p>
*
* @param vibe {@link VibrationEffect} describing the vibration to be performed.
*/
@@ -440,7 +440,7 @@
/**
* Vibrate with a given effect.
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param vibe {@link VibrationEffect} describing the vibration to be performed.
@@ -461,7 +461,7 @@
/**
* Vibrate with a given effect.
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param vibe {@link VibrationEffect} describing the vibration to be performed.
@@ -477,7 +477,7 @@
/**
* Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the
- * caller to specify the vibration is owned by someone else and set reason for vibration.
+ * caller to specify the vibration is owned by someone else and set a reason for vibration.
*
* @hide
*/
@@ -519,7 +519,7 @@
}
/**
- * Query whether the vibrator supports all of the given effects.
+ * Query whether the vibrator supports all the given effects.
*
* <p>If an effect is not supported, the system may still automatically fall back to a simpler
* vibration instead, which is not optimised for the specific device, however vibration isn't
@@ -533,7 +533,7 @@
* vibration.
*
* <p>If the result is {@link #VIBRATION_EFFECT_SUPPORT_UNKNOWN}, the system doesn't know
- * whether all of the effects are supported. It may support any or all of the queried effects,
+ * whether all the effects are supported. It may support any or all of the queried effects,
* but there's no way to programmatically know whether a {@link #vibrate} call will successfully
* cause a vibration. It's guaranteed, however, that none of the queried effects are
* definitively unsupported by the hardware.
@@ -541,7 +541,7 @@
* <p>Use {@link #areEffectsSupported(int...)} to get individual results for each effect.
*
* @param effectIds Which effects to query for.
- * @return Whether all of the effects are natively supported by the device.
+ * @return Whether all the effects are natively supported by the device.
*/
@VibrationEffectSupport
public final int areAllEffectsSupported(
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 00ce14f..71ec096 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -35,7 +35,8 @@
/**
* A VibratorInfo describes the capabilities of a {@link Vibrator}.
*
- * This description includes its capabilities, list of supported effects and composition primitives.
+ * <p>This description includes its capabilities, list of supported effects and composition
+ * primitives.
*
* @hide
*/
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index c82a516..f506ef8 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -25,7 +25,7 @@
import android.util.Log;
/**
- * Class that provides access to all vibrators from the device, as well as the ability to run them
+ * Provides access to all vibrators from the device, as well as the ability to run them
* in a synchronized fashion.
* <p>
* If your process exits, any vibration you started will stop.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4e1337f..cc98339 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1538,6 +1538,8 @@
* be reserved for cached data depending on the device state which is then passed on
* to getStorageCacheBytes.
*
+ * Input File path must point to a storage volume.
+ *
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
diff --git a/core/java/android/os/vibrator/VibratorFrequencyProfile.java b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
index 23b45ae..0f2aa15 100644
--- a/core/java/android/os/vibrator/VibratorFrequencyProfile.java
+++ b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
@@ -61,8 +61,7 @@
* <p>The returned list will not be empty, and will have entries representing frequencies from
* {@link #getMinFrequency()} to {@link #getMaxFrequency()}, inclusive.
*
- * @return Array of maximum relative amplitude measurements, each value is between 0 and 1,
- * inclusive.
+ * @return Array of maximum relative amplitude measurements.
*/
@NonNull
@FloatRange(from = 0, to = 1)
diff --git a/core/java/android/service/resumeonreboot/OWNERS b/core/java/android/service/resumeonreboot/OWNERS
index 3a127d5..721fbaf 100644
--- a/core/java/android/service/resumeonreboot/OWNERS
+++ b/core/java/android/service/resumeonreboot/OWNERS
@@ -1,2 +1 @@
-xunchang@google.com
-zhaojiac@google.com
+ejyzhang@google.com
\ No newline at end of file
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index e075c05..832db91 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -17,6 +17,7 @@
package android.speech;
import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -38,7 +39,6 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import com.android.internal.R;
@@ -49,6 +49,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Queue;
+import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
/**
@@ -206,10 +207,9 @@
handleSetTemporaryComponent((ComponentName) msg.obj);
break;
case MSG_CHECK_RECOGNITION_SUPPORT:
- Pair<Intent, RecognitionSupportCallback> intentAndListener =
- (Pair<Intent, RecognitionSupportCallback>) msg.obj;
+ CheckRecognitionSupportArgs args = (CheckRecognitionSupportArgs) msg.obj;
handleCheckRecognitionSupport(
- intentAndListener.first, intentAndListener.second);
+ args.mIntent, args.mCallbackExecutor, args.mCallback);
break;
case MSG_TRIGGER_MODEL_DOWNLOAD:
handleTriggerModelDownload((Intent) msg.obj);
@@ -492,6 +492,7 @@
*/
public void checkRecognitionSupport(
@NonNull Intent recognizerIntent,
+ @NonNull @CallbackExecutor Executor executor,
@NonNull RecognitionSupportCallback supportListener) {
Objects.requireNonNull(recognizerIntent, "intent must not be null");
Objects.requireNonNull(supportListener, "listener must not be null");
@@ -508,13 +509,13 @@
connectToSystemService();
}
putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
- Pair.create(recognizerIntent, supportListener)));
+ new CheckRecognitionSupportArgs(recognizerIntent, executor, supportListener)));
}
/**
* Attempts to download the support for the given {@code recognizerIntent}. This might trigger
* user interaction to approve the download. Callers can verify the status of the request via
- * {@link #checkRecognitionSupport(Intent, RecognitionSupportCallback)}.
+ * {@link #checkRecognitionSupport(Intent, Executor, RecognitionSupportCallback)}.
*
* @param recognizerIntent contains parameters for the recognition to be performed. The intent
* may also contain optional extras, see {@link RecognizerIntent}.
@@ -625,18 +626,20 @@
}
private void handleCheckRecognitionSupport(
- Intent recognizerIntent, RecognitionSupportCallback recognitionSupportCallback) {
+ Intent recognizerIntent,
+ Executor callbackExecutor,
+ RecognitionSupportCallback recognitionSupportCallback) {
if (!maybeInitializeManagerService()) {
return;
}
try {
mService.checkRecognitionSupport(
recognizerIntent,
- new InternalSupportCallback(recognitionSupportCallback));
+ new InternalSupportCallback(callbackExecutor, recognitionSupportCallback));
if (DBG) Log.d(TAG, "service support command succeeded");
} catch (final RemoteException e) {
Log.e(TAG, "checkRecognitionSupport() failed", e);
- mListener.onError(ERROR_CLIENT);
+ callbackExecutor.execute(() -> recognitionSupportCallback.onError(ERROR_CLIENT));
}
}
@@ -780,6 +783,21 @@
return ComponentName.unflattenFromString(serviceComponent);
}
+ private static class CheckRecognitionSupportArgs {
+ final Intent mIntent;
+ final Executor mCallbackExecutor;
+ final RecognitionSupportCallback mCallback;
+
+ private CheckRecognitionSupportArgs(
+ Intent intent,
+ Executor callbackExecutor,
+ RecognitionSupportCallback callback) {
+ mIntent = intent;
+ mCallbackExecutor = callbackExecutor;
+ mCallback = callback;
+ }
+ }
+
/**
* Internal wrapper of IRecognitionListener which will propagate the results to
* RecognitionListener
@@ -890,40 +908,22 @@
}
private static class InternalSupportCallback extends IRecognitionSupportCallback.Stub {
+ private final Executor mExecutor;
private final RecognitionSupportCallback mCallback;
- private static final int MSG_SUPPORT_RESULT = 1;
- private static final int MSG_ERROR = 2;
-
- private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- if (mCallback == null) {
- return;
- }
- switch (msg.what) {
- case MSG_SUPPORT_RESULT:
- mCallback.onSupportResult((RecognitionSupport) msg.obj);
- break;
- case MSG_ERROR:
- mCallback.onError((Integer) msg.obj);
- break;
- }
- }
- };
-
- private InternalSupportCallback(RecognitionSupportCallback callback) {
+ private InternalSupportCallback(Executor executor, RecognitionSupportCallback callback) {
+ this.mExecutor = executor;
this.mCallback = callback;
}
@Override
public void onSupportResult(RecognitionSupport recognitionSupport) throws RemoteException {
- Message.obtain(mInternalHandler, MSG_SUPPORT_RESULT, recognitionSupport).sendToTarget();
+ mExecutor.execute(() -> mCallback.onSupportResult(recognitionSupport));
}
@Override
public void onError(int errorCode) throws RemoteException {
- Message.obtain(mInternalHandler, MSG_ERROR, errorCode).sendToTarget();
+ mExecutor.execute(() -> mCallback.onError(errorCode));
}
}
}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 048b94f..188bc3f 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -67,6 +67,13 @@
public static final String SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME =
"settings_app_allow_dark_theme_activation_at_bedtime";
+ /**
+ * Hide back key in the Settings two pane design.
+ * @hide
+ */
+ public static final String SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE =
+ "settings_hide_secondary_page_back_button_in_two_pane";
+
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -92,6 +99,7 @@
DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "false");
+ DEFAULT_FLAGS.put(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
@@ -101,6 +109,7 @@
PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
+ PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE);
}
/**
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index b8eb602..8e3cc34 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -499,9 +499,9 @@
*
* @param callback The extended frame callback to run during the next frame.
*
- * @see #removeExtendedFrameCallback
+ * @see #removeVsyncCallback
*/
- public void postExtendedFrameCallback(@NonNull ExtendedFrameCallback callback) {
+ public void postVsyncCallback(@NonNull VsyncCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
@@ -603,9 +603,9 @@
*
* @param callback The extended frame callback to remove.
*
- * @see #postExtendedFrameCallback
+ * @see #postVsyncCallback
*/
- public void removeExtendedFrameCallback(@Nullable ExtendedFrameCallback callback) {
+ public void removeVsyncCallback(@Nullable VsyncCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
@@ -1021,7 +1021,7 @@
* The time in {@link System#nanoTime()} timebase which this frame is expected to be
* presented.
*/
- public long getExpectedPresentTimeNanos() {
+ public long getExpectedPresentationTimeNanos() {
return mExpectedPresentTimeNanos;
}
@@ -1034,7 +1034,7 @@
}
/**
- * The payload for {@link ExtendedFrameCallback} which includes frame information such as when
+ * The payload for {@link VsyncCallback} which includes frame information such as when
* the frame started being rendered, and multiple possible frame timelines and their
* information including deadline and expected present time.
*/
@@ -1101,7 +1101,7 @@
*
* @see FrameCallback
*/
- public interface ExtendedFrameCallback {
+ public interface VsyncCallback {
/**
* Called when a new display frame is being rendered.
*
@@ -1214,7 +1214,7 @@
void run(FrameData frameData) {
if (token == EXTENDED_FRAME_CALLBACK_TOKEN) {
- ((ExtendedFrameCallback) action).onVsync(frameData);
+ ((VsyncCallback) action).onVsync(frameData);
} else {
run(frameData.getFrameTimeNanos());
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 36baa04..ce21086 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,7 +65,7 @@
import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
/**
* System private interface to the window manager.
@@ -926,21 +926,21 @@
* registered, the registered callback will not be unregistered until
* {@link unregisterTaskFpsCallback()} is called
* @param taskId task id of the task.
- * @param listener listener to be registered.
+ * @param callback callback to be registered.
*
* @hide
*/
- void registerTaskFpsCallback(in int taskId, in IOnFpsCallbackListener listener);
+ void registerTaskFpsCallback(in int taskId, in ITaskFpsCallback callback);
/**
* Unregisters the frame rate per second count callback which was registered with
* {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
*
- * @param listener listener to be unregistered.
+ * @param callback callback to be unregistered.
*
* @hide
*/
- void unregisterTaskFpsCallback(in IOnFpsCallbackListener listener);
+ void unregisterTaskFpsCallback(in ITaskFpsCallback listener);
/**
* Take a snapshot using the same path that's used for Recents. This is used for Testing only.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ce54968..c08177e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -46,10 +46,13 @@
import android.gui.DropInputMode;
import android.hardware.DataSpace;
import android.hardware.HardwareBuffer;
+import android.hardware.SyncFence;
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
import android.hardware.graphics.common.DisplayDecorationSupport;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSync;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
@@ -209,7 +212,7 @@
private static native void nativeReparent(long transactionObj, long nativeObject,
long newParentNativeObject);
private static native void nativeSetBuffer(long transactionObj, long nativeObject,
- HardwareBuffer buffer);
+ HardwareBuffer buffer, long fencePtr);
private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
int transform);
private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
@@ -3692,8 +3695,44 @@
*/
public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
@Nullable HardwareBuffer buffer) {
+ return setBuffer(sc, buffer, null);
+ }
+
+ /**
+ * Updates the HardwareBuffer displayed for the SurfaceControl.
+ *
+ * Note that the buffer must be allocated with {@link HardwareBuffer#USAGE_COMPOSER_OVERLAY}
+ * as well as {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE} as the surface control might
+ * be composited using either an overlay or using the GPU.
+ *
+ * A presentation fence may be passed to improve performance by allowing the buffer
+ * to complete rendering while it is waiting for the transaction to be applied.
+ * For example, if the buffer is being produced by rendering with OpenGL ES then
+ * a fence created with
+ * {@link android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)} can be
+ * used to allow the GPU rendering to be concurrent with the transaction. The compositor
+ * will wait for the fence to be signaled before the buffer is displayed. If multiple
+ * buffers are set as part of the same transaction, the presentation fences of all of them
+ * must signal before any buffer is displayed. That is, the entire transaction is delayed
+ * until all presentation fences have signaled, ensuring the transaction remains consistent.
+ *
+ * @param sc The SurfaceControl to update
+ * @param buffer The buffer to be displayed
+ * @param fence The presentation fence. If null or invalid, this is equivalent to
+ * {@link #setBuffer(SurfaceControl, HardwareBuffer)}
+ * @return this
+ */
+ public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
+ @Nullable HardwareBuffer buffer, @Nullable SyncFence fence) {
checkPreconditions(sc);
- nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer);
+ if (fence != null) {
+ synchronized (fence.getLock()) {
+ nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
+ fence.getNativeFence());
+ }
+ } else {
+ nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0);
+ }
return this;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8236fbb..8444032 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1201,7 +1201,7 @@
mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
setFrame(mTmpFrames.frame);
registerBackCallbackOnWindow();
- if (WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// For apps requesting legacy back behavior, we add a compat callback that
// dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
// This way from system point of view, these apps are providing custom
@@ -6507,7 +6507,7 @@
if (isBack(event)
&& mContext != null
- && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// Invoke the appropriate {@link OnBackInvokedCallback} if the new back
// navigation should be used, and the key event is not handled by anything else.
OnBackInvokedCallback topCallback =
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 771d40b..1c27046 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -4865,21 +4865,24 @@
* Registers the frame rate per second count callback for one given task ID.
* Each callback can only register for receiving FPS callback for one task id until unregister
* is called. If there's no task associated with the given task id,
- * {@link IllegalArgumentException} will be thrown. If a task id destroyed after a callback is
- * registered, the registered callback will not be unregistered until
- * {@link #unregisterTaskFpsCallback(TaskFpsCallback))} is called
+ * {@link IllegalArgumentException} will be thrown. Registered callbacks should always be
+ * unregistered via {@link #unregisterTaskFpsCallback(TaskFpsCallback)}
+ * even when the task id has been destroyed.
+ *
* @param taskId task id of the task.
+ * @param executor Executor to execute the callback.
* @param callback callback to be registered.
*
* @hide
*/
@SystemApi
default void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
+ @NonNull Executor executor,
@NonNull TaskFpsCallback callback) {}
/**
* Unregisters the frame rate per second count callback which was registered with
- * {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
+ * {@link #registerTaskFpsCallback(Executor, int, TaskFpsCallback)}.
*
* @param callback callback to be unregistered.
*
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index f4353eb..20cdad4 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -39,14 +39,18 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.window.ITaskFpsCallback;
import android.window.TaskFpsCallback;
import android.window.WindowContext;
import android.window.WindowProvider;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -99,6 +103,10 @@
@Nullable
private final IBinder mWindowContextToken;
+ @GuardedBy("mOnFpsCallbackListenerProxies")
+ private final ArrayList<OnFpsCallbackListenerProxy> mOnFpsCallbackListenerProxies =
+ new ArrayList<>();
+
public WindowManagerImpl(Context context) {
this(context, null /* parentWindow */, null /* clientToken */);
}
@@ -424,20 +432,56 @@
}
@Override
- public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, TaskFpsCallback callback) {
+ public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, @NonNull Executor executor,
+ TaskFpsCallback callback) {
+ final OnFpsCallbackListenerProxy onFpsCallbackListenerProxy =
+ new OnFpsCallbackListenerProxy(executor, callback);
try {
WindowManagerGlobal.getWindowManagerService().registerTaskFpsCallback(
- taskId, callback.getListener());
+ taskId, onFpsCallbackListenerProxy);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ synchronized (mOnFpsCallbackListenerProxies) {
+ mOnFpsCallbackListenerProxies.add(onFpsCallbackListenerProxy);
}
}
@Override
public void unregisterTaskFpsCallback(TaskFpsCallback callback) {
- try {
- WindowManagerGlobal.getWindowManagerService().unregisterTaskFpsCallback(
- callback.getListener());
- } catch (RemoteException e) {
+ synchronized (mOnFpsCallbackListenerProxies) {
+ final Iterator<OnFpsCallbackListenerProxy> iterator =
+ mOnFpsCallbackListenerProxies.iterator();
+ while (iterator.hasNext()) {
+ final OnFpsCallbackListenerProxy proxy = iterator.next();
+ if (proxy.mCallback == callback) {
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .unregisterTaskFpsCallback(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ private static class OnFpsCallbackListenerProxy
+ extends ITaskFpsCallback.Stub {
+ private final Executor mExecutor;
+ private final TaskFpsCallback mCallback;
+
+ private OnFpsCallbackListenerProxy(Executor executor, TaskFpsCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onFpsReported(float fps) {
+ mExecutor.execute(() -> {
+ mCallback.onFpsReported(fps);
+ });
}
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index ad48ea0..48d2970 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -218,6 +218,7 @@
public static final boolean DEBUG = false;
/** @hide */
+ @TestApi
public static final String DUMPABLE_NAME = "ContentCaptureManager";
/** Error happened during the data sharing session. */
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 08cc31c..69ad739 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -391,22 +391,6 @@
public void changeInputMethodSubtype(InputMethodSubtype subtype);
/**
- * Update token of the client window requesting {@link #showSoftInput(int, ResultReceiver)}
- * @param showInputToken placeholder app window token for window requesting
- * {@link InputMethodManager#showSoftInput(View, int)}
- * @hide
- */
- public void setCurrentShowInputToken(IBinder showInputToken);
-
- /**
- * Update token of the client window requesting {@link #hideSoftInput(int, ResultReceiver)}
- * @param hideInputToken placeholder app window token for window requesting
- * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}
- * @hide
- */
- public void setCurrentHideInputToken(IBinder hideInputToken);
-
- /**
* Checks if IME is ready to start stylus handwriting session.
* If yes, {@link #startStylusHandwriting(InputChannel, List)} is called.
* @param requestId
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/window/ITaskFpsCallback.aidl
similarity index 95%
rename from core/java/android/window/IOnFpsCallbackListener.aidl
rename to core/java/android/window/ITaskFpsCallback.aidl
index 3091df3..aee403e9 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/core/java/android/window/ITaskFpsCallback.aidl
@@ -19,7 +19,7 @@
/**
* @hide
*/
-oneway interface IOnFpsCallbackListener {
+oneway interface ITaskFpsCallback {
/**
* Reports the fps from the registered task
diff --git a/core/java/android/window/TaskFpsCallback.java b/core/java/android/window/TaskFpsCallback.java
index a8e01b6..19b9f28 100644
--- a/core/java/android/window/TaskFpsCallback.java
+++ b/core/java/android/window/TaskFpsCallback.java
@@ -21,8 +21,6 @@
import android.annotation.SystemApi;
import android.os.RemoteException;
-import java.util.concurrent.Executor;
-
/**
* Callback for sampling the frames per second for a task and its children.
* This should only be used by a system component that needs to listen to a task's
@@ -30,44 +28,19 @@
* Otherwise, ASurfaceTransaction_OnComplete callbacks should be used.
*
* Each callback can only register for receiving FPS report for one task id until
- * {@link WindowManager#unregister()} is called.
+ * {@link WindowManager#unregisterTaskFpsCallback()} is called.
*
* @hide
*/
@SystemApi
-public final class TaskFpsCallback {
+public abstract class TaskFpsCallback {
/**
- * Listener interface to receive frame per second of a task.
+ * Reports the fps from the registered task
+ * @param fps The frame per second of the task that has the registered task id
+ * and its children.
*/
- public interface OnFpsCallbackListener {
- /**
- * Reports the fps from the registered task
- * @param fps The frame per second of the task that has the registered task id
- * and its children.
- */
- void onFpsReported(float fps);
- }
-
- private final IOnFpsCallbackListener mListener;
-
- public TaskFpsCallback(@NonNull Executor executor, @NonNull OnFpsCallbackListener listener) {
- mListener = new IOnFpsCallbackListener.Stub() {
- @Override
- public void onFpsReported(float fps) {
- executor.execute(() -> {
- listener.onFpsReported(fps);
- });
- }
- };
- }
-
- /**
- * @hide
- */
- public IOnFpsCallbackListener getListener() {
- return mListener;
- }
+ public abstract void onFpsReported(float fps);
/**
* Dispatch the collected sample.
@@ -76,7 +49,7 @@
*/
@BinderThread
private static void dispatchOnFpsReported(
- @NonNull IOnFpsCallbackListener listener, float fps) {
+ @NonNull ITaskFpsCallback listener, float fps) {
try {
listener.onFpsReported(fps);
} catch (RemoteException e) {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 62292f97..0503c40 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -19,9 +19,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.compat.CompatChanges;
+import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Log;
import android.view.IWindow;
import android.view.IWindowSession;
@@ -50,10 +52,9 @@
private IWindowSession mWindowSession;
private IWindow mWindow;
private static final String TAG = "WindowOnBackDispatcher";
- private static final boolean DEBUG = false;
private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
- .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
/** Convenience hashmap to quickly decide if a callback has been added. */
private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
@@ -227,10 +228,23 @@
*
* Legacy back behavior dispatches KEYCODE_BACK instead of invoking the application registered
* {@link android.view.OnBackInvokedCallback}.
- *
*/
- public static boolean shouldUseLegacyBack() {
- return !CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME)
- || !IS_BACK_PREDICTABILITY_ENABLED;
+ public static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) {
+ // new back is enabled if the app targets T AND the feature flag is enabled AND the app
+ // does not explicitly request legacy back.
+ boolean targetsT = CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME);
+ boolean featureFlagEnabled = IS_BACK_PREDICTABILITY_ENABLED;
+ // If the context is null, we assume true and fallback on the two other conditions.
+ boolean appRequestsLegacy =
+ context == null || !context.getApplicationInfo().isOnBackInvokedCallbackEnabled();
+
+ if (DEBUG) {
+ Log.d(TAG, TextUtils.formatSimple("App: %s isChangeEnabled=%s featureFlagEnabled=%s "
+ + "onBackInvokedEnabled=%s",
+ context != null ? context.getApplicationInfo().packageName : "null context",
+ targetsT, featureFlagEnabled, !appRequestsLegacy));
+ }
+
+ return targetsT && featureFlagEnabled && !appRequestsLegacy;
}
}
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index b32a6b0..1eb446e 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -249,7 +249,7 @@
dump.write("is_power_transfer_limited", UsbPortStatusProto.IS_POWER_TRANSFER_LIMITED,
status.isPowerTransferLimited());
dump.write("usb_power_brick_status", UsbPortStatusProto.USB_POWER_BRICK_STATUS,
- UsbPort.powerBrickStatusToString(status.getPowerBrickStatus()));
+ UsbPort.powerBrickConnectionStatusToString(status.getPowerBrickConnectionStatus()));
dump.end(token);
}
}
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index cfb2bf9..869da1f 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -20,15 +20,14 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.ContentObserver;
-import android.graphics.Point;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.Display;
import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
@@ -73,19 +72,16 @@
* otherwise Configuration.ORIENTATION_UNDEFINED if any orientation is lockable.
*/
public static int getRotationLockOrientation(Context context) {
- if (!areAllRotationsAllowed(context)) {
- final Point size = new Point();
- final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- try {
- final int displayId = context.getDisplayId();
- wm.getInitialDisplaySize(displayId, size);
- return size.x < size.y ?
- Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to get the display size");
- }
+ if (areAllRotationsAllowed(context)) {
+ return Configuration.ORIENTATION_UNDEFINED;
}
- return Configuration.ORIENTATION_UNDEFINED;
+ final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ final int rotation =
+ context.getResources().getConfiguration().windowConfiguration.getRotation();
+ final boolean rotated = rotation % 2 != 0;
+ final int w = rotated ? metrics.heightPixels : metrics.widthPixels;
+ final int h = rotated ? metrics.widthPixels : metrics.heightPixels;
+ return w < h ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
}
/**
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index d7eeb5f..93ce377 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -130,10 +130,6 @@
mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
- mInfo.flags = Flags<WindowInfo::Flag>(
- env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
- mInfo.type = static_cast<WindowInfo::Type>(
- env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
mInfo.dispatchingTimeout = std::chrono::milliseconds(
env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
mInfo.frameLeft = env->GetIntField(obj,
@@ -159,14 +155,72 @@
env->DeleteLocalRef(regionObj);
}
- mInfo.visible = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.visible);
- mInfo.focusable = env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable);
- mInfo.hasWallpaper = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.hasWallpaper);
- mInfo.paused = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.paused);
- mInfo.trustedOverlay = env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay);
+ const auto flags = Flags<WindowInfo::Flag>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
+ const auto type = static_cast<WindowInfo::Type>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
+ mInfo.layoutParamsFlags = flags;
+ mInfo.layoutParamsType = type;
+
+ using InputConfig = gui::WindowInfo::InputConfig;
+ // Determine the value for each of the InputConfig flags. We rely on a switch statement and
+ // -Wswitch-enum to give us a build error if we forget to explicitly handle an InputConfig flag.
+ mInfo.inputConfig = InputConfig::NONE;
+ InputConfig enumerationStart = InputConfig::NONE;
+ switch (enumerationStart) {
+ case InputConfig::NONE:
+ FALLTHROUGH_INTENDED;
+ case InputConfig::NOT_VISIBLE:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.visible) == JNI_FALSE) {
+ mInfo.inputConfig |= InputConfig::NOT_VISIBLE;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::NOT_FOCUSABLE:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable) == JNI_FALSE) {
+ mInfo.inputConfig |= InputConfig::NOT_FOCUSABLE;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::NOT_TOUCHABLE:
+ if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+ mInfo.inputConfig |= InputConfig::NOT_TOUCHABLE;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::PREVENT_SPLITTING:
+ if (!flags.test(WindowInfo::Flag::SPLIT_TOUCH)) {
+ mInfo.inputConfig |= InputConfig::PREVENT_SPLITTING;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.hasWallpaper) == JNI_TRUE) {
+ mInfo.inputConfig |= InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::IS_WALLPAPER:
+ if (type == WindowInfo::Type::WALLPAPER) {
+ mInfo.inputConfig |= InputConfig::IS_WALLPAPER;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::PAUSE_DISPATCHING:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.paused) == JNI_TRUE) {
+ mInfo.inputConfig |= InputConfig::PAUSE_DISPATCHING;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::TRUSTED_OVERLAY:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay) == JNI_TRUE) {
+ mInfo.inputConfig |= InputConfig::TRUSTED_OVERLAY;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::WATCH_OUTSIDE_TOUCH:
+ if (flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
+ mInfo.inputConfig |= InputConfig::WATCH_OUTSIDE_TOUCH;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::SLIPPERY:
+ if (flags.test(WindowInfo::Flag::SLIPPERY)) {
+ mInfo.inputConfig |= InputConfig::SLIPPERY;
+ }
+ }
+
mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
mInfo.ownerPid = env->GetIntField(obj,
@@ -274,9 +328,9 @@
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name,
env->NewStringUTF(windowInfo.name.data()));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags,
- static_cast<uint32_t>(windowInfo.flags.get()));
+ static_cast<uint32_t>(windowInfo.layoutParamsFlags.get()));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType,
- static_cast<int32_t>(windowInfo.type));
+ static_cast<int32_t>(windowInfo.layoutParamsType));
env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis,
std::chrono::duration_cast<std::chrono::milliseconds>(
windowInfo.dispatchingTimeout)
@@ -305,15 +359,17 @@
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion,
regionObj.get());
+ using InputConfig = gui::WindowInfo::InputConfig;
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible,
- windowInfo.visible);
+ !windowInfo.inputConfig.test(InputConfig::NOT_VISIBLE));
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable,
- windowInfo.focusable);
+ !windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper,
- windowInfo.hasWallpaper);
- env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused, windowInfo.paused);
+ windowInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
+ env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused,
+ windowInfo.inputConfig.test(InputConfig::PAUSE_DISPATCHING));
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay,
- windowInfo.trustedOverlay);
+ windowInfo.inputConfig.test(InputConfig::TRUSTED_OVERLAY));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
static_cast<int32_t>(windowInfo.touchOcclusionMode));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid);
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index d91d526..19402f7 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -118,11 +118,11 @@
ScopedLocalRef<jobjectArray>
frameTimelineObjs(env,
- env->NewObjectArray(vsyncEventData.frameTimelines.size(),
+ env->NewObjectArray(VsyncEventData::kFrameTimelinesLength,
gDisplayEventReceiverClassInfo
.frameTimelineClassInfo.clazz,
/*initial element*/ NULL));
- for (int i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
ScopedLocalRef<jobject>
frameTimelineObj(env,
@@ -130,8 +130,8 @@
.frameTimelineClassInfo.clazz,
gDisplayEventReceiverClassInfo
.frameTimelineClassInfo.init,
- frameTimeline.id,
- frameTimeline.expectedPresentTime,
+ frameTimeline.vsyncId,
+ frameTimeline.expectedPresentationTime,
frameTimeline.deadlineTimestamp));
env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 336161c..fb5b5ff 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -625,12 +625,16 @@
}
static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
- jobject bufferObject) {
+ jobject bufferObject, jlong fencePtr) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
android_hardware_HardwareBuffer_getNativeHardwareBuffer(env, bufferObject)));
- transaction->setBuffer(ctrl, graphicBuffer);
+ std::optional<sp<Fence>> optFence = std::nullopt;
+ if (fencePtr != 0) {
+ optFence = sp<Fence>{reinterpret_cast<Fence*>(fencePtr)};
+ }
+ transaction->setBuffer(ctrl, graphicBuffer, optFence);
}
static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2133,7 +2137,7 @@
(void*)nativeGetDisplayedContentSample },
{"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
(void*)nativeSetGeometry },
- {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;)V",
+ {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;J)V",
(void*)nativeSetBuffer },
{"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
{"nativeSetDataSpace", "(JJI)V",
diff --git a/core/res/res/drawable/default_dream_preview.xml b/core/res/res/drawable/default_dream_preview.xml
deleted file mode 100644
index bf4a04b..0000000
--- a/core/res/res/drawable/default_dream_preview.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <solid android:color="@android:color/white"/>
-</shape>
\ No newline at end of file
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 009df4a..17ec02c 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -57,6 +57,12 @@
com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
</string>
+ <!-- Component name of the activity used to inform a user about a sensory being blocked because
+ of hardware privacy switches. -->
+ <string name="config_sensorUseStartedActivity_hwToggle" translatable="false">
+ com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
+ </string>
+
<!-- Component name of the activity that shows the request for access to a usb device. -->
<string name="config_usbPermissionActivity" translatable="false">
com.android.systemui/com.android.systemui.usb.tv.TvUsbPermissionActivity
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6dc975b..0e0c6a3 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2030,6 +2030,14 @@
-->
<attr name="resetEnabledSettingsOnAppDataCleared" format="boolean" />
<attr name="knownActivityEmbeddingCerts" />
+
+ <!-- If false, {@link android.view.KeyEvent#KEYCODE_BACK KEYCODE_BACK} and
+ {@link android.app.Activity#onBackPressed Activity.onBackPressed()}
+ and related event will be forwarded to the Activities and View, otherwise those events
+ will be replaced by a call to
+ {@link android.view.OnBackInvokedCallback#onBackInvoked
+ OnBackInvokedCallback.onBackInvoked()} on the focused window. -->
+ <attr name="enableOnBackInvokedCallback" format="boolean"/>
</declare-styleable>
<!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fdb85a9..80d84d7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2902,6 +2902,11 @@
<string name="config_sensorUseStartedActivity" translatable="false"
>com.android.systemui/com.android.systemui.sensorprivacy.SensorUseStartedActivity</string>
+ <!-- Component name of the activity used to inform a user about a sensory being blocked because
+ of hardware privacy switches. -->
+ <string name="config_sensorUseStartedActivity_hwToggle" translatable="false"
+ >com.android.systemui/com.android.systemui.sensorprivacy.SensorUseStartedActivity</string>
+
<!-- Component name of the activity used to ask a user to confirm system language change after
receiving <Set Menu Language> CEC message. -->
<string name="config_hdmiCecSetMenuLanguageActivity"
@@ -5473,10 +5478,16 @@
<!-- On-device package for providing companion device associations. -->
<string name="config_systemCompanionDeviceProvider" translatable="false"></string>
- <!-- Whether this device is supporting the microphone toggle -->
+ <!-- Whether this device is supporting the software microphone toggle -->
<bool name="config_supportsMicToggle">false</bool>
<!-- Whether this device is supporting the camera toggle -->
<bool name="config_supportsCamToggle">false</bool>
+ <!-- Whether this device is supporting the hardware microphone toggle -->
+ <bool name="config_supportsHardwareMicToggle">false</bool>
+ <!-- Whether this device is supporting the hardware camera toggle -->
+ <bool name="config_supportsHardwareCamToggle">false</bool>
+ <!-- Whether a camera intent is launched when the lens cover is toggled -->
+ <bool name="config_launchCameraOnCameraLensCoverToggle">true</bool>
<!-- List containing the allowed install sources for accessibility service. -->
<string-array name="config_accessibility_allowed_install_source" translatable="false"/>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7bf34a1..9fa5f78 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3279,6 +3279,7 @@
<public name="allowUntrustedActivityEmbedding" />
<public name="knownActivityEmbeddingCerts" />
<public name="intro" />
+ <public name="enableOnBackInvokedCallback" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index db66777..f16b156 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -375,6 +375,7 @@
<java-symbol type="string" name="config_usbConfirmActivity" />
<java-symbol type="string" name="config_usbResolverActivity" />
<java-symbol type="string" name="config_sensorUseStartedActivity" />
+ <java-symbol type="string" name="config_sensorUseStartedActivity_hwToggle" />
<java-symbol type="string" name="config_hdmiCecSetMenuLanguageActivity" />
<java-symbol type="integer" name="config_minNumVisibleRecentTasks_lowRam" />
<java-symbol type="integer" name="config_maxNumVisibleRecentTasks_lowRam" />
@@ -2233,7 +2234,6 @@
<java-symbol type="string" name="config_dreamsDefaultComponent" />
<java-symbol type="array" name="config_supportedDreamComplications" />
<java-symbol type="array" name="config_dreamComplicationsEnabledByDefault" />
- <java-symbol type="drawable" name="default_dream_preview" />
<java-symbol type="array" name="config_disabledDreamComponents" />
<java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
@@ -4649,6 +4649,9 @@
<java-symbol type="bool" name="config_supportsMicToggle" />
<java-symbol type="bool" name="config_supportsCamToggle" />
+ <java-symbol type="bool" name="config_supportsHardwareMicToggle" />
+ <java-symbol type="bool" name="config_supportsHardwareCamToggle" />
+ <java-symbol type="bool" name="config_launchCameraOnCameraLensCoverToggle" />
<java-symbol type="dimen" name="starting_surface_icon_size" />
<java-symbol type="dimen" name="starting_surface_default_icon_size" />
diff --git a/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
index bf508db..2dadb20 100644
--- a/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
+++ b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
@@ -53,14 +53,15 @@
@Test
public void testRegisterAndUnregister() {
- final TaskFpsCallback.OnFpsCallbackListener listener = fps -> {
- // Ignore
+ final TaskFpsCallback callback = new TaskFpsCallback() {
+ @Override
+ public void onFpsReported(float fps) {
+ // Ignore
+ }
};
- final TaskFpsCallback callback = new TaskFpsCallback(Runnable::run, listener);
-
final List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1);
assertEquals(tasks.size(), 1);
- mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, callback);
+ mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, Runnable::run, callback);
mWindowManager.unregisterTaskFpsCallback(callback);
}
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 88228f2..2a82d8e 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C} 2018 The Android Open Source Project
+// 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.
@@ -140,13 +140,6 @@
}
prebuilt_etc {
- name: "privapp_whitelist_com.android.networkstack.tethering",
- sub_dir: "permissions",
- src: "com.android.networkstack.tethering.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "privapp_whitelist_com.android.provision",
system_ext_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.networkstack.tethering.xml b/data/etc/com.android.networkstack.tethering.xml
deleted file mode 100644
index f26a961..0000000
--- a/data/etc/com.android.networkstack.tethering.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
--->
-
-<permissions>
- <privapp-permissions package="com.android.networkstack.tethering">
- <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
- <permission name="android.permission.MANAGE_USB"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
- <permission name="android.permission.TETHER_PRIVILEGED"/>
- <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
- <permission name="android.permission.UPDATE_DEVICE_STATS"/>
- </privapp-permissions>
-</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 4aa0f07..1779655 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2653,6 +2653,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "664667685": {
+ "message": "Activity %s: enableOnBackInvokedCallback=false. Returning null BackNavigationInfo.",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"665256544": {
"message": "All windows drawn!",
"level": "DEBUG",
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index d35ecbd..0bf078d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -833,8 +833,8 @@
if (shouldExpand(null, intent, getSplitRules())) {
setLaunchingInExpandedContainer(launchingActivity, options);
- } else if (!setLaunchingToSideContainer(launchingActivity, intent, options)) {
- setLaunchingInSameContainer(launchingActivity, intent, options);
+ } else if (!splitWithLaunchingActivity(launchingActivity, intent, options)) {
+ setLaunchingInSameSideContainer(launchingActivity, intent, options);
}
return super.onStartActivity(who, intent, options);
@@ -853,9 +853,9 @@
/**
* Returns {@code true} if the activity that is going to be started via the
* {@code intent} should be paired with the {@code launchingActivity} and is set to be
- * launched in an empty side container.
+ * launched in the side container.
*/
- private boolean setLaunchingToSideContainer(Activity launchingActivity, Intent intent,
+ private boolean splitWithLaunchingActivity(Activity launchingActivity, Intent intent,
Bundle options) {
final SplitPairRule splitPairRule = getSplitRule(launchingActivity, intent,
getSplitRules());
@@ -863,9 +863,14 @@
return false;
}
- // Create a new split with an empty side container
- final TaskFragmentContainer secondaryContainer = mPresenter
- .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+ // Check if there is any existing side container to launch into.
+ TaskFragmentContainer secondaryContainer = findSideContainerForNewLaunch(
+ launchingActivity, splitPairRule);
+ if (secondaryContainer == null) {
+ // Create a new split with an empty side container.
+ secondaryContainer = mPresenter
+ .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+ }
// Amend the request to let the WM know that the activity should be placed in the
// dedicated container.
@@ -875,12 +880,39 @@
}
/**
+ * Finds if there is an existing split side {@link TaskFragmentContainer} that can be used
+ * for the new rule.
+ */
+ @Nullable
+ private TaskFragmentContainer findSideContainerForNewLaunch(Activity launchingActivity,
+ SplitPairRule splitPairRule) {
+ final TaskFragmentContainer launchingContainer = getContainerWithActivity(
+ launchingActivity.getActivityToken());
+ if (launchingContainer == null) {
+ return null;
+ }
+
+ // We only check if the launching activity is the primary of the split. We will check
+ // if the launching activity is the secondary in #setLaunchingInSameSideContainer.
+ final SplitContainer splitContainer = getActiveSplitForContainer(launchingContainer);
+ if (splitContainer == null
+ || splitContainer.getPrimaryContainer() != launchingContainer) {
+ return null;
+ }
+
+ if (canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
+ return splitContainer.getSecondaryContainer();
+ }
+ return null;
+ }
+
+ /**
* Checks if the activity that is going to be started via the {@code intent} should be
* paired with the existing top activity which is currently paired with the
- * {@code launchingActivity}. If so, set the activity to be launched in the same
+ * {@code launchingActivity}. If so, set the activity to be launched in the same side
* container of the {@code launchingActivity}.
*/
- private void setLaunchingInSameContainer(Activity launchingActivity, Intent intent,
+ private void setLaunchingInSameSideContainer(Activity launchingActivity, Intent intent,
Bundle options) {
final TaskFragmentContainer launchingContainer = getContainerWithActivity(
launchingActivity.getActivityToken());
@@ -911,6 +943,11 @@
return;
}
+ // Can only launch in the same container if the rules share the same presentation.
+ if (!canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
+ return;
+ }
+
// Amend the request to let the WM know that the activity should be placed in the
// dedicated container. This is necessary for the case that the activity is started
// into a new Task, or new Task will be escaped from the current host Task and be
@@ -928,4 +965,31 @@
public boolean isActivityEmbedded(@NonNull Activity activity) {
return mPresenter.isActivityEmbedded(activity.getActivityToken());
}
+
+ /**
+ * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if
+ * there is any.
+ */
+ private static boolean canReuseContainer(SplitRule rule1, SplitRule rule2) {
+ if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) {
+ return false;
+ }
+ return rule1.getSplitRatio() == rule2.getSplitRatio()
+ && rule1.getLayoutDirection() == rule2.getLayoutDirection();
+ }
+
+ /**
+ * Whether it is ok for other rule to reuse the {@link TaskFragmentContainer} of the given
+ * rule.
+ */
+ private static boolean isContainerReusableRule(SplitRule rule) {
+ // We don't expect to reuse the placeholder rule.
+ if (!(rule instanceof SplitPairRule)) {
+ return false;
+ }
+ final SplitPairRule pairRule = (SplitPairRule) rule;
+
+ // Not reuse if it needs to destroy the existing.
+ return !pairRule.shouldClearTop();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 8d5fdfb..e50ad38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -54,7 +54,7 @@
private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
public static final boolean IS_ENABLED = SystemProperties
- .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
"persist.debug.back_predictability_progress_threshold";
private static final int PROGRESS_THRESHOLD = SystemProperties
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index e616172..77fd228 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -620,7 +620,7 @@
setCurrentValue(bounds);
final Rect insets = computeInsets(fraction);
final float degree, x, y;
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (Transitions.SHELL_TRANSITIONS_ROTATION) {
if (rotationDelta == ROTATION_90) {
degree = 90 * (1 - fraction);
x = fraction * (end.left - start.left)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 86b73fc..efb52a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -74,6 +74,8 @@
/** Set to {@code true} to enable shell transitions. */
public static final boolean ENABLE_SHELL_TRANSITIONS =
SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
+ && SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
/** Transition type for exiting PIP via the Shell, via pressing the expand button. */
public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 1;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
index a20a201..0a3321e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -16,8 +16,8 @@
package com.android.wm.shell.flicker.bubble
-import android.platform.test.annotations.Presubmit
-import androidx.test.filters.RequiresDevice
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
@@ -25,8 +25,8 @@
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import org.junit.Assume
import org.junit.Before
-import org.junit.runner.RunWith
import org.junit.Test
+import org.junit.runner.RunWith
import org.junit.runners.Parameterized
/**
@@ -57,7 +57,7 @@
}
}
- @Presubmit
+ @FlakyTest(bugId = 218642026)
@Test
open fun testAppIsAlwaysVisible() {
testSpec.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 467cadc..f2c5093 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -167,7 +166,7 @@
* Checks that the focus changes between the [pipApp] window and the launcher when
* closing the pip window
*/
- @Postsubmit
+ @Presubmit
@Test
fun focusChanges() {
testSpec.assertEventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 173140d..c22d3f6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import com.android.server.wm.flicker.FlickerTestParameter
@@ -98,11 +97,11 @@
/**
* Checks that the focus doesn't change between windows during the transition
*/
- @Postsubmit
+ @Presubmit
@Test
open fun focusDoesNotChange() {
testSpec.assertEventLog {
this.focusDoesNotChange()
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 931d060..4f98b70 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -54,6 +54,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
+@FlakyTest(bugId = 219750830)
class ExitPipViaExpandButtonClickTest(
testSpec: FlickerTestParameter
) : ExitPipToAppTransition(testSpec) {
@@ -101,4 +102,4 @@
supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 07c3b15..19e020a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -16,10 +16,9 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -149,7 +148,7 @@
/**
* Checks that the focus doesn't change between windows during the transition
*/
- @Postsubmit
+ @FlakyTest(bugId = 216306753)
@Test
fun focusDoesNotChange() {
testSpec.assertEventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
index e91bef1..8729bb6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -55,7 +55,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
-class MovePipDownShelfHeightChangeTest(
+open class MovePipDownShelfHeightChangeTest(
testSpec: FlickerTestParameter
) : MovePipShelfHeightTransition(testSpec) {
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt
new file mode 100644
index 0000000..6c80daa
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip movement with Launcher shelf height change (decrease).
+ *
+ * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest`
+ *
+ * Actions:
+ * Launch [pipApp] in pip mode
+ * Launch [testApp]
+ * Press home
+ * Check if pip window moves down (visually)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+@FlakyTest(bugId = 219693385)
+class MovePipDownShelfHeightChangeTest_ShellTransit(
+ testSpec: FlickerTestParameter
+) : MovePipDownShelfHeightChangeTest(testSpec) {
+ @Before
+ fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
index 7e66cd3..4bc8eb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -16,15 +16,18 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.traces.region.RegionSubject
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,6 +61,11 @@
class MovePipUpShelfHeightChangeTest(
testSpec: FlickerTestParameter
) : MovePipShelfHeightTransition(testSpec) {
+ @Before
+ fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
new file mode 100644
index 0000000..0e9c99b
--- /dev/null
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ * AudioDeviceVolumeManager provides access to audio device volume control.
+ */
+public class AudioDeviceVolumeManager {
+
+ // define when using Log.*
+ //private static final String TAG = "AudioDeviceVolumeManager";
+ private static IAudioService sService;
+
+ private final String mPackageName;
+
+ public AudioDeviceVolumeManager(Context context) {
+ mPackageName = context.getApplicationContext().getOpPackageName();
+ }
+
+ /**
+ * @hide
+ * Interface to receive volume changes on a device that behaves in absolute volume mode.
+ * @see #setDeviceAbsoluteMultiVolumeBehavior(AudioDeviceAttributes, List, Executor,
+ * OnAudioDeviceVolumeChangeListener)
+ * @see #setDeviceAbsoluteVolumeBehavior(AudioDeviceAttributes, VolumeInfo, Executor,
+ * OnAudioDeviceVolumeChangeListener)
+ */
+ public interface OnAudioDeviceVolumeChangedListener {
+ /**
+ * Called the device for the given audio device has changed.
+ * @param device the audio device whose volume has changed
+ * @param vol the new volume for the device
+ */
+ void onAudioDeviceVolumeChanged(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull VolumeInfo vol);
+ }
+
+ static class ListenerInfo {
+ final @NonNull OnAudioDeviceVolumeChangedListener mListener;
+ final @NonNull Executor mExecutor;
+ final @NonNull AudioDeviceAttributes mDevice;
+
+ ListenerInfo(@NonNull OnAudioDeviceVolumeChangedListener listener, @NonNull Executor exe,
+ @NonNull AudioDeviceAttributes device) {
+ mListener = listener;
+ mExecutor = exe;
+ mDevice = device;
+ }
+ }
+
+ private final Object mDeviceVolumeListenerLock = new Object();
+ /**
+ * List of listeners for volume changes, the associated device, and their associated Executor.
+ * List is lazy-initialized on first registration
+ */
+ @GuardedBy("mDeviceVolumeListenerLock")
+ private @Nullable ArrayList<ListenerInfo> mDeviceVolumeListeners;
+
+ @GuardedBy("mDeviceVolumeListenerLock")
+ private DeviceVolumeDispatcherStub mDeviceVolumeDispatcherStub;
+
+ final class DeviceVolumeDispatcherStub extends IAudioDeviceVolumeDispatcher.Stub {
+ /**
+ * Register / unregister the stub
+ * @param register true for registering, false for unregistering
+ * @param device device for which volume is monitored
+ */
+ public void register(boolean register, @NonNull AudioDeviceAttributes device,
+ @NonNull List<VolumeInfo> volumes) {
+ try {
+ getService().registerDeviceVolumeDispatcherForAbsoluteVolume(register,
+ this, mPackageName,
+ Objects.requireNonNull(device), Objects.requireNonNull(volumes));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void dispatchDeviceVolumeChanged(
+ @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo vol) {
+ final ArrayList<ListenerInfo> volumeListeners;
+ synchronized (mDeviceVolumeListenerLock) {
+ volumeListeners = (ArrayList<ListenerInfo>) mDeviceVolumeListeners.clone();
+ }
+ for (ListenerInfo listenerInfo : volumeListeners) {
+ if (listenerInfo.mDevice.equals(device)) {
+ listenerInfo.mExecutor.execute(
+ () -> listenerInfo.mListener.onAudioDeviceVolumeChanged(device, vol));
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Configures a device to use absolute volume model, and registers a listener for receiving
+ * volume updates to apply on that device
+ * @param device the audio device set to absolute volume mode
+ * @param volume the type of volume this device responds to
+ * @param executor the Executor used for receiving volume updates through the listener
+ * @param vclistener the callback for volume updates
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void setDeviceAbsoluteVolumeBehavior(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull VolumeInfo volume,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+ final ArrayList<VolumeInfo> volumes = new ArrayList<>(1);
+ volumes.add(volume);
+ setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener);
+ }
+
+ /**
+ * @hide
+ * Configures a device to use absolute volume model applied to different volume types, and
+ * registers a listener for receiving volume updates to apply on that device
+ * @param device the audio device set to absolute multi-volume mode
+ * @param volumes the list of volumes the given device responds to
+ * @param executor the Executor used for receiving volume updates through the listener
+ * @param vclistener the callback for volume updates
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void setDeviceAbsoluteMultiVolumeBehavior(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull List<VolumeInfo> volumes,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+ Objects.requireNonNull(device);
+ Objects.requireNonNull(volumes);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(vclistener);
+
+ // TODO verify not already registered
+ //final ListenerInfo listenerInfo = new ListenerInfo(vclistener, executor, device);
+ synchronized (mDeviceVolumeListenerLock) {
+ if (mDeviceVolumeListeners == null) {
+ mDeviceVolumeListeners = new ArrayList<>();
+ }
+ if (mDeviceVolumeListeners.size() == 0) {
+ if (mDeviceVolumeDispatcherStub == null) {
+ mDeviceVolumeDispatcherStub = new DeviceVolumeDispatcherStub();
+ }
+ }
+ mDeviceVolumeDispatcherStub.register(true, device, volumes);
+ }
+ }
+
+ private static IAudioService getService() {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ sService = IAudioService.Stub.asInterface(b);
+ return sService;
+ }
+}
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
similarity index 65%
copy from core/java/android/window/IOnFpsCallbackListener.aidl
copy to media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
index 3091df3..65633fe 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-package android.window;
+package android.media;
+
+import android.media.AudioDeviceAttributes;
+import android.media.VolumeInfo;
/**
- * @hide
+ * AIDL for the AudioService to signal audio device volume changes.
+ *
+ * {@hide}
*/
-oneway interface IOnFpsCallbackListener {
+oneway interface IAudioDeviceVolumeDispatcher {
- /**
- * Reports the fps from the registered task
- * @param fps The frame rate per second of the task that has the registered task id
- * and its children.
- */
- void onFpsReported(in float fps);
+ void dispatchDeviceVolumeChanged(in AudioDeviceAttributes device, in VolumeInfo vol);
+
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index a6fdf6c..2c9f015 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.BluetoothProfileConnectionInfo;
+import android.media.IAudioDeviceVolumeDispatcher;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -44,6 +45,7 @@
import android.media.IVolumeController;
import android.media.IVolumeController;
import android.media.PlayerBase;
+import android.media.VolumeInfo;
import android.media.VolumePolicy;
import android.media.audiopolicy.AudioPolicyConfig;
import android.media.audiopolicy.AudioProductStrategy;
@@ -456,6 +458,8 @@
boolean isVolumeFixed();
+ VolumeInfo getDefaultVolumeInfo();
+
boolean isPstnCallAudioInterceptable();
oneway void muteAwaitConnection(in int[] usagesToMute, in AudioDeviceAttributes dev,
@@ -474,6 +478,7 @@
boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
+
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
void addAssistantServicesUids(in int[] assistantUID);
@@ -488,4 +493,10 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
int[] getActiveAssistantServiceUids();
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
+ in IAudioDeviceVolumeDispatcher cb,
+ in String packageName,
+ in AudioDeviceAttributes device, in List<VolumeInfo> volumes);
}
diff --git a/media/java/android/media/VolumeInfo.aidl b/media/java/android/media/VolumeInfo.aidl
new file mode 100644
index 0000000..aa82f52
--- /dev/null
+++ b/media/java/android/media/VolumeInfo.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2022, 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;
+
+parcelable VolumeInfo;
diff --git a/media/java/android/media/VolumeInfo.java b/media/java/android/media/VolumeInfo.java
new file mode 100644
index 0000000..c61b0e5
--- /dev/null
+++ b/media/java/android/media/VolumeInfo.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.audiopolicy.AudioVolumeGroup;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @hide
+ * A class to represent type of volume information.
+ * Can be used to represent volume associated with a stream type or {@link AudioVolumeGroup}.
+ * Volume index is optional when used to represent a category of volume.
+ * Index ranges are supported too, making the representation of volume changes agnostic to the
+ * range (e.g. can be used to map BT A2DP absolute volume range to internal range).
+ *
+ * Note: this class is not yet part of the SystemApi but is intended to be gradually introduced
+ * particularly in parts of the audio framework that suffer from code ambiguity when
+ * dealing with different volume ranges / units.
+ */
+public final class VolumeInfo implements Parcelable {
+ private static final String TAG = "VolumeInfo";
+
+ private final boolean mUsesStreamType; // false implies AudioVolumeGroup is used
+ private final boolean mIsMuted;
+ private final int mVolIndex;
+ private final int mMinVolIndex;
+ private final int mMaxVolIndex;
+ private final int mVolGroupId;
+ private final int mStreamType;
+
+ private static IAudioService sService;
+ private static VolumeInfo sDefaultVolumeInfo;
+
+ private VolumeInfo(boolean usesStreamType, boolean isMuted, int volIndex,
+ int minVolIndex, int maxVolIndex,
+ int volGroupId, int streamType) {
+ mUsesStreamType = usesStreamType;
+ mIsMuted = isMuted;
+ mVolIndex = volIndex;
+ mMinVolIndex = minVolIndex;
+ mMaxVolIndex = maxVolIndex;
+ mVolGroupId = volGroupId;
+ mStreamType = streamType;
+ }
+
+ /**
+ * Indicates whether this instance has a stream type associated to it.
+ * Note this method returning true implies {@link #hasVolumeGroup()} returns false.
+ * (e.g. {@link AudioManager#STREAM_MUSIC}).
+ * @return true if it has stream type information
+ */
+ public boolean hasStreamType() {
+ return mUsesStreamType;
+ }
+
+ /**
+ * Returns the associated stream type, or will throw if {@link #hasStreamType()} returned false.
+ * @return a stream type value, see AudioManager.STREAM_*
+ */
+ public int getStreamType() {
+ if (!mUsesStreamType) {
+ throw new IllegalStateException("VolumeInfo doesn't use stream types");
+ }
+ return mStreamType;
+ }
+
+ /**
+ * Indicates whether this instance has a {@link AudioVolumeGroup} associated to it.
+ * Note this method returning true implies {@link #hasStreamType()} returns false.
+ * @return true if it has volume group information
+ */
+ public boolean hasVolumeGroup() {
+ return !mUsesStreamType;
+ }
+
+ /**
+ * Returns the associated volume group, or will throw if {@link #hasVolumeGroup()} returned
+ * false.
+ * @return the volume group corresponding to this VolumeInfo, or null if an error occurred
+ * in the volume group management
+ */
+ public @Nullable AudioVolumeGroup getVolumeGroup() {
+ if (mUsesStreamType) {
+ throw new IllegalStateException("VolumeInfo doesn't use AudioVolumeGroup");
+ }
+ List<AudioVolumeGroup> volGroups = AudioVolumeGroup.getAudioVolumeGroups();
+ for (AudioVolumeGroup group : volGroups) {
+ if (group.getId() == mVolGroupId) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether this instance is conveying a mute state.
+ * @return true if the volume state is muted
+ */
+ public boolean isMuted() {
+ return mIsMuted;
+ }
+
+ /**
+ * A value used to express no volume index has been set.
+ */
+ public static final int INDEX_NOT_SET = -100;
+
+ /**
+ * Returns the volume index.
+ * @return a volume index, or {@link #INDEX_NOT_SET} if no index was set, in which case this
+ * instance is used to express a volume representation type (stream vs group) and
+ * optionally its volume range
+ */
+ public int getVolumeIndex() {
+ return mVolIndex;
+ }
+
+ /**
+ * Returns the minimum volume index.
+ * @return the minimum volume index, or {@link #INDEX_NOT_SET} if no minimum index was set.
+ */
+ public int getMinVolumeIndex() {
+ return mMinVolIndex;
+ }
+
+ /**
+ * Returns the maximum volume index.
+ * @return the maximum volume index, or {@link #INDEX_NOT_SET} if no maximum index was
+ * set.
+ */
+ public int getMaxVolumeIndex() {
+ return mMaxVolIndex;
+ }
+
+ /**
+ * Returns the default info for the platform, typically initialized
+ * to STREAM_MUSIC with min/max initialized to the associated range
+ * @return the default VolumeInfo for the device
+ */
+ public static @NonNull VolumeInfo getDefaultVolumeInfo() {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ sService = IAudioService.Stub.asInterface(b);
+ }
+ if (sDefaultVolumeInfo == null) {
+ try {
+ sDefaultVolumeInfo = sService.getDefaultVolumeInfo();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling getDefaultVolumeInfo", e);
+ // return a valid value, but don't cache it
+ return new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build();
+ }
+ }
+ return sDefaultVolumeInfo;
+ }
+
+ /**
+ * The builder class for creating and initializing, or copying and modifying VolumeInfo
+ * instances
+ */
+ public static final class Builder {
+ private boolean mUsesStreamType = true; // false implies AudioVolumeGroup is used
+ private int mStreamType = AudioManager.STREAM_MUSIC;
+ private boolean mIsMuted = false;
+ private int mVolIndex = INDEX_NOT_SET;
+ private int mMinVolIndex = INDEX_NOT_SET;
+ private int mMaxVolIndex = INDEX_NOT_SET;
+ private int mVolGroupId = -Integer.MIN_VALUE;
+
+ /**
+ * Builder constructor for stream type-based VolumeInfo
+ */
+ public Builder(int streamType) {
+ // TODO validate stream type
+ mUsesStreamType = true;
+ mStreamType = streamType;
+ }
+
+ /**
+ * Builder constructor for volume group-based VolumeInfo
+ */
+ public Builder(@NonNull AudioVolumeGroup volGroup) {
+ Objects.requireNonNull(volGroup);
+ mUsesStreamType = false;
+ mStreamType = -Integer.MIN_VALUE;
+ mVolGroupId = volGroup.getId();
+ }
+
+ /**
+ * Builder constructor to copy a given VolumeInfo.
+ * Note you can't change the stream type or volume group later.
+ */
+ public Builder(@NonNull VolumeInfo info) {
+ Objects.requireNonNull(info);
+ mUsesStreamType = info.mUsesStreamType;
+ mStreamType = info.mStreamType;
+ mIsMuted = info.mIsMuted;
+ mVolIndex = info.mVolIndex;
+ mMinVolIndex = info.mMinVolIndex;
+ mMaxVolIndex = info.mMaxVolIndex;
+ mVolGroupId = info.mVolGroupId;
+ }
+
+ /**
+ * Sets whether the volume is in a muted state
+ * @param isMuted
+ * @return the same builder instance
+ */
+ public @NonNull Builder setMuted(boolean isMuted) {
+ mIsMuted = isMuted;
+ return this;
+ }
+
+ /**
+ * Sets the volume index
+ * @param volIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+ * @return the same builder instance
+ */
+ // TODO should we allow muted true + volume index set? (useful when toggling mute on/off?)
+ public @NonNull Builder setVolumeIndex(int volIndex) {
+ if (volIndex != INDEX_NOT_SET && volIndex < 0) {
+ throw new IllegalArgumentException("Volume index cannot be negative");
+ }
+ mVolIndex = volIndex;
+ return this;
+ }
+
+ /**
+ * Sets the minimum volume index
+ * @param minIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+ * @return the same builder instance
+ */
+ public @NonNull Builder setMinVolumeIndex(int minIndex) {
+ if (minIndex != INDEX_NOT_SET && minIndex < 0) {
+ throw new IllegalArgumentException("Min volume index cannot be negative");
+ }
+ mMinVolIndex = minIndex;
+ return this;
+ }
+
+ /**
+ * Sets the maximum volume index
+ * @param maxIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+ * @return the same builder instance
+ */
+ public @NonNull Builder setMaxVolumeIndex(int maxIndex) {
+ if (maxIndex != INDEX_NOT_SET && maxIndex < 0) {
+ throw new IllegalArgumentException("Max volume index cannot be negative");
+ }
+ mMaxVolIndex = maxIndex;
+ return this;
+ }
+
+ /**
+ * Builds the VolumeInfo with the data given to the builder
+ * @return the new VolumeInfo instance
+ */
+ public @NonNull VolumeInfo build() {
+ if (mVolIndex != INDEX_NOT_SET) {
+ if (mMinVolIndex != INDEX_NOT_SET && mVolIndex < mMinVolIndex) {
+ throw new IllegalArgumentException("Volume index:" + mVolIndex
+ + " lower than min index:" + mMinVolIndex);
+ }
+ if (mMaxVolIndex != INDEX_NOT_SET && mVolIndex > mMaxVolIndex) {
+ throw new IllegalArgumentException("Volume index:" + mVolIndex
+ + " greater than max index:" + mMaxVolIndex);
+ }
+ }
+ if (mMinVolIndex != INDEX_NOT_SET && mMaxVolIndex != INDEX_NOT_SET
+ && mMinVolIndex > mMaxVolIndex) {
+ throw new IllegalArgumentException("Min volume index:" + mMinVolIndex
+ + " greater than max index:" + mMaxVolIndex);
+ }
+ return new VolumeInfo(mUsesStreamType, mIsMuted,
+ mVolIndex, mMinVolIndex, mMaxVolIndex,
+ mVolGroupId, mStreamType);
+ }
+ }
+
+ //-----------------------------------------------
+ // Parcelable
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUsesStreamType, mStreamType, mIsMuted,
+ mVolIndex, mMinVolIndex, mMaxVolIndex, mVolGroupId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ VolumeInfo that = (VolumeInfo) o;
+ return ((mUsesStreamType == that.mUsesStreamType)
+ && (mStreamType == that.mStreamType)
+ && (mIsMuted == that.mIsMuted)
+ && (mVolIndex == that.mVolIndex)
+ && (mMinVolIndex == that.mMinVolIndex)
+ && (mMaxVolIndex == that.mMaxVolIndex)
+ && (mVolGroupId == that.mVolGroupId));
+ }
+
+ @Override
+ public String toString() {
+ return new String("VolumeInfo:"
+ + (mUsesStreamType ? (" streamType:" + mStreamType)
+ : (" volGroupId" + mVolGroupId))
+ + " muted:" + mIsMuted
+ + ((mVolIndex != INDEX_NOT_SET) ? (" volIndex:" + mVolIndex) : "")
+ + ((mMinVolIndex != INDEX_NOT_SET) ? (" min:" + mMinVolIndex) : "")
+ + ((mMaxVolIndex != INDEX_NOT_SET) ? (" max:" + mMaxVolIndex) : ""));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mUsesStreamType);
+ dest.writeInt(mStreamType);
+ dest.writeBoolean(mIsMuted);
+ dest.writeInt(mVolIndex);
+ dest.writeInt(mMinVolIndex);
+ dest.writeInt(mMaxVolIndex);
+ dest.writeInt(mVolGroupId);
+ }
+
+ private VolumeInfo(@NonNull Parcel in) {
+ mUsesStreamType = in.readBoolean();
+ mStreamType = in.readInt();
+ mIsMuted = in.readBoolean();
+ mVolIndex = in.readInt();
+ mMinVolIndex = in.readInt();
+ mMaxVolIndex = in.readInt();
+ mVolGroupId = in.readInt();
+ }
+
+ public static final @NonNull Parcelable.Creator<VolumeInfo> CREATOR =
+ new Parcelable.Creator<VolumeInfo>() {
+ /**
+ * Rebuilds a VolumeInfo previously stored with writeToParcel().
+ * @param p Parcel object to read the VolumeInfo from
+ * @return a new VolumeInfo created from the data in the parcel
+ */
+ public VolumeInfo createFromParcel(Parcel p) {
+ return new VolumeInfo(p);
+ }
+
+ public VolumeInfo[] newArray(int size) {
+ return new VolumeInfo[size];
+ }
+ };
+}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 9d3fc7f..16e851b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -51,6 +51,8 @@
import androidx.appcompat.app.AppCompatActivity;
+import java.util.List;
+
/**
* A CompanionDevice activity response for showing the available
* nearby devices to be associated with.
@@ -204,10 +206,7 @@
if (mRequest.isSelfManaged()) {
initUiForSelfManagedAssociation(appLabel);
} else if (mRequest.isSingleDevice()) {
- // TODO(b/211722613)
- // Treat singleDevice as the multipleDevices for now
- // initUiForSingleDevice(appLabel);
- initUiForMultipleDevices(appLabel);
+ initUiForSingleDevice(appLabel);
} else {
initUiForMultipleDevices(appLabel);
}
@@ -221,12 +220,6 @@
}
private void onUserSelectedDevice(@NonNull DeviceFilterPair<?> selectedDevice) {
- if (mSelectedDevice != null) {
- if (DEBUG) Log.w(TAG, "Already selected.");
- return;
- }
- mSelectedDevice = requireNonNull(selectedDevice);
-
final MacAddress macAddress = selectedDevice.getMacAddress();
onAssociationApproved(macAddress);
}
@@ -346,13 +339,26 @@
private void initUiForSingleDevice(CharSequence appLabel) {
if (DEBUG) Log.i(TAG, "initUiFor_SingleDevice()");
- // TODO: use real name
- final String deviceName = "<device>";
final String deviceProfile = mRequest.getDeviceProfile();
+ CompanionDeviceDiscoveryService.getScanResult().observe(this,
+ deviceFilterPairs -> updateSingleDeviceUi(
+ deviceFilterPairs, deviceProfile, appLabel));
+
+ mListView.setVisibility(View.GONE);
+ }
+
+ private void updateSingleDeviceUi(List<DeviceFilterPair<?>> deviceFilterPairs,
+ String deviceProfile, CharSequence appLabel) {
+ // Ignore "empty" scan repots.
+ if (deviceFilterPairs.isEmpty()) return;
+ mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
+
+ final String deviceName = mSelectedDevice.getDisplayName();
final Spanned title = getHtmlFromResources(
this, R.string.confirmation_title, appLabel, deviceName);
final Spanned summary;
+
if (deviceProfile == null) {
summary = getHtmlFromResources(this, R.string.summary_generic);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
@@ -363,8 +369,6 @@
mTitle.setText(title);
mSummary.setText(summary);
-
- mListView.setVisibility(View.GONE);
}
private void initUiForMultipleDevices(CharSequence appLabel) {
@@ -405,6 +409,14 @@
if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
final DeviceFilterPair<?> selectedDevice = mAdapter.getItem(position);
+
+ if (mSelectedDevice != null) {
+ if (DEBUG) Log.w(TAG, "Already selected.");
+ return;
+ }
+
+ mSelectedDevice = requireNonNull(selectedDevice);
+
onUserSelectedDevice(selectedDevice);
}
@@ -417,9 +429,7 @@
if (mRequest.isSelfManaged()) {
onAssociationApproved(null);
} else {
- // TODO(b/211722613): call onUserSelectedDevice().
- throw new UnsupportedOperationException(
- "isSingleDevice() requests are not supported yet.");
+ onUserSelectedDevice(mSelectedDevice);
}
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 5d48708..5f07fcf 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -103,6 +103,8 @@
private final Runnable mTimeoutRunnable = this::timeout;
+ private boolean mStopAfterFirstMatch;;
+
/**
* A state enum for devices' discovery.
*/
@@ -163,8 +165,7 @@
break;
case ACTION_STOP_DISCOVERY:
- stopDiscoveryAndFinish();
- sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
+ stopDiscoveryAndFinish(/* timeout */ false);
break;
}
return START_NOT_STICKY;
@@ -182,6 +183,7 @@
requireNonNull(request);
if (mDiscoveryStarted) throw new RuntimeException("Discovery in progress.");
+ mStopAfterFirstMatch = request.isSingleDevice();
mDiscoveryStarted = true;
sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
sScanResultsLiveData.setValue(Collections.emptyList());
@@ -208,7 +210,7 @@
}
@MainThread
- private void stopDiscoveryAndFinish() {
+ private void stopDiscoveryAndFinish(boolean timeout) {
if (DEBUG) Log.i(TAG, "stopDiscovery()");
if (!mDiscoveryStarted) {
@@ -243,6 +245,12 @@
Handler.getMain().removeCallbacks(mTimeoutRunnable);
+ if (timeout) {
+ sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
+ } else {
+ sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
+ }
+
// "Finish".
stopSelf();
}
@@ -332,6 +340,7 @@
private void onDeviceFound(@NonNull DeviceFilterPair<?> device) {
runOnMainThread(() -> {
if (DEBUG) Log.v(TAG, "onDeviceFound() " + device);
+ if (mDiscoveryStopped) return;
if (mDevicesFound.contains(device)) {
// TODO: update the device instead of ignoring (new found device may contain
// additional/updated info, eg. name of the device).
@@ -347,6 +356,10 @@
mDevicesFound.add(device);
// Then: notify observers.
sScanResultsLiveData.setValue(mDevicesFound);
+ // Stop discovery when there's one device found for singleDevice.
+ if (mStopAfterFirstMatch) {
+ stopDiscoveryAndFinish(/* timeout */ false);
+ }
});
}
@@ -378,8 +391,7 @@
private void timeout() {
if (DEBUG) Log.i(TAG, "timeout()");
- stopDiscoveryAndFinish();
- sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
+ stopDiscoveryAndFinish(/* timeout */ true);
}
@Override
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 30748e6..d2a4de4 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -50,7 +50,7 @@
android:tint="?android:attr/colorAccent"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@android:drawable/ic_info"
+ android:src="@drawable/settingslib_ic_info"
android:visibility="gone" />
<Switch
diff --git a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
index 923d022..52d7775 100644
--- a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
+++ b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
@@ -34,14 +34,4 @@
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textColor="?android:attr/textColorAlertDialogListItem" />
- <ImageView
- android:id="@+id/restricted_icon"
- android:layout_width="@*android:dimen/config_restrictedIconSize"
- android:layout_height="@*android:dimen/config_restrictedIconSize"
- android:layout_alignParentRight="true"
- android:scaleType="centerInside"
- android:src="@*android:drawable/ic_info"
- android:tint="?android:attr/colorAccent"
- android:visibility="gone" />
-
</RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml b/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml
deleted file mode 100644
index 69df751..0000000
--- a/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <include layout="@layout/restricted_icon"/>
-
- <include layout="@layout/preference_widget_primary_switch"/>
-</merge>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
deleted file mode 100644
index 1520ac8..0000000
--- a/packages/SettingsLib/res/layout/restricted_switch_widget.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/restricted_icon"
- android:layout_width="@dimen/two_target_min_width"
- android:layout_height="@*android:dimen/config_restrictedIconSize"
- android:tint="?android:attr/colorAccent"
- android:src="@*android:drawable/ic_info"
- android:gravity="center" />
- <!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
- <Switch xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/switch_widget"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="false"
- android:clickable="false"
- android:background="@null" />
-</merge>
diff --git a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
index 246fc8dd..b43b444 100644
--- a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
@@ -59,7 +59,7 @@
@Override
protected int getSecondTargetResId() {
- return R.layout.restricted_preference_widget_primary_switch;
+ return R.layout.preference_widget_primary_switch;
}
@Override
@@ -67,7 +67,6 @@
super.onBindViewHolder(holder);
final View switchWidget = holder.findViewById(R.id.switchWidget);
if (switchWidget != null) {
- switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
switchWidget.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index 81146fa..db2a6ec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -22,7 +22,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.AttributeSet;
-import android.view.View;
import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.PreferenceManager;
@@ -67,23 +66,9 @@
}
@Override
- protected int getSecondTargetResId() {
- return R.layout.restricted_icon;
- }
-
- @Override
- protected boolean shouldHideSecondTarget() {
- return !isDisabledByAdmin();
- }
-
- @Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mHelper.onBindViewHolder(holder);
- final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
- if (restrictedIcon != null) {
- restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
- }
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 342189d..c607d74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -46,7 +46,6 @@
public RestrictedSwitchPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- setWidgetLayoutResource(R.layout.restricted_switch_widget);
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
if (attrs != null) {
final TypedArray attributes = context.obtainStyledAttributes(attrs,
@@ -108,15 +107,6 @@
switchSummary = mRestrictedSwitchSummary;
}
- final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
- final View switchWidget = holder.findViewById(android.R.id.switch_widget);
- if (restrictedIcon != null) {
- restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
- }
- if (switchWidget != null) {
- switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
- }
-
final ImageView icon = holder.itemView.findViewById(android.R.id.icon);
if (mIconSize > 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
index afd3626..fc38ada 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
@@ -22,6 +22,7 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
@@ -33,7 +34,10 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -48,11 +52,12 @@
private static DeviceStateRotationLockSettingsManager sSingleton;
private final ContentResolver mContentResolver;
- private final String[] mDeviceStateRotationLockDefaults;
private final Handler mMainHandler = Handler.getMain();
private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
+ private String[] mDeviceStateRotationLockDefaults;
private SparseIntArray mDeviceStateRotationLockSettings;
private SparseIntArray mDeviceStateRotationLockFallbackSettings;
+ private List<SettableDeviceState> mSettableDeviceStates;
private DeviceStateRotationLockSettingsManager(Context context) {
mContentResolver = context.getContentResolver();
@@ -73,6 +78,12 @@
return sSingleton;
}
+ /** Resets the singleton instance of this class. Only used for testing. */
+ @VisibleForTesting
+ public static synchronized void resetInstance() {
+ sSingleton = null;
+ }
+
/** Returns true if device-state based rotation lock settings are enabled. */
public static boolean isDeviceStateRotationLockEnabled(Context context) {
return context.getResources()
@@ -180,6 +191,12 @@
return true;
}
+ /** Returns a list of device states and their respective auto-rotation setting availability. */
+ public List<SettableDeviceState> getSettableDeviceStates() {
+ // Returning a copy to make sure that nothing outside can mutate our internal list.
+ return new ArrayList<>(mSettableDeviceStates);
+ }
+
private void initializeInMemoryMap() {
String serializedSetting =
Settings.Secure.getStringForUser(
@@ -215,6 +232,17 @@
}
}
+ /**
+ * Resets the state of the class and saved settings back to the default values provided by the
+ * resources config.
+ */
+ @VisibleForTesting
+ public void resetStateForTesting(Resources resources) {
+ mDeviceStateRotationLockDefaults =
+ resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
+ fallbackOnDefaults();
+ }
+
private void fallbackOnDefaults() {
loadDefaults();
persistSettings();
@@ -251,6 +279,7 @@
}
private void loadDefaults() {
+ mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockSettings = new SparseIntArray(
mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
@@ -271,6 +300,8 @@
+ values.length);
}
}
+ boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
+ mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
@@ -300,4 +331,38 @@
/** Called whenever the settings have changed. */
void onSettingsChanged();
}
+
+ /** Represents a device state and whether it has an auto-rotation setting. */
+ public static class SettableDeviceState {
+ private final int mDeviceState;
+ private final boolean mIsSettable;
+
+ SettableDeviceState(int deviceState, boolean isSettable) {
+ mDeviceState = deviceState;
+ mIsSettable = isSettable;
+ }
+
+ /** Returns the device state associated with this object. */
+ public int getDeviceState() {
+ return mDeviceState;
+ }
+
+ /** Returns whether there is an auto-rotation setting for this device state. */
+ public boolean isSettable() {
+ return mIsSettable;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SettableDeviceState)) return false;
+ SettableDeviceState that = (SettableDeviceState) o;
+ return mDeviceState == that.mDeviceState && mIsSettable == that.mIsSettable;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceState, mIsSettable);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index bd3deae..fcb56d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -50,7 +50,6 @@
public class DreamBackend {
private static final String TAG = "DreamBackend";
private static final boolean DEBUG = false;
- private final Drawable mDreamPreviewDefault;
public static class DreamInfo {
public CharSequence caption;
@@ -135,8 +134,6 @@
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
mDreamsActivatedOnDockByDefault = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
- mDreamPreviewDefault = resources.getDrawable(
- com.android.internal.R.drawable.default_dream_preview);
mDisabledDreams = Arrays.stream(resources.getStringArray(
com.android.internal.R.array.config_disabledDreamComponents))
.map(ComponentName::unflattenFromString)
@@ -182,9 +179,6 @@
dreamInfo.settingsComponentName = dreamMetadata.settingsActivity;
dreamInfo.previewImage = dreamMetadata.previewImage;
}
- if (dreamInfo.previewImage == null) {
- dreamInfo.previewImage = mDreamPreviewDefault;
- }
dreamInfos.add(dreamInfo);
}
dreamInfos.sort(mComparator);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
new file mode 100644
index 0000000..8d687b6
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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.settingslib.devicestate;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceStateRotationLockSettingsManagerTest {
+
+ @Mock private Context mMockContext;
+ @Mock private Resources mMockResources;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = InstrumentationRegistry.getTargetContext();
+ when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
+ }
+
+ @Test
+ public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
+ when(mMockResources.getStringArray(
+ R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+ new String[]{"2:2", "4:0", "1:1", "0:0"});
+
+ List<SettableDeviceState> settableDeviceStates =
+ DeviceStateRotationLockSettingsManager.getInstance(
+ mMockContext).getSettableDeviceStates();
+
+ assertThat(settableDeviceStates).containsExactly(
+ new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
+ new SettableDeviceState(/* deviceState= */ 4, /* isSettable= */ false),
+ new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ true),
+ new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
+ ).inOrder();
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
index 4e2b63b..9c16740 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
@@ -53,13 +53,7 @@
mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate(
com.android.settingslib.R.layout.preference_two_target, null));
mWidgetView = mHolder.itemView.findViewById(android.R.id.widget_frame);
- inflater.inflate(R.layout.restricted_preference_widget_primary_switch, mWidgetView, true);
- }
-
- @Test
- public void createNewPreference_shouldSetLayout() {
- assertThat(mPreference.getWidgetLayoutResource())
- .isEqualTo(R.layout.restricted_preference_widget_primary_switch);
+ inflater.inflate(R.layout.preference_widget_primary_switch, mWidgetView, true);
}
@Test
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
index 757ed76..b33c544 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
@@ -91,6 +91,9 @@
* areas, false otherwise
*/
static boolean isInAreas(ArrayList<Rect> areas, View view) {
+ if (areas.isEmpty()) {
+ return true;
+ }
for (Rect area : areas) {
if (isInArea(area, view)) {
return true;
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index cf69512..6352f81 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -1,16 +1,22 @@
# Preserve line number information for debugging stack traces.
-keepattributes SourceFile,LineNumberTable
+-keep class com.android.systemui.recents.OverviewProxyRecentsImpl
+-keep class com.android.systemui.statusbar.car.CarStatusBar
+-keep class com.android.systemui.statusbar.phone.StatusBar
+-keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.car.CarSystemUIFactory
-keep class com.android.systemui.SystemUIFactory
-keep class com.android.systemui.tv.TvSystemUIFactory
+-keep class * extends com.android.systemui.CoreStartable
+-keep class * implements com.android.systemui.CoreStartable$Injector
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keep class ** extends androidx.preference.PreferenceFragment
-
+-keep class com.android.systemui.tuner.*
-keep class com.android.systemui.plugins.** {
*;
}
@@ -19,6 +25,10 @@
}
-keep class androidx.core.app.CoreComponentFactory
+-keep public class * extends com.android.systemui.CoreStartable {
+ public <init>(android.content.Context);
+}
+
# Keep the wm shell lib
-keep class com.android.wm.shell.*
# Keep the protolog group methods that are called by the generated code
@@ -26,6 +36,11 @@
*;
}
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent { !synthetic *; }
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { !synthetic *; }
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.Dagger** { !synthetic *; }
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.Dagger** { !synthetic *; }
+
# Allows proguard to make private and protected methods and fields public as
# part of optimization. This lets proguard inline trivial getter/setter methods.
-allowaccessmodification
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index b96c5ae..13067bf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -42,6 +42,7 @@
import com.android.systemui.flags.FlagsModule;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
+import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -86,6 +87,7 @@
import com.android.systemui.wallet.dagger.WalletModule;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.dagger.DynamicOverride;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -214,4 +216,19 @@
groupManager, entryManager, notifCollection, notifPipeline, sysUiState,
notifPipelineFlags, dumpManager, sysuiMainExecutor));
}
+
+ @BindsOptionalOf
+ @DynamicOverride
+ abstract LowLightClockController optionalLowLightClockController();
+
+ @SysUISingleton
+ @Provides
+ static Optional<LowLightClockController> provideLowLightClockController(
+ @DynamicOverride Optional<LowLightClockController> optionalController) {
+ if (optionalController.isPresent() && optionalController.get().isLowLightClockEnabled()) {
+ return optionalController;
+ } else {
+ return Optional.empty();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 239109a..c8720e4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -288,7 +288,7 @@
for (TriggerSensor triggerSensor : mTriggerSensors) {
triggerSensor.setListening(false);
}
- mProximitySensor.pause();
+ mProximitySensor.destroy();
mDevicePostureController.removeCallback(mDevicePostureCallback);
mAuthController.removeCallback(mAuthControllerCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 68b74bd..8bff3ba 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -228,6 +228,7 @@
@Override
public void destroy() {
mDozeSensors.destroy();
+ mProxCheck.destroy();
}
private void onNotification(Runnable onPulseSuppressedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 4dacf65..338a8b2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -132,6 +132,7 @@
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
setCurrentState(Lifecycle.State.STARTED);
mExecutor.execute(() -> {
+ mStateController.setShouldShowComplications(shouldShowComplications());
addOverlayWindowLocked(layoutParams);
setCurrentState(Lifecycle.State.RESUMED);
mStateController.setOverlayActive(true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index bc5a52a..fc71e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -16,6 +16,7 @@
package com.android.systemui.dreams;
+import android.service.dreams.DreamService;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -84,6 +85,8 @@
@Complication.ComplicationType
private int mAvailableComplicationTypes = Complication.COMPLICATION_TYPE_NONE;
+ private boolean mShouldShowComplications = DreamService.DEFAULT_SHOW_COMPLICATIONS;
+
private final Collection<Complication> mComplications = new HashSet();
@VisibleForTesting
@@ -131,7 +134,12 @@
.filter(complication -> {
@Complication.ComplicationType
final int requiredTypes = complication.getRequiredTypeAvailability();
- return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
+ // If it should show complications, show ones whose required types are
+ // available. Otherwise, only show ones that don't require types.
+ if (mShouldShowComplications) {
+ return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
+ }
+ return requiredTypes == Complication.COMPLICATION_TYPE_NONE;
})
.collect(Collectors.toCollection(HashSet::new))
: mComplications);
@@ -221,7 +229,24 @@
public void setAvailableComplicationTypes(@Complication.ComplicationType int types) {
mExecutor.execute(() -> {
mAvailableComplicationTypes = types;
- mCallbacks.forEach(callback -> callback.onAvailableComplicationTypesChanged());
+ mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged);
+ });
+ }
+
+ /**
+ * Returns whether the dream overlay should show complications.
+ */
+ public boolean getShouldShowComplications() {
+ return mShouldShowComplications;
+ }
+
+ /**
+ * Sets whether the dream overlay should show complications.
+ */
+ public void setShouldShowComplications(boolean shouldShowComplications) {
+ mExecutor.execute(() -> {
+ mShouldShowComplications = shouldShowComplications;
+ mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 55e48a7..dd36fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -111,7 +111,7 @@
public static final ResourceBooleanFlag QS_USER_DETAIL_SHORTCUT =
new ResourceBooleanFlag(503, R.bool.flag_lockscreen_qs_user_detail_shortcut);
- public static final BooleanFlag NEW_FOOTER = new BooleanFlag(504, false);
+ public static final BooleanFlag NEW_FOOTER = new BooleanFlag(504, true);
public static final BooleanFlag NEW_HEADER = new BooleanFlag(505, false);
public static final ResourceBooleanFlag FULL_SCREEN_USER_SWITCHER =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index b96eee7..88555ed 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -102,7 +102,7 @@
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
new file mode 100644
index 0000000..0b15f4f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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.systemui.lowlightclock;
+
+import android.view.ViewGroup;
+
+/**
+ * A controller responsible for attaching and showing an optional low-light clock while dozing.
+ */
+public interface LowLightClockController {
+ /**
+ * Returns {@code true} if the low-light clock is enabled.
+ */
+ boolean isLowLightClockEnabled();
+
+ /**
+ * Attach the low light-clock to the given parent {@link ViewGroup}.
+ * @param parent The parent {@link ViewGroup} to which the low-light clock view should be
+ * attached.
+ */
+ void attachLowLightClockView(ViewGroup parent);
+
+ /**
+ * Show or hide the low-light clock.
+ * @param show Whether to show the low-light clock.
+ * @return {@code true} if the low-light clock was shown.
+ */
+ boolean showLowLightClock(boolean show);
+
+ /**
+ * An opportunity to perform burn-in prevention.
+ */
+ void dozeTimeTick();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 593b278c..6ea7aec 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -125,6 +125,7 @@
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
private int mNavBarMode;
+ private boolean mImeDrawsImeNavBar;
private final Region mTmpRegion = new Region();
private final int[] mTmpPosition = new int[2];
@@ -324,6 +325,7 @@
mIsVertical = false;
mLongClickableAccessibilityButton = false;
mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
+ mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
mSysUiFlagContainer = Dependency.get(SysUiState.class);
// Set up the context group of buttons
@@ -773,7 +775,7 @@
updateRecentsIcon();
- boolean isImeRenderingNavButtons = isGesturalMode(mNavBarMode)
+ boolean isImeRenderingNavButtons = mImeDrawsImeNavBar
&& mImeCanRenderGesturalNavButtons
&& (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0;
@@ -966,6 +968,7 @@
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
+ mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
mBarTransitions.onNavigationModeChanged(mNavBarMode);
mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
updateRotationButton();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
index 73a0c54..6920ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
@@ -156,6 +156,11 @@
mListeners.remove(listener);
}
+ public boolean getImeDrawsImeNavBar() {
+ return mCurrentUserContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_imeDrawsImeNavBar);
+ }
+
private int getCurrentInteractionMode(Context context) {
int mode = context.getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
index 6a6f572..e473dd2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
@@ -73,7 +74,7 @@
}
@Override
- protected void setDrawableTintList(ColorStateList tint) {
+ protected void setDrawableTintList(@Nullable ColorStateList tint) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
index 67cfc59..26399d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
@@ -27,6 +27,8 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.systemui.R;
import java.util.Objects;
@@ -48,6 +50,7 @@
private final TextView mSecondLine;
private final int mHorizontalPaddingPx;
+ @Nullable
private String mText;
public QSDualTileLabel(Context context) {
@@ -122,6 +125,7 @@
rescheduleUpdateText();
}
+ @Nullable
public String getText() {
return mText;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0c854df..5126fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -48,6 +48,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/** View that represents the quick settings tile panel (when expanded/pulled down). **/
public class QSPanel extends LinearLayout implements Tunable {
@@ -78,7 +79,7 @@
protected boolean mExpanded;
protected boolean mListening;
- protected QSTileHost mHost;
+ @Nullable protected QSTileHost mHost;
private final List<OnConfigurationChangedListener> mOnConfigurationChangedListeners =
new ArrayList<>();
@@ -92,14 +93,18 @@
@Nullable
private ViewGroup mHeaderContainer;
+ @Nullable
private PageIndicator mFooterPageIndicator;
private int mContentMarginStart;
private int mContentMarginEnd;
private boolean mUsingHorizontalLayout;
+ @Nullable
private LinearLayout mHorizontalLinearLayout;
+ @Nullable
protected LinearLayout mHorizontalContentContainer;
+ @Nullable
protected QSTileLayout mTileLayout;
private float mSquishinessFraction = 1f;
private final ArrayMap<View, Integer> mChildrenLayoutTop = new ArrayMap<>();
@@ -284,7 +289,7 @@
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (move) {
- int top = mChildrenLayoutTop.get(child);
+ int top = Objects.requireNonNull(mChildrenLayoutTop.get(child));
child.setLeftTopRightBottom(child.getLeft(), top + tileHeightOffset,
child.getRight(), top + tileHeightOffset + child.getHeight());
}
@@ -337,6 +342,7 @@
}
}
+ @Nullable
public QSTileHost getHost() {
return mHost;
}
@@ -501,7 +507,6 @@
mListening = listening;
}
-
protected void drawTile(QSPanelControllerBase.TileRecord r, QSTile.State state) {
r.tileView.onStateChanged(state);
}
@@ -548,6 +553,7 @@
return getMeasuredHeight();
}
+ @Nullable
QSTileLayout getTileLayout() {
return mTileLayout;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 0bff722..3172aa9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -76,6 +76,7 @@
private Consumer<Boolean> mMediaVisibilityChangedListener;
private int mLastOrientation;
private String mCachedSpecs = "";
+ @Nullable
private QSTileRevealController mQsTileRevealController;
private float mRevealExpansion;
@@ -185,6 +186,7 @@
mDumpManager.unregisterDumpable(mView.getDumpableTag());
}
+ @Nullable
protected QSTileRevealController createTileRevealController() {
return null;
}
@@ -250,6 +252,7 @@
return !mRecords.isEmpty();
}
+ @Nullable
QSTileView getTileView(QSTile tile) {
for (QSPanelControllerBase.TileRecord r : mRecords) {
if (r.tile == tile) {
@@ -411,6 +414,7 @@
mUsingHorizontalLayoutChangedListener = listener;
}
+ @Nullable
public View getBrightnessView() {
return mView.getBrightnessView();
}
@@ -425,6 +429,7 @@
public QSTile tile;
public com.android.systemui.plugins.qs.QSTileView tileView;
public boolean scanState;
+ @Nullable
public QSTile.Callback callback;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index 4b705ad..6908e5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -20,6 +20,7 @@
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
@@ -81,6 +82,7 @@
private final CarrierConfigTracker mCarrierConfigTracker;
private boolean mIsSingleCarrier;
+ @Nullable
private OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
private final SlotIndexResolver mSlotIndexResolver;
@@ -294,7 +296,8 @@
* This will get notified when the number of carriers changes between 1 and "not one".
* @param listener
*/
- public void setOnSingleCarrierChangedListener(OnSingleCarrierChangedListener listener) {
+ public void setOnSingleCarrierChangedListener(
+ @Nullable OnSingleCarrierChangedListener listener) {
mOnSingleCarrierChangedListener = listener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 90cf92a..c1970b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -96,15 +96,20 @@
private int mFocusIndex;
private boolean mNeedsFocus;
+ @Nullable
private List<String> mCurrentSpecs;
+ @Nullable
private List<TileInfo> mOtherTiles;
+ @Nullable
private List<TileInfo> mAllTiles;
+ @Nullable
private Holder mCurrentDrag;
private int mAccessibilityAction = ACTION_NONE;
private int mAccessibilityFromIndex;
private final UiEventLogger mUiEventLogger;
private final AccessibilityDelegateCompat mAccessibilityDelegate;
+ @Nullable
private RecyclerView mRecyclerView;
private int mNumColumns;
@@ -240,6 +245,7 @@
notifyDataSetChanged();
}
+ @Nullable
private TileInfo getAndRemoveOther(String s) {
for (int i = 0; i < mOtherTiles.size(); i++) {
if (mOtherTiles.get(i).spec.equals(s)) {
@@ -555,7 +561,7 @@
}
public class Holder extends ViewHolder {
- private QSTileViewImpl mTileView;
+ @Nullable private QSTileViewImpl mTileView;
public Holder(View itemView) {
super(itemView);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 106a1b6..7fb9ef3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -17,6 +17,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -49,6 +50,7 @@
private boolean mAnimationEnabled = true;
private int mState = -1;
private int mTint;
+ @Nullable
private QSTile.Icon mLastIcon;
public QSIconViewImpl(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index e8d27ec..a70f534 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -316,5 +316,5 @@
public void onKeyguardShowingChanged() {
refreshState();
}
- };
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 72c4ce8..0fb6ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -427,15 +427,17 @@
typedValue, true);
float scaleFactor = typedValue.getFloat();
- // We downscale the loaded drawable to reasonable size to protect against applications
- // using too much memory. The size can be tweaked in config.xml. Drawables
- // that are already sized properly won't be touched.
- boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
- Resources res = sysuiContext.getResources();
- int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
- ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
- : com.android.internal.R.dimen.notification_small_icon_size);
- icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+ if (icon != null) {
+ // We downscale the loaded drawable to reasonable size to protect against applications
+ // using too much memory. The size can be tweaked in config.xml. Drawables that are
+ // already sized properly won't be touched.
+ boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+ Resources res = sysuiContext.getResources();
+ int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
+ ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
+ : com.android.internal.R.dimen.notification_small_icon_size);
+ icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+ }
// No need to scale the icon, so return it as is.
if (scaleFactor == 1.f) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 7811401..fcbe179 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -507,6 +507,10 @@
pw.println(" mLeaveOpenOnKeyguardHide=" + mLeaveOpenOnKeyguardHide);
pw.println(" mKeyguardRequested=" + mKeyguardRequested);
pw.println(" mIsDozing=" + mIsDozing);
+ pw.println(" mListeners{" + mListeners.size() + "}=");
+ for (RankedListener rl : mListeners) {
+ pw.println(" " + rl.mListener);
+ }
pw.println(" Historical states:");
// Ignore records without a timestamp
int size = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index b35e684..6d774838 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -214,6 +214,7 @@
}
mStatusBarStateController.setIsDozing(dozing);
+ mNotificationShadeWindowViewController.setDozing(dozing);
}
@Override
@@ -294,6 +295,7 @@
public void dozeTimeTick() {
mNotificationPanel.dozeTimeTick();
mAuthController.dozeTimeTick();
+ mNotificationShadeWindowViewController.dozeTimeTick();
if (mAmbientIndicationContainer instanceof DozeReceiver) {
((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 4e2eb6a..396703b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -49,6 +50,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Optional;
import javax.inject.Inject;
@@ -84,6 +86,7 @@
private final DockManager mDockManager;
private final NotificationPanelViewController mNotificationPanelViewController;
private final PanelExpansionStateManager mPanelExpansionStateManager;
+ private final Optional<LowLightClockController> mLowLightClockController;
private boolean mIsTrackingBarGesture = false;
@@ -101,7 +104,8 @@
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
StatusBarWindowStateController statusBarWindowStateController,
- LockIconViewController lockIconViewController) {
+ LockIconViewController lockIconViewController,
+ Optional<LowLightClockController> lowLightClockController) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
mTunerService = tunerService;
@@ -115,6 +119,7 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mStatusBarWindowStateController = statusBarWindowStateController;
mLockIconViewController = lockIconViewController;
+ mLowLightClockController = lowLightClockController;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -171,6 +176,8 @@
};
mGestureDetector = new GestureDetector(mView.getContext(), gestureListener);
+ mLowLightClockController.ifPresent(controller -> controller.attachLowLightClockView(mView));
+
mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
@Override
public Boolean handleDispatchTouchEvent(MotionEvent ev) {
@@ -450,6 +457,21 @@
mNotificationShadeWindowController = controller;
}
+ /**
+ * Tell the controller that dozing has begun or ended.
+ * @param dozing True if dozing has begun.
+ */
+ public void setDozing(boolean dozing) {
+ mLowLightClockController.ifPresent(controller -> controller.showLowLightClock(dozing));
+ }
+
+ /**
+ * Tell the controller to perform burn-in prevention.
+ */
+ public void dozeTimeTick() {
+ mLowLightClockController.ifPresent(LowLightClockController::dozeTimeTick);
+ }
+
@VisibleForTesting
void setDragDownHelper(DragDownHelper dragDownHelper) {
mDragDownHelper = dragDownHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
index 8471e0a..a32a5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -25,6 +25,7 @@
import com.android.internal.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.Assert;
import java.util.ArrayList;
import java.util.List;
@@ -70,6 +71,7 @@
}
deviceStateManager.registerCallback(executor, state -> {
+ Assert.isMainThread();
mCurrentDevicePosture =
mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
@@ -79,11 +81,13 @@
@Override
public void addCallback(@NonNull Callback listener) {
+ Assert.isMainThread();
mListeners.add(listener);
}
@Override
public void removeCallback(@NonNull Callback listener) {
+ Assert.isMainThread();
mListeners.remove(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 5e91a25..f52c6ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -272,7 +272,7 @@
}
boolean highPowerOp = areActiveHighPowerLocationRequests();
- mAreActiveLocationRequests = highPowerOp || shouldDisplay;
+ mAreActiveLocationRequests = shouldDisplay;
if (mAreActiveLocationRequests != hadActiveLocationRequests) {
mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
}
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 3205e09..48949f92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -118,7 +118,6 @@
private boolean mColorized;
private int mTint;
private boolean mResetting;
- private boolean mWasSpinning;
// TODO(b/193539698): move these to a Controller
private RemoteInputController mController;
@@ -440,10 +439,6 @@
mEditText.requestFocus();
}
}
- if (mWasSpinning) {
- mController.addSpinning(mEntry.getKey(), mToken);
- mWasSpinning = false;
- }
}
@Override
@@ -452,7 +447,6 @@
mEditText.removeTextChangedListener(mTextWatcher);
mEditText.setOnEditorActionListener(null);
mEditText.mRemoteInputView = null;
- mWasSpinning = mController.isSpinning(mEntry.getKey(), mToken);
if (mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) {
return;
}
@@ -539,8 +533,6 @@
if (isActive() && mWrapper != null) {
mWrapper.setRemoteInputVisible(true);
}
-
- mWasSpinning = false;
}
private void reset() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
index 40982bb..460b7d9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
@@ -37,6 +37,8 @@
private final ThresholdSensor[] mPostureToPrimaryProxSensorMap;
private final ThresholdSensor[] mPostureToSecondaryProxSensorMap;
+ private final DevicePostureController mDevicePostureController;
+
@Inject
PostureDependentProximitySensor(
@PrimaryProxSensor ThresholdSensor[] postureToPrimaryProxSensorMap,
@@ -53,15 +55,24 @@
);
mPostureToPrimaryProxSensorMap = postureToPrimaryProxSensorMap;
mPostureToSecondaryProxSensorMap = postureToSecondaryProxSensorMap;
- mDevicePosture = devicePostureController.getDevicePosture();
- devicePostureController.addCallback(mDevicePostureCallback);
+ mDevicePostureController = devicePostureController;
+
+ mDevicePosture = mDevicePostureController.getDevicePosture();
+ mDevicePostureController.addCallback(mDevicePostureCallback);
chooseSensors();
}
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ mDevicePostureController.removeCallback(mDevicePostureCallback);
+ }
+
private void chooseSensors() {
if (mDevicePosture >= mPostureToPrimaryProxSensorMap.length
|| mDevicePosture >= mPostureToSecondaryProxSensorMap.length) {
- Log.e("PostureDependentProxSensor",
+ Log.e("PostureDependProxSensor",
"unsupported devicePosture=" + mDevicePosture);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
index a8a6341..c06a3a1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
@@ -73,6 +73,13 @@
}
}
+ /**
+ * Cleanup after no longer needed.
+ */
+ public void destroy() {
+ mSensor.destroy();
+ }
+
private void unregister() {
mSensor.unregister(mListener);
mRegistered.set(false);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index d3f1c93..7f64322 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -42,4 +42,10 @@
* of what is reported by the primary sensor.
*/
void setSecondarySafe(boolean safe);
+
+ /**
+ * Called when the proximity sensor is no longer needed. All listeners should
+ * be unregistered and cleaned up.
+ */
+ void destroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
index 5568f64..8ab5bc6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
@@ -252,6 +252,11 @@
}
@Override
+ public void destroy() {
+ pause();
+ }
+
+ @Override
public String getName() {
return mPrimaryThresholdSensor.getName();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index f207b9e..0a1e45c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -175,6 +175,7 @@
public void testDestroy() {
mDozeSensors.destroy();
+ verify(mProximitySensor).destroy();
verify(mTriggerSensor).setListening(false);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 7fc354f..ae387e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -299,6 +299,12 @@
verify(mAuthController).onAodInterrupt(eq(screenX), eq(screenY), eq(major), eq(minor));
}
+ @Test
+ public void testDestroy() {
+ mTriggers.destroy();
+ verify(mProximityCheck).destroy();
+ }
+
private void waitForSensorManager() {
mExecutor.runAllReady();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 627da3c..515a1ac8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -123,7 +123,7 @@
}
@Test
- public void testComplicationFiltering() {
+ public void testComplicationFilteringWhenShouldShowComplications() {
final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor);
@@ -160,4 +160,50 @@
}
}
+
+ @Test
+ public void testComplicationFilteringWhenShouldHideComplications() {
+ final DreamOverlayStateController stateController =
+ new DreamOverlayStateController(mExecutor);
+ stateController.setShouldShowComplications(true);
+
+ final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
+ final Complication weatherComplication = Mockito.mock(Complication.class);
+ when(alwaysAvailableComplication.getRequiredTypeAvailability())
+ .thenReturn(Complication.COMPLICATION_TYPE_NONE);
+ when(weatherComplication.getRequiredTypeAvailability())
+ .thenReturn(Complication.COMPLICATION_TYPE_WEATHER);
+
+ stateController.addComplication(alwaysAvailableComplication);
+ stateController.addComplication(weatherComplication);
+
+ final DreamOverlayStateController.Callback callback =
+ Mockito.mock(DreamOverlayStateController.Callback.class);
+
+ stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_WEATHER);
+ stateController.addCallback(callback);
+ mExecutor.runAllReady();
+
+ {
+ clearInvocations(callback);
+ stateController.setShouldShowComplications(true);
+ mExecutor.runAllReady();
+
+ verify(callback).onAvailableComplicationTypesChanged();
+ final Collection<Complication> complications = stateController.getComplications();
+ assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
+ assertThat(complications.contains(weatherComplication)).isTrue();
+ }
+
+ {
+ clearInvocations(callback);
+ stateController.setShouldShowComplications(false);
+ mExecutor.runAllReady();
+
+ verify(callback).onAvailableComplicationTypesChanged();
+ final Collection<Complication> complications = stateController.getComplications();
+ assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
+ assertThat(complications.contains(weatherComplication)).isFalse();
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index d13451d..03c22b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -155,4 +155,19 @@
mIconView.getIcon(largeIcon);
// no crash? good
}
-}
\ No newline at end of file
+
+ @Test
+ public void testNullIcon() {
+ Icon mockIcon = mock(Icon.class);
+ when(mockIcon.loadDrawableAsUser(any(), anyInt())).thenReturn(null);
+ mStatusBarIcon.icon = mockIcon;
+ mIconView.set(mStatusBarIcon);
+
+ Bitmap bitmap = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888);
+ Icon icon = Icon.createWithBitmap(bitmap);
+ StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+ icon, 0, 0, "");
+ mIconView.getIcon(largeIcon);
+ // No crash? good
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
index 12e71af..34a5d4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
+import com.android.systemui.lowlightclock.LowLightClockController
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationShadeDepthController
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -38,11 +39,13 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import java.util.Optional
import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@@ -79,6 +82,8 @@
private lateinit var mLockIconViewController: LockIconViewController
@Mock
private lateinit var mPhoneStatusBarViewController: PhoneStatusBarViewController
+ @Mock
+ private lateinit var mLowLightClockController: LowLightClockController
private lateinit var mInteractionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var mInteractionEventHandler: InteractionEventHandler
@@ -101,7 +106,8 @@
stackScrollLayoutController,
mStatusBarKeyguardViewManager,
mStatusBarWindowStateController,
- mLockIconViewController
+ mLockIconViewController,
+ Optional.of(mLowLightClockController)
)
mController.setupExpandedStatusBar()
mController.setService(mStatusBar, mNotificationShadeWindowController)
@@ -235,6 +241,31 @@
verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent)
assertThat(returnVal).isTrue()
}
+
+ @Test
+ fun testLowLightClockAttachedWhenExpandedStatusBarSetup() {
+ verify(mLowLightClockController).attachLowLightClockView(ArgumentMatchers.any())
+ }
+
+ @Test
+ fun testLowLightClockShownWhenDozing() {
+ mController.setDozing(true)
+ verify(mLowLightClockController).showLowLightClock(true)
+ }
+
+ @Test
+ fun testLowLightClockDozeTimeTickCalled() {
+ mController.dozeTimeTick()
+ verify(mLowLightClockController).dozeTimeTick()
+ }
+
+ @Test
+ fun testLowLightClockHiddenWhenNotDozing() {
+ mController.setDozing(true)
+ verify(mLowLightClockController).showLowLightClock(true)
+ mController.setDozing(false)
+ verify(mLowLightClockController).showLowLightClock(false)
+ }
}
private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index d885da8..6c33113 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -37,6 +37,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -56,6 +57,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -79,6 +82,7 @@
@Mock private StatusBarWindowStateController mStatusBarWindowStateController;
@Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Mock private LockIconViewController mLockIconViewController;
+ @Mock private LowLightClockController mLowLightClockController;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor;
@@ -110,7 +114,8 @@
mNotificationStackScrollLayoutController,
mStatusBarKeyguardViewManager,
mStatusBarWindowStateController,
- mLockIconViewController);
+ mLockIconViewController,
+ Optional.of(mLowLightClockController));
mController.setupExpandedStatusBar();
mController.setService(mStatusBar, mNotificationShadeWindowController);
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index f5554c5..9f9cb40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -205,6 +205,12 @@
mTestableLooper.processAllMessages();
verify(callback, times(1)).onLocationActiveChanged(false);
+
+ when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "com.google.android.googlequicksearchbox", true);
+ mTestableLooper.processAllMessages();
+ verify(callback, times(1)).onLocationActiveChanged(true);
}
@Test
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 52a0aa7..d218af3 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -45,7 +45,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
@@ -369,13 +368,10 @@
// we are only interested in doing things at PHASE_BOOT_COMPLETED
if (phase == PHASE_BOOT_COMPLETED) {
+ // due to potentially long computation that holds up boot time, apex sha computations
+ // are deferred to first call
Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
getVBMetaDigestInformation();
-
- // due to potentially long computation that may hold up boot time, SHA256 computations
- // for APEXs and Modules will be executed via threads.
- Slog.i(TAG, "Executing APEX & Module digest computations");
- computeApexAndModuleDigests();
}
}
@@ -385,12 +381,6 @@
FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
}
- private void computeApexAndModuleDigests() {
- // using Executors will allow the computations to be done asynchronously, thus not holding
- // up boot time.
- Executors.defaultThreadFactory().newThread(() -> updateBinaryMeasurements()).start();
- }
-
@NonNull
private List<PackageInfo> getInstalledApexs() {
List<PackageInfo> results = new ArrayList<PackageInfo>();
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index c236a7f..569d480 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -43,6 +43,7 @@
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.UiModeManager;
+import android.app.UiModeManager.NightModeCustomReturnType;
import android.app.UiModeManager.NightModeCustomType;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -111,6 +112,9 @@
// Enable launching of applications when entering the dock.
private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
private static final String SYSTEM_PROPERTY_DEVICE_THEME = "persist.sys.theme";
+ @VisibleForTesting
+ public static final Set<Integer> SUPPORTED_NIGHT_MODE_CUSTOM_TYPES = new ArraySet(
+ new Integer[]{MODE_NIGHT_CUSTOM_TYPE_SCHEDULE, MODE_NIGHT_CUSTOM_TYPE_BEDTIME});
private final Injector mInjector;
private final Object mLock = new Object();
@@ -631,6 +635,8 @@
+ "permission ENTER_CAR_MODE_PRIORITIZED");
}
+ assertLegit(callingPackage);
+
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -671,6 +677,9 @@
// mode flag to be specified; this is so that the user can disable car mode at all
// priorities using the persistent notification.
boolean isSystemCaller = mInjector.getCallingUid() == Process.SYSTEM_UID;
+ if (!isSystemCaller) {
+ assertLegit(callingPackage);
+ }
final int carModeFlags =
isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES;
@@ -728,8 +737,13 @@
case UiModeManager.MODE_NIGHT_NO:
case UiModeManager.MODE_NIGHT_YES:
case MODE_NIGHT_AUTO:
- case MODE_NIGHT_CUSTOM:
break;
+ case MODE_NIGHT_CUSTOM:
+ if (SUPPORTED_NIGHT_MODE_CUSTOM_TYPES.contains(customModeType)) {
+ break;
+ }
+ throw new IllegalArgumentException(
+ "Can't set the custom type to " + customModeType);
default:
throw new IllegalArgumentException("Unknown mode: " + mode);
}
@@ -783,7 +797,7 @@
}
@Override
- public int getNightModeCustomType() {
+ public @NightModeCustomReturnType int getNightModeCustomType() {
if (getContext().checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e56098c..559c309 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -188,6 +188,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.PendingIntentStats;
import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
import android.app.SyncNotedAppOp;
@@ -5614,15 +5615,29 @@
synchronized (mProcLock) {
synchronized (mPidsSelfLocked) {
+ int newestTimeIndex = -1;
+ long newestTime = Long.MIN_VALUE;
for (int i = 0; i < pids.length; i++) {
ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
if (pr != null) {
- final boolean isPendingTop =
- mPendingStartActivityUids.isPendingTopPid(pr.uid, pids[i]);
- states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.mState.getCurProcState();
- if (scores != null) {
- scores[i] = isPendingTop
- ? (ProcessList.FOREGROUND_APP_ADJ - 1) : pr.mState.getCurAdj();
+ final long pendingTopTime =
+ mPendingStartActivityUids.getPendingTopPidTime(pr.uid, pids[i]);
+ if (pendingTopTime != PendingStartActivityUids.INVALID_TIME) {
+ // The uid in mPendingStartActivityUids gets the TOP process state.
+ states[i] = PROCESS_STATE_TOP;
+ if (scores != null) {
+ // The uid in mPendingStartActivityUids gets a better score.
+ scores[i] = ProcessList.FOREGROUND_APP_ADJ - 1;
+ }
+ if (pendingTopTime > newestTime) {
+ newestTimeIndex = i;
+ newestTime = pendingTopTime;
+ }
+ } else {
+ states[i] = pr.mState.getCurProcState();
+ if (scores != null) {
+ scores[i] = pr.mState.getCurAdj();
+ }
}
} else {
states[i] = PROCESS_STATE_NONEXISTENT;
@@ -5631,6 +5646,13 @@
}
}
}
+ // The uid with the newest timestamp in mPendingStartActivityUids gets the best
+ // score.
+ if (newestTimeIndex != -1) {
+ if (scores != null) {
+ scores[newestTimeIndex] = ProcessList.FOREGROUND_APP_ADJ - 2;
+ }
+ }
}
}
}
@@ -15952,6 +15974,11 @@
implements ActivityManagerLocal {
@Override
+ public List<PendingIntentStats> getPendingIntentStats() {
+ return mPendingIntentController.dumpPendingIntentStatsForStatsd();
+ }
+
+ @Override
public Pair<String, String> getAppProfileStatsForDebugging(long time, int lines) {
return mAppProfiler.getAppProfileStatsForDebugging(time, lines);
}
diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java
index 34d9a60..1e1024e 100644
--- a/services/core/java/com/android/server/am/AnrHelper.java
+++ b/services/core/java/com/android/server/am/AnrHelper.java
@@ -60,6 +60,10 @@
*/
private long mLastAnrTimeMs = 0L;
+ /** The pid which is running appNotResponding(). */
+ @GuardedBy("mAnrRecords")
+ private int mProcessingPid = -1;
+
AnrHelper(final ActivityManagerService service) {
mService = service;
}
@@ -73,7 +77,18 @@
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
+ final int incomingPid = anrProcess.mPid;
synchronized (mAnrRecords) {
+ if (mProcessingPid == incomingPid) {
+ Slog.i(TAG, "Skip duplicated ANR, pid=" + incomingPid + " " + annotation);
+ return;
+ }
+ for (int i = mAnrRecords.size() - 1; i >= 0; i--) {
+ if (mAnrRecords.get(i).mPid == incomingPid) {
+ Slog.i(TAG, "Skip queued ANR, pid=" + incomingPid + " " + annotation);
+ return;
+ }
+ }
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation));
}
@@ -87,8 +102,8 @@
}
/**
- * The thread to execute {@link ProcessRecord#appNotResponding}. It will terminate if all
- * records are handled.
+ * The thread to execute {@link ProcessErrorStateRecord#appNotResponding}. It will terminate if
+ * all records are handled.
*/
private class AnrConsumerThread extends Thread {
AnrConsumerThread() {
@@ -97,7 +112,12 @@
private AnrRecord next() {
synchronized (mAnrRecords) {
- return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
+ if (mAnrRecords.isEmpty()) {
+ return null;
+ }
+ final AnrRecord record = mAnrRecords.remove(0);
+ mProcessingPid = record.mPid;
+ return record;
}
}
@@ -106,6 +126,13 @@
AnrRecord r;
while ((r = next()) != null) {
scheduleBinderHeavyHitterAutoSamplerIfNecessary();
+ final int currentPid = r.mApp.mPid;
+ if (currentPid != r.mPid) {
+ // The process may have restarted or died.
+ Slog.i(TAG, "Skip ANR with mismatched pid=" + r.mPid + ", current pid="
+ + currentPid);
+ continue;
+ }
final long startTime = SystemClock.uptimeMillis();
// If there are many ANR at the same time, the latency may be larger. If the latency
// is too large, the stack trace might not be meaningful.
@@ -120,6 +147,7 @@
mRunning.set(false);
synchronized (mAnrRecords) {
+ mProcessingPid = -1;
// The race should be unlikely to happen. Just to make sure we don't miss.
if (!mAnrRecords.isEmpty()) {
startAnrConsumerIfNeeded();
@@ -139,6 +167,7 @@
private static class AnrRecord {
final ProcessRecord mApp;
+ final int mPid;
final String mActivityShortComponentName;
final String mParentShortComponentName;
final String mAnnotation;
@@ -151,6 +180,7 @@
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
mApp = anrProcess;
+ mPid = anrProcess.mPid;
mActivityShortComponentName = activityShortComponentName;
mParentShortComponentName = parentShortComponentName;
mAnnotation = annotation;
diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java
index 5ac5a70..075402f 100644
--- a/services/core/java/com/android/server/am/AppFGSTracker.java
+++ b/services/core/java/com/android/server/am/AppFGSTracker.java
@@ -560,20 +560,22 @@
int changes = serviceTypes ^ mForegroundServiceTypes;
for (int serviceType = Integer.highestOneBit(changes); serviceType != 0;) {
final int i = foregroundServiceTypeToIndex(serviceType);
- if ((serviceTypes & serviceType) != 0) {
- // Start this type.
- if (mEvents[i] == null) {
- mEvents[i] = new LinkedList<>();
- }
- if (!isActive(i)) {
- mEvents[i].add(new BaseTimeEvent(now));
- notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
- }
- } else {
- // Stop this type.
- if (mEvents[i] != null && isActive(i)) {
- mEvents[i].add(new BaseTimeEvent(now));
- notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
+ if (i < mEvents.length) {
+ if ((serviceTypes & serviceType) != 0) {
+ // Start this type.
+ if (mEvents[i] == null) {
+ mEvents[i] = new LinkedList<>();
+ }
+ if (!isActive(i)) {
+ mEvents[i].add(new BaseTimeEvent(now));
+ notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
+ }
+ } else {
+ // Stop this type.
+ if (mEvents[i] != null && isActive(i)) {
+ mEvents[i].add(new BaseTimeEvent(now));
+ notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
+ }
}
}
changes &= ~serviceType;
diff --git a/services/core/java/com/android/server/am/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java
index f0910dc..4c96078 100644
--- a/services/core/java/com/android/server/am/DataConnectionStats.java
+++ b/services/core/java/com/android/server/am/DataConnectionStats.java
@@ -73,7 +73,8 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
- mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler);
+ mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler,
+ Context.RECEIVER_NOT_EXPORTED);
}
@Override
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index c49e696..7ee96aa 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -28,6 +28,7 @@
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.PendingIntent;
+import android.app.PendingIntentStats;
import android.content.IIntentSender;
import android.content.Intent;
import android.os.Binder;
@@ -60,6 +61,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
/**
* Helper class for {@link ActivityManagerService} responsible for managing pending intents.
@@ -422,6 +424,55 @@
}
/**
+ * Provides some stats tracking of the current state of the PendingIntent queue.
+ *
+ * Data about the pending intent queue is intended to be used for memory impact tracking.
+ * Returned data (one per uid) will consist of instances of PendingIntentStats containing
+ * (I) number of PendingIntents and (II) total size of all bundled extras in the PIs.
+ *
+ * @hide
+ */
+ public List<PendingIntentStats> dumpPendingIntentStatsForStatsd() {
+ List<PendingIntentStats> pendingIntentStats = new ArrayList<>();
+
+ synchronized (mLock) {
+ if (mIntentSenderRecords.size() > 0) {
+ // First, aggregate PendingIntent data by package uid.
+ final SparseIntArray countsByUid = new SparseIntArray();
+ final SparseIntArray bundleSizesByUid = new SparseIntArray();
+
+ for (WeakReference<PendingIntentRecord> reference : mIntentSenderRecords.values()) {
+ if (reference == null || reference.get() == null) {
+ continue;
+ }
+ PendingIntentRecord record = reference.get();
+ int index = countsByUid.indexOfKey(record.uid);
+
+ if (index < 0) { // ie. the key was not found
+ countsByUid.put(record.uid, 1);
+ bundleSizesByUid.put(record.uid,
+ record.key.requestIntent.getExtrasTotalSize());
+ } else {
+ countsByUid.put(record.uid, countsByUid.valueAt(index) + 1);
+ bundleSizesByUid.put(record.uid,
+ bundleSizesByUid.valueAt(index)
+ + record.key.requestIntent.getExtrasTotalSize());
+ }
+ }
+
+ // Now generate the output.
+ for (int i = 0, size = countsByUid.size(); i < size; i++) {
+ pendingIntentStats.add(new PendingIntentStats(
+ countsByUid.keyAt(i),
+ countsByUid.valueAt(i),
+ /* NB: int conversion here */ bundleSizesByUid.valueAt(i) / 1024));
+ }
+ }
+ }
+ return pendingIntentStats;
+ }
+
+ /**
* Increment the number of the PendingIntentRecord for the given uid, log a warning
* if there are too many for this uid already.
*/
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index 6bf9d4e..802ea00 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -35,6 +35,8 @@
final class PendingStartActivityUids {
static final String TAG = ActivityManagerService.TAG;
+ public static final long INVALID_TIME = 0;
+
// Key is uid, value is Pair of pid and SystemClock.elapsedRealtime() when the
// uid is added.
private final SparseArray<Pair<Integer, Long>> mPendingUids = new SparseArray();
@@ -63,13 +65,20 @@
}
}
- synchronized boolean isPendingTopPid(int uid, int pid) {
+ /**
+ * Return the elapsedRealtime when the uid is added to the mPendingUids map.
+ * @param uid
+ * @param pid
+ * @return elapsedRealtime if the uid is in the mPendingUids map;
+ * INVALID_TIME if the uid is not in the mPendingUids map.
+ */
+ synchronized long getPendingTopPidTime(int uid, int pid) {
+ long ret = INVALID_TIME;
final Pair<Integer, Long> pendingPid = mPendingUids.get(uid);
- if (pendingPid != null) {
- return pendingPid.first == pid;
- } else {
- return false;
+ if (pendingPid != null && pendingPid.first == pid) {
+ ret = pendingPid.second;
}
+ return ret;
}
synchronized boolean isPendingTopUid(int uid) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c4163e6..763bbee 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1718,17 +1718,18 @@
return Zygote.MEMORY_TAG_LEVEL_NONE;
}
- // Check to see that the compat feature for TBI is enabled.
- if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
- return Zygote.MEMORY_TAG_LEVEL_TBI;
- }
-
String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
if ("sync".equals(defaultLevel)) {
return Zygote.MEMORY_TAG_LEVEL_SYNC;
} else if ("async".equals(defaultLevel)) {
return Zygote.MEMORY_TAG_LEVEL_ASYNC;
}
+
+ // Check to see that the compat feature for TBI is enabled.
+ if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
+ return Zygote.MEMORY_TAG_LEVEL_TBI;
+ }
+
return Zygote.MEMORY_TAG_LEVEL_NONE;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3e5e435..807293f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -36,6 +36,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -87,6 +88,7 @@
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo;
+import android.media.IAudioDeviceVolumeDispatcher;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -108,6 +110,7 @@
import android.media.MediaRecorder.AudioSource;
import android.media.PlayerBase;
import android.media.Spatializer;
+import android.media.VolumeInfo;
import android.media.VolumePolicy;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
@@ -4246,6 +4249,24 @@
return (mStreamStates[streamType].getIndex(device) + 5) / 10;
}
+ /**
+ * Default VolumeInfo returned by {@link VolumeInfo#getDefaultVolumeInfo()}
+ * Lazily initialized in {@link #getDefaultVolumeInfo()}
+ */
+ static VolumeInfo sDefaultVolumeInfo;
+
+ /** @see VolumeInfo#getDefaultVolumeInfo() */
+ public VolumeInfo getDefaultVolumeInfo() {
+ if (sDefaultVolumeInfo == null) {
+ sDefaultVolumeInfo = new VolumeInfo.Builder(AudioSystem.STREAM_MUSIC)
+ .setMinVolumeIndex(getStreamMinVolume(AudioSystem.STREAM_MUSIC))
+ .setMaxVolumeIndex(getStreamMaxVolume(AudioSystem.STREAM_MUSIC))
+ .setMuted(false)
+ .build();
+ }
+ return sDefaultVolumeInfo;
+ }
+
/** @see AudioManager#getUiSoundsStreamType()
* TODO(b/181140246): when using VolumeGroup alias, we are lacking configurability for
* UI Sounds identification.
@@ -6310,6 +6331,37 @@
}
/**
+ * @see AudioDeviceVolumeManager#setDeviceAbsoluteMultiVolumeBehavior
+ * @param cb
+ * @param attr
+ * @param volumes
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
+ IAudioDeviceVolumeDispatcher cb, String packageName,
+ AudioDeviceAttributes device, List<VolumeInfo> volumes) {
+ // verify permissions
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Missing MODIFY_AUDIO_ROUTING or BLUETOOTH_PRIVILEGED permissions");
+ }
+ // verify arguments
+ Objects.requireNonNull(device);
+ Objects.requireNonNull(volumes);
+
+ // current implementation maps this call to existing abs volume API of AudioManager
+ // TODO implement the volume/device listener through IAudioDeviceVolumeDispatcher
+ final int volumeBehavior = volumes.size() == 1
+ ? AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
+ : AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
+ setDeviceVolumeBehavior(device, volumeBehavior, packageName);
+ }
+
+ /**
* @see AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)
* @param device the audio device to be affected
* @param deviceVolumeBehavior one of the device behaviors
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 6866137..064e307 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -42,7 +42,6 @@
import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HighBrightnessMode;
-import com.android.server.display.config.Interpolation;
import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.RefreshRateRange;
@@ -1254,19 +1253,17 @@
}
}
- private int convertInterpolationType(Interpolation value) {
- if (value == null) {
+ private int convertInterpolationType(String value) {
+ if (TextUtils.isEmpty(value)) {
return INTERPOLATION_DEFAULT;
}
- switch (value) {
- case _default:
- return INTERPOLATION_DEFAULT;
- case linear:
- return INTERPOLATION_LINEAR;
- default:
- Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
- return INTERPOLATION_DEFAULT;
+
+ if ("linear".equals(value)) {
+ return INTERPOLATION_LINEAR;
}
+
+ Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
+ return INTERPOLATION_DEFAULT;
}
private void loadAmbientHorizonFromDdc(DisplayConfiguration config) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 940c25c..c15242a 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -41,6 +41,9 @@
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.graphics.PointF;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors;
+import android.hardware.SensorPrivacyManagerInternal;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayViewport;
import android.hardware.input.IInputDevicesChangedListener;
@@ -550,6 +553,19 @@
}
}
+ // Set the HW mic toggle switch state
+ final int micMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
+ SW_MUTE_DEVICE);
+ if (micMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
+ setSensorPrivacy(Sensors.MICROPHONE, micMuteState != InputManager.SWITCH_STATE_OFF);
+ }
+ // Set the HW camera toggle switch state
+ final int cameraMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
+ SW_CAMERA_LENS_COVER);
+ if (cameraMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
+ setSensorPrivacy(Sensors.CAMERA, cameraMuteState != InputManager.SWITCH_STATE_OFF);
+ }
+
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -2816,6 +2832,8 @@
if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
+ // Use SW_CAMERA_LENS_COVER code for camera privacy toggles
+ setSensorPrivacy(Sensors.CAMERA, lensCovered);
}
if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
@@ -2836,9 +2854,20 @@
final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
audioManager.setMicrophoneMuteFromSwitch(micMute);
+
+ setSensorPrivacy(Sensors.MICROPHONE, micMute);
}
}
+ // Set the sensor privacy state based on the hardware toggles switch states
+ private void setSensorPrivacy(@SensorPrivacyManager.Sensors.Sensor int sensor,
+ boolean enablePrivacy) {
+ final SensorPrivacyManagerInternal sensorPrivacyManagerInternal =
+ LocalServices.getService(SensorPrivacyManagerInternal.class);
+ sensorPrivacyManagerInternal.setPhysicalToggleSensorPrivacy(UserHandle.USER_CURRENT, sensor,
+ enablePrivacy);
+ }
+
// Native callback.
@SuppressWarnings("unused")
private void notifyInputChannelBroken(IBinder token) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3d34976..16b5fb1 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -682,7 +682,14 @@
return mBuffer.descendingIterator();
}
- public StatusBarNotification[] getArray(int count, boolean includeSnoozed) {
+ public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) {
+ ArrayList<Integer> currentUsers = new ArrayList<>();
+ currentUsers.add(UserHandle.USER_ALL);
+ Binder.withCleanCallingIdentity(() -> {
+ for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) {
+ currentUsers.add(user);
+ }
+ });
synchronized (mBufferLock) {
if (count == 0) count = mBufferSize;
List<StatusBarNotification> a = new ArrayList();
@@ -691,8 +698,10 @@
while (iter.hasNext() && i < count) {
Pair<StatusBarNotification, Integer> pair = iter.next();
if (pair.second != REASON_SNOOZED || includeSnoozed) {
- i++;
- a.add(pair.first);
+ if (currentUsers.contains(pair.first.getUserId())) {
+ i++;
+ a.add(pair.first);
+ }
}
}
return a.toArray(new StatusBarNotification[a.size()]);
@@ -4200,22 +4209,32 @@
android.Manifest.permission.ACCESS_NOTIFICATIONS,
"NotificationManagerService.getActiveNotifications");
- StatusBarNotification[] tmp = null;
+ ArrayList<StatusBarNotification> tmp = new ArrayList<>();
int uid = Binder.getCallingUid();
+ ArrayList<Integer> currentUsers = new ArrayList<>();
+ currentUsers.add(UserHandle.USER_ALL);
+ Binder.withCleanCallingIdentity(() -> {
+ for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) {
+ currentUsers.add(user);
+ }
+ });
+
// noteOp will check to make sure the callingPkg matches the uid
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
callingAttributionTag, null)
== MODE_ALLOWED) {
synchronized (mNotificationLock) {
- tmp = new StatusBarNotification[mNotificationList.size()];
final int N = mNotificationList.size();
- for (int i=0; i<N; i++) {
- tmp[i] = mNotificationList.get(i).getSbn();
+ for (int i = 0; i < N; i++) {
+ final StatusBarNotification sbn = mNotificationList.get(i).getSbn();
+ if (currentUsers.contains(sbn.getUserId())) {
+ tmp.add(sbn);
+ }
}
}
}
- return tmp;
+ return tmp.toArray(new StatusBarNotification[tmp.size()]);
}
/**
@@ -4324,7 +4343,7 @@
callingAttributionTag, null)
== MODE_ALLOWED) {
synchronized (mArchive) {
- tmp = mArchive.getArray(count, includeSnoozed);
+ tmp = mArchive.getArray(mUm, count, includeSnoozed);
}
}
return tmp;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8f4cef9..725e92a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6255,6 +6255,13 @@
}
});
+ if (wasNotLaunched) {
+ final String installerPackageName = wasNotLaunchedAndInstallerPackageName.second;
+ if (installerPackageName != null) {
+ notifyFirstLaunch(packageName, installerPackageName, userId);
+ }
+ }
+
scheduleWritePackageRestrictions(userId);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c19e758..936da4a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -24,6 +24,7 @@
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManager.UNINSTALL_REASON_USER_TYPE;
+import static android.os.Process.INVALID_UID;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
@@ -1117,6 +1118,9 @@
"Updating application package " + pkgName + " failed");
}
pkgSetting.setSharedUserAppId(sharedUser.mAppId);
+ } else {
+ // migrating off shared user
+ pkgSetting.setSharedUserAppId(INVALID_UID);
}
if (!pkgSetting.getPath().equals(codePath)) {
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index f87063a..9c74dd7 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -71,6 +71,14 @@
"include-filter": "com.android.server.pm.test.OverlayActorVisibilityTest"
}
]
+ },
+ {
+ "name": "CtsSharedUserMigrationTestCases",
+ "options": [
+ {
+ "include-filter": "android.uidmigration.cts"
+ }
+ ]
}
],
"presubmit-large": [
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 60d2fc1..49553f4 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -740,7 +740,7 @@
grantPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm,
DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
- userId, CONTACTS_PERMISSIONS);
+ userId, CONTACTS_PERMISSIONS, NOTIFICATION_PERMISSIONS);
// Maps
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
@@ -775,7 +775,7 @@
grantPermissionsToSystemPackage(pm, voiceInteractPackageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- NEARBY_DEVICES_PERMISSIONS);
+ NEARBY_DEVICES_PERMISSIONS, NOTIFICATION_PERMISSIONS);
}
}
@@ -784,7 +784,8 @@
grantPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
- userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
+ userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
+ NOTIFICATION_PERMISSIONS);
}
// Voice recognition
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
index f199841..91d2010 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
@@ -887,7 +887,9 @@
| flag(pkg.hasRequestForegroundServiceExemption(),
ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
| flag(pkg.areAttributionsUserVisible(),
- ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE);
+ ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
+ | flag(pkg.isOnBackInvokedCallbackEnabled(),
+ ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK);
// @formatter:on
return privateFlagsExt;
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 1754877..cdc2b12 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -387,6 +387,8 @@
*/
ParsingPackage setKnownActivityEmbeddingCerts(Set<String> knownActivityEmbeddingCerts);
+ ParsingPackage setOnBackInvokedCallbackEnabled(boolean enableOnBackInvokedCallback);
+
// TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
// for moving to the next step
@CallSuper
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index c4b1275..177eaca 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -548,6 +548,7 @@
private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48;
private static final long SDK_LIBRARY = 1L << 49;
private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
+ private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 51;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2397,6 +2398,11 @@
}
@Override
+ public boolean isOnBackInvokedCallbackEnabled() {
+ return getBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK);
+ }
+
+ @Override
public ParsingPackageImpl setBaseRevisionCode(int value) {
baseRevisionCode = value;
return this;
@@ -2995,4 +3001,10 @@
mKnownActivityEmbeddingCerts = knownEmbeddingCerts;
return this;
}
+
+ @Override
+ public ParsingPackage setOnBackInvokedCallbackEnabled(boolean value) {
+ setBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK, value);
+ return this;
+ }
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 4b659a14..428374f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -355,4 +355,9 @@
* @see R.styleable#AndroidManifest_inheritKeyStoreKeys
*/
boolean shouldInheritKeyStoreKeys();
+
+ /**
+ * @see R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
+ */
+ boolean isOnBackInvokedCallbackEnabled();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index a891980..f30daa9 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -2202,8 +2202,9 @@
.setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
.setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
.setResetEnabledSettingsOnAppDataCleared(bool(false,
- R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
- sa))
+ R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
+ sa))
+ .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
// targetSdkVersion gated
.setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
.setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4b61970..4387249 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3547,6 +3547,10 @@
if (mCameraLensCoverState == lensCoverState) {
return;
}
+ if (!mContext.getResources().getBoolean(
+ R.bool.config_launchCameraOnCameraLensCoverToggle)) {
+ return;
+ }
if (mCameraLensCoverState == CAMERA_LENS_COVERED &&
lensCoverState == CAMERA_LENS_UNCOVERED) {
Intent intent;
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 1856786..fd64c75 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,16 +16,11 @@
package com.android.server.rollback;
-import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
-
import android.annotation.AnyThread;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
@@ -240,64 +235,6 @@
return null;
}
- @WorkerThread
- private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
- int rollbackId, @Nullable VersionedPackage logPackage) {
- assertInWorkerThread();
- BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handleStagedSessionChange(rollbackManager,
- rollbackId, this /* BroadcastReceiver */, logPackage);
- }
- };
- IntentFilter sessionUpdatedFilter =
- new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
- mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter, null, mHandler);
- return sessionUpdatedReceiver;
- }
-
- @WorkerThread
- private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
- BroadcastReceiver listener, @Nullable VersionedPackage logPackage) {
- assertInWorkerThread();
- PackageInstaller packageInstaller =
- mContext.getPackageManager().getPackageInstaller();
- List<RollbackInfo> recentRollbacks =
- rollbackManager.getRecentlyCommittedRollbacks();
- for (int i = 0; i < recentRollbacks.size(); i++) {
- RollbackInfo recentRollback = recentRollbacks.get(i);
- int sessionId = recentRollback.getCommittedSessionId();
- if ((rollbackId == recentRollback.getRollbackId())
- && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
- PackageInstaller.SessionInfo sessionInfo =
- packageInstaller.getSessionInfo(sessionId);
- if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) {
- mContext.unregisterReceiver(listener);
- saveStagedRollbackId(rollbackId, logPackage);
- WatchdogRollbackLogger.logEvent(logPackage,
- FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
- WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
- "");
- } else if (sessionInfo.isStagedSessionFailed()
- && markStagedSessionHandled(rollbackId)) {
- WatchdogRollbackLogger.logEvent(logPackage,
- FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
- WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
- "");
- mContext.unregisterReceiver(listener);
- }
- }
- }
-
- // Wait for all pending staged sessions to get handled before rebooting.
- if (isPendingStagedSessionsEmpty()) {
- mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
- }
- }
-
/**
* Returns {@code true} if staged session associated with {@code rollbackId} was marked
* as handled, {@code false} if already handled.
@@ -447,12 +384,12 @@
if (status == RollbackManager.STATUS_SUCCESS) {
if (rollback.isStaged()) {
int rollbackId = rollback.getRollbackId();
- mPendingStagedRollbackIds.add(rollbackId);
- BroadcastReceiver listener =
- listenForStagedSessionReady(rollbackManager, rollbackId,
- logPackage);
- handleStagedSessionChange(rollbackManager, rollbackId, listener,
- logPackage);
+ saveStagedRollbackId(rollbackId, logPackage);
+ WatchdogRollbackLogger.logEvent(logPackage,
+ FrameworkStatsLog
+ .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
+ reasonToLog, failedPackageToLog);
+
} else {
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
@@ -460,14 +397,18 @@
reasonToLog, failedPackageToLog);
}
} else {
- if (rollback.isStaged()) {
- markStagedSessionHandled(rollback.getRollbackId());
- }
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
reasonToLog, failedPackageToLog);
}
+ if (rollback.isStaged()) {
+ markStagedSessionHandled(rollback.getRollbackId());
+ // Wait for all pending staged sessions to get handled before rebooting.
+ if (isPendingStagedSessionsEmpty()) {
+ mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
+ }
+ }
};
final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver(result -> {
diff --git a/services/core/java/com/android/server/sensorprivacy/PersistedState.java b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
index ce9fff5..06f5fc0 100644
--- a/services/core/java/com/android/server/sensorprivacy/PersistedState.java
+++ b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
@@ -295,6 +295,11 @@
TypeUserSensor userSensor = states.keyAt(i);
SensorState sensorState = states.valueAt(i);
+ // Do not persist hardware toggle states. Will be restored on reboot
+ if (userSensor.mType != SensorPrivacyManager.ToggleTypes.SOFTWARE) {
+ continue;
+ }
+
serializer.startTag(null, XML_TAG_SENSOR_STATE);
serializer.attributeInt(null, XML_ATTRIBUTE_TOGGLE_TYPE,
userSensor.mType);
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 19c8cd2..358f69e 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -39,6 +39,8 @@
import static android.hardware.SensorPrivacyManager.Sources.QS_TILE;
import static android.hardware.SensorPrivacyManager.Sources.SETTINGS;
import static android.hardware.SensorPrivacyManager.Sources.SHELL;
+import static android.hardware.SensorPrivacyManager.ToggleTypes.HARDWARE;
+import static android.hardware.SensorPrivacyManager.ToggleTypes.SOFTWARE;
import static android.os.UserHandle.USER_NULL;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
@@ -108,7 +110,6 @@
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
-import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -127,6 +128,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -139,7 +141,7 @@
private static final boolean DEBUG_LOGGING = false;
private static final String SENSOR_PRIVACY_CHANNEL_ID = Context.SENSOR_PRIVACY_SERVICE;
- private static final String ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY =
+ private static final String ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY =
SensorPrivacyService.class.getName() + ".action.disable_sensor_privacy";
public static final int REMINDER_DIALOG_DELAY_MILLIS = 500;
@@ -273,12 +275,12 @@
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- setIndividualSensorPrivacy(
+ setToggleSensorPrivacy(
((UserHandle) intent.getParcelableExtra(
Intent.EXTRA_USER)).getIdentifier(), OTHER,
intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
}
- }, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY),
+ }, new IntentFilter(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY),
MANAGE_SENSOR_PRIVACY, null, Context.RECEIVER_EXPORTED);
mContext.registerReceiver(new BroadcastReceiver() {
@@ -299,7 +301,7 @@
mSensorPrivacyStateController.setSensorPrivacyListener(
mHandler,
(toggleType, userId, sensor, state) -> mHandler.handleSensorPrivacyChanged(
- userId, sensor, state.isEnabled()));
+ userId, toggleType, sensor, state.isEnabled()));
}
@Override
@@ -308,11 +310,11 @@
// Reset sensor privacy when restriction is added
if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)
&& newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) {
- setIndividualSensorPrivacyUnchecked(userId, OTHER, CAMERA, false);
+ setToggleSensorPrivacyUnchecked(SOFTWARE, userId, OTHER, CAMERA, false);
}
if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)
&& newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) {
- setIndividualSensorPrivacyUnchecked(userId, OTHER, MICROPHONE, false);
+ setToggleSensorPrivacyUnchecked(SOFTWARE, userId, OTHER, MICROPHONE, false);
}
}
@@ -352,15 +354,15 @@
}
/**
- * Called when a sensor protected by individual sensor privacy is attempting to get used.
+ * Called when a sensor protected by toggle sensor privacy is attempting to get used.
*
* @param uid The uid of the app using the sensor
* @param packageName The package name of the app using the sensor
* @param sensor The sensor that is attempting to be used
*/
private void onSensorUseStarted(int uid, String packageName, int sensor) {
- UserHandle user = UserHandle.getUserHandleForUid(uid);
- if (!isIndividualSensorPrivacyEnabled(user.getIdentifier(), sensor)) {
+ UserHandle user = UserHandle.of(mCurrentUser);
+ if (!isCombinedToggleSensorPrivacyEnabled(sensor)) {
return;
}
@@ -371,12 +373,10 @@
}
synchronized (mLock) {
- UserHandle parentUser = UserHandle.of(mUserManagerInternal
- .getProfileParentId(user.getIdentifier()));
- if (mSuppressReminders.containsKey(new Pair<>(sensor, parentUser))) {
+ if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) {
Log.d(TAG,
"Suppressed sensor privacy reminder for " + packageName + "/"
- + parentUser);
+ + user);
return;
}
}
@@ -406,8 +406,8 @@
}
tasksOfPackageUsingSensor.add(task);
- } else if (task.topActivity.flattenToString().equals(mContext.getResources()
- .getString(R.string.config_sensorUseStartedActivity))
+ } else if (task.topActivity.flattenToString().equals(
+ getSensorUseActivityName(new ArraySet<>(Arrays.asList(sensor))))
&& task.isFocused) {
enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName,
sensor);
@@ -442,7 +442,7 @@
String inputMethodComponent = Settings.Secure.getStringForUser(
mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD,
- mCurrentUser);
+ user.getIdentifier());
String inputMethodPackageName = null;
if (inputMethodComponent != null) {
inputMethodPackageName = ComponentName.unflattenFromString(
@@ -534,9 +534,8 @@
return;
}
Intent dialogIntent = new Intent();
- dialogIntent.setComponent(ComponentName.unflattenFromString(
- mContext.getResources().getString(
- R.string.config_sensorUseStartedActivity)));
+ dialogIntent.setComponent(
+ ComponentName.unflattenFromString(getSensorUseActivityName(sensors)));
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchTaskId(info.mTaskId);
@@ -560,6 +559,21 @@
}
/**
+ * Get the activity component based on which privacy toggles are enabled.
+ * @param sensors
+ * @return component name to launch
+ */
+ private String getSensorUseActivityName(ArraySet<Integer> sensors) {
+ for (Integer sensor : sensors) {
+ if (isToggleSensorPrivacyEnabled(HARDWARE, sensor)) {
+ return mContext.getResources().getString(
+ R.string.config_sensorUseStartedActivity_hwToggle);
+ }
+ }
+ return mContext.getResources().getString(R.string.config_sensorUseStartedActivity);
+ }
+
+ /**
* Show a notification that informs the user that a sensor use or a blocked sensor started.
* The user can then react to this event.
*
@@ -619,7 +633,7 @@
String actionTitle = getUiContext().getString(
R.string.sensor_privacy_start_use_dialog_turn_on_button);
PendingIntent actionIntent = PendingIntent.getBroadcast(mContext, sensor,
- new Intent(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY)
+ new Intent(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY)
.setPackage(mContext.getPackageName())
.putExtra(EXTRA_SENSOR, sensor)
.putExtra(Intent.EXTRA_USER, user),
@@ -657,12 +671,12 @@
}
@Override
- public void setIndividualSensorPrivacy(@UserIdInt int userId,
+ public void setToggleSensorPrivacy(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
if (DEBUG) {
Log.d(TAG, "callingUid=" + Binder.getCallingUid()
+ " callingPid=" + Binder.getCallingPid()
- + " setIndividualSensorPrivacy("
+ + " setToggleSensorPrivacy("
+ "userId=" + userId
+ " source=" + source
+ " sensor=" + sensor
@@ -673,22 +687,22 @@
if (userId == UserHandle.USER_CURRENT) {
userId = mCurrentUser;
}
- if (!canChangeIndividualSensorPrivacy(userId, sensor)) {
+ if (!canChangeToggleSensorPrivacy(userId, sensor)) {
return;
}
- setIndividualSensorPrivacyUnchecked(userId, source, sensor, enable);
+ setToggleSensorPrivacyUnchecked(SOFTWARE, userId, source, sensor, enable);
}
- private void setIndividualSensorPrivacyUnchecked(int userId, int source, int sensor,
- boolean enable) {
+ private void setToggleSensorPrivacyUnchecked(int toggleType, int userId, int source,
+ int sensor, boolean enable) {
final long[] lastChange = new long[1];
mSensorPrivacyStateController.atomic(() -> {
SensorState sensorState = mSensorPrivacyStateController
- .getState(SensorPrivacyManager.ToggleTypes.SOFTWARE, userId, sensor);
+ .getState(toggleType, userId, sensor);
lastChange[0] = sensorState.getLastChange();
mSensorPrivacyStateController.setState(
- SensorPrivacyManager.ToggleTypes.SOFTWARE, userId, sensor, enable, mHandler,
+ toggleType, userId, sensor, enable, mHandler,
changeSuccessful -> {
if (changeSuccessful) {
if (userId == mUserManagerInternal.getProfileParentId(userId)) {
@@ -701,7 +715,7 @@
});
}
- private boolean canChangeIndividualSensorPrivacy(@UserIdInt int userId, int sensor) {
+ private boolean canChangeToggleSensorPrivacy(@UserIdInt int userId, int sensor) {
if (sensor == MICROPHONE && mCallStateHelper.isInEmergencyCall()) {
// During emergency call the microphone toggle managed automatically
Log.i(TAG, "Can't change mic toggle during an emergency call");
@@ -784,7 +798,7 @@
}
@Override
- public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
+ public void setToggleSensorPrivacyForProfileGroup(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
enforceManageSensorPrivacyPermission();
if (userId == UserHandle.USER_CURRENT) {
@@ -793,7 +807,7 @@
int parentId = mUserManagerInternal.getProfileParentId(userId);
forAllUsers(userId2 -> {
if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
- setIndividualSensorPrivacy(userId2, source, sensor, enable);
+ setToggleSensorPrivacy(userId2, source, sensor, enable);
}
});
}
@@ -835,31 +849,55 @@
}
@Override
- public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
+ public boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor) {
if (DEBUG) {
Log.d(TAG, "callingUid=" + Binder.getCallingUid()
+ " callingPid=" + Binder.getCallingPid()
- + " isIndividualSensorPrivacyEnabled("
- + "userId=" + userId
+ + " isToggleSensorPrivacyEnabled("
+ + "toggleType=" + toggleType
+ " sensor=" + sensor
+ ")");
}
enforceObserveSensorPrivacyPermission();
- if (userId == UserHandle.USER_CURRENT) {
- userId = mCurrentUser;
- }
- return mSensorPrivacyStateController.getState(SensorPrivacyManager.ToggleTypes.SOFTWARE,
+
+ return mSensorPrivacyStateController.getState(toggleType, mCurrentUser, sensor)
+ .isEnabled();
+ }
+
+ @Override
+ public boolean isCombinedToggleSensorPrivacyEnabled(int sensor) {
+ return isToggleSensorPrivacyEnabled(SOFTWARE, sensor) || isToggleSensorPrivacyEnabled(
+ HARDWARE, sensor);
+ }
+
+ private boolean isToggleSensorPrivacyEnabledInternal(int userId, int toggleType,
+ int sensor) {
+
+ return mSensorPrivacyStateController.getState(toggleType,
userId, sensor).isEnabled();
}
@Override
- public boolean supportsSensorToggle(int sensor) {
- if (sensor == MICROPHONE) {
- return mContext.getResources().getBoolean(R.bool.config_supportsMicToggle);
- } else if (sensor == CAMERA) {
- return mContext.getResources().getBoolean(R.bool.config_supportsCamToggle);
+ public boolean supportsSensorToggle(int toggleType, int sensor) {
+ if (toggleType == SOFTWARE) {
+ if (sensor == MICROPHONE) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsMicToggle);
+ } else if (sensor == CAMERA) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsCamToggle);
+ }
+ } else if (toggleType == SensorPrivacyManager.ToggleTypes.HARDWARE) {
+ if (sensor == MICROPHONE) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsHardwareMicToggle);
+ } else if (sensor == CAMERA) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsHardwareCamToggle);
+ }
}
- throw new IllegalArgumentException("Unable to find value " + sensor);
+ throw new IllegalArgumentException("Invalid arguments. "
+ + "toggleType=" + toggleType + " sensor=" + sensor);
}
/**
@@ -878,29 +916,13 @@
* Registers a listener to be notified when the sensor privacy state changes.
*/
@Override
- public void addIndividualSensorPrivacyListener(int userId, int sensor,
- ISensorPrivacyListener listener) {
+ public void addToggleSensorPrivacyListener(ISensorPrivacyListener listener) {
+ Log.d("evan", "trying to add from " + Binder.getCallingUid());
enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
- mHandler.addListener(userId, sensor, listener);
- }
-
-
- /**
- * Registers a listener to be notified when the sensor privacy state changes. The callback
- * can be called if the user changes and the setting is different between the transitioning
- * users.
- */
- @Override
- public void addUserGlobalIndividualSensorPrivacyListener(int sensor,
- ISensorPrivacyListener listener) {
- enforceObserveSensorPrivacyPermission();
- if (listener == null) {
- throw new IllegalArgumentException("listener cannot be null");
- }
- mHandler.addUserGlobalListener(sensor, listener);
+ mHandler.addToggleListener(listener);
}
/**
@@ -919,27 +941,16 @@
* Unregisters a listener from sensor privacy state change notifications.
*/
@Override
- public void removeIndividualSensorPrivacyListener(int sensor,
- ISensorPrivacyListener listener) {
+ public void removeToggleSensorPrivacyListener(ISensorPrivacyListener listener) {
enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
- mHandler.removeListener(sensor, listener);
+ mHandler.removeToggleListener(listener);
}
@Override
- public void removeUserGlobalIndividualSensorPrivacyListener(int sensor,
- ISensorPrivacyListener listener) {
- enforceObserveSensorPrivacyPermission();
- if (listener == null) {
- throw new IllegalArgumentException("listener cannot be null");
- }
- mHandler.removeUserGlobalListener(sensor, listener);
- }
-
- @Override
- public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
+ public void suppressToggleSensorPrivacyReminders(int userId, int sensor,
IBinder token, boolean suppress) {
enforceManageSensorPrivacyPermission();
if (userId == UserHandle.USER_CURRENT) {
@@ -976,7 +987,7 @@
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Can only be called by the system uid");
}
- if (!isIndividualSensorPrivacyEnabled(mCurrentUser, sensor)) {
+ if (!isCombinedToggleSensorPrivacyEnabled(sensor)) {
return;
}
enqueueSensorUseReminderDialogAsync(
@@ -984,23 +995,46 @@
}
private void userSwitching(int from, int to) {
- final boolean[] micState = new boolean[1];
- final boolean[] camState = new boolean[1];
- final boolean[] prevMicState = new boolean[1];
- final boolean[] prevCamState = new boolean[1];
+ final boolean[] micState = new boolean[2];
+ final boolean[] camState = new boolean[2];
+ final boolean[] prevMicState = new boolean[2];
+ final boolean[] prevCamState = new boolean[2];
+ final int swToggleIdx = 0;
+ final int hwToggleIdx = 1;
+ // Get SW toggles state
mSensorPrivacyStateController.atomic(() -> {
- prevMicState[0] = isIndividualSensorPrivacyEnabled(from, MICROPHONE);
- prevCamState[0] = isIndividualSensorPrivacyEnabled(from, CAMERA);
- micState[0] = isIndividualSensorPrivacyEnabled(to, MICROPHONE);
- camState[0] = isIndividualSensorPrivacyEnabled(to, CAMERA);
+ prevMicState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, SOFTWARE,
+ MICROPHONE);
+ prevCamState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, SOFTWARE,
+ CAMERA);
+ micState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, SOFTWARE,
+ MICROPHONE);
+ camState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, SOFTWARE, CAMERA);
});
- if (from == USER_NULL || prevMicState[0] != micState[0]) {
- mHandler.onUserGlobalSensorPrivacyChanged(MICROPHONE, micState[0]);
- setGlobalRestriction(MICROPHONE, micState[0]);
+ // Get HW toggles state
+ mSensorPrivacyStateController.atomic(() -> {
+ prevMicState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, HARDWARE,
+ MICROPHONE);
+ prevCamState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, HARDWARE,
+ CAMERA);
+ micState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, HARDWARE,
+ MICROPHONE);
+ camState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, HARDWARE, CAMERA);
+ });
+
+ if (from == USER_NULL || prevMicState[swToggleIdx] != micState[swToggleIdx]
+ || prevMicState[hwToggleIdx] != micState[hwToggleIdx]) {
+ mHandler.handleSensorPrivacyChanged(to, SOFTWARE, MICROPHONE,
+ micState[swToggleIdx]);
+ mHandler.handleSensorPrivacyChanged(to, HARDWARE, MICROPHONE,
+ micState[hwToggleIdx]);
+ setGlobalRestriction(MICROPHONE, micState[swToggleIdx] || micState[hwToggleIdx]);
}
- if (from == USER_NULL || prevCamState[0] != camState[0]) {
- mHandler.onUserGlobalSensorPrivacyChanged(CAMERA, camState[0]);
- setGlobalRestriction(CAMERA, camState[0]);
+ if (from == USER_NULL || prevCamState[swToggleIdx] != camState[swToggleIdx]
+ || prevCamState[hwToggleIdx] != camState[hwToggleIdx]) {
+ mHandler.handleSensorPrivacyChanged(to, SOFTWARE, CAMERA, camState[swToggleIdx]);
+ mHandler.handleSensorPrivacyChanged(to, HARDWARE, CAMERA, camState[hwToggleIdx]);
+ setGlobalRestriction(CAMERA, camState[swToggleIdx] || camState[hwToggleIdx]);
}
}
@@ -1153,7 +1187,7 @@
return -1;
}
- setIndividualSensorPrivacy(userId, SHELL, sensor, true);
+ setToggleSensorPrivacy(userId, SHELL, sensor, true);
}
break;
case "disable" : {
@@ -1163,7 +1197,7 @@
return -1;
}
- setIndividualSensorPrivacy(userId, SHELL, sensor, false);
+ setToggleSensorPrivacy(userId, SHELL, sensor, false);
}
break;
default:
@@ -1205,11 +1239,8 @@
private final RemoteCallbackList<ISensorPrivacyListener> mListeners =
new RemoteCallbackList<>();
@GuardedBy("mListenerLock")
- private final SparseArray<SparseArray<RemoteCallbackList<ISensorPrivacyListener>>>
- mIndividualSensorListeners = new SparseArray<>();
- @GuardedBy("mListenerLock")
- private final SparseArray<RemoteCallbackList<ISensorPrivacyListener>>
- mUserGlobalIndividualSensorListeners = new SparseArray<>();
+ private final RemoteCallbackList<ISensorPrivacyListener>
+ mToggleSensorListeners = new RemoteCallbackList<>();
@GuardedBy("mListenerLock")
private final ArrayMap<ISensorPrivacyListener, Pair<DeathRecipient, Integer>>
mDeathRecipients;
@@ -1221,12 +1252,6 @@
mContext = context;
}
- public void onUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
- sendMessage(PooledLambda.obtainMessage(
- SensorPrivacyHandler::handleUserGlobalSensorPrivacyChanged,
- this, sensor, enabled));
- }
-
public void addListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
if (mListeners.register(listener)) {
@@ -1235,34 +1260,9 @@
}
}
- public void addListener(int userId, int sensor, ISensorPrivacyListener listener) {
+ public void addToggleListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
- mIndividualSensorListeners.get(userId);
- if (listenersForUser == null) {
- listenersForUser = new SparseArray<>();
- mIndividualSensorListeners.put(userId, listenersForUser);
- }
- RemoteCallbackList<ISensorPrivacyListener> listeners = listenersForUser.get(sensor);
- if (listeners == null) {
- listeners = new RemoteCallbackList<>();
- listenersForUser.put(sensor, listeners);
- }
- if (listeners.register(listener)) {
- addDeathRecipient(listener);
- }
- }
- }
-
- public void addUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
- synchronized (mListenerLock) {
- RemoteCallbackList<ISensorPrivacyListener> listeners =
- mUserGlobalIndividualSensorListeners.get(sensor);
- if (listeners == null) {
- listeners = new RemoteCallbackList<>();
- mUserGlobalIndividualSensorListeners.put(sensor, listeners);
- }
- if (listeners.register(listener)) {
+ if (mToggleSensorListeners.register(listener)) {
addDeathRecipient(listener);
}
}
@@ -1276,28 +1276,10 @@
}
}
- public void removeListener(int sensor, ISensorPrivacyListener listener) {
+ public void removeToggleListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- for (int i = 0, numUsers = mIndividualSensorListeners.size(); i < numUsers; i++) {
- RemoteCallbackList callbacks =
- mIndividualSensorListeners.valueAt(i).get(sensor);
- if (callbacks != null) {
- if (callbacks.unregister(listener)) {
- removeDeathRecipient(listener);
- }
- }
- }
- }
- }
-
- public void removeUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
- synchronized (mListenerLock) {
- RemoteCallbackList callbacks =
- mUserGlobalIndividualSensorListeners.get(sensor);
- if (callbacks != null) {
- if (callbacks.unregister(listener)) {
- removeDeathRecipient(listener);
- }
+ if (mToggleSensorListeners.unregister(listener)) {
+ removeDeathRecipient(listener);
}
}
}
@@ -1307,7 +1289,7 @@
for (int i = 0; i < count; i++) {
ISensorPrivacyListener listener = mListeners.getBroadcastItem(i);
try {
- listener.onSensorPrivacyChanged(enabled);
+ listener.onSensorPrivacyChanged(-1, -1, enabled);
} catch (RemoteException e) {
Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
}
@@ -1315,62 +1297,34 @@
mListeners.finishBroadcast();
}
- public void handleSensorPrivacyChanged(int userId, int sensor, boolean enabled) {
- // TODO handle hardware
+ public void handleSensorPrivacyChanged(int userId, int toggleType, int sensor,
+ boolean enabled) {
mSensorPrivacyManagerInternal.dispatch(userId, sensor, enabled);
- SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
- mIndividualSensorListeners.get(userId);
if (userId == mCurrentUser) {
- mSensorPrivacyServiceImpl.setGlobalRestriction(sensor, enabled);
+ mSensorPrivacyServiceImpl.setGlobalRestriction(sensor,
+ mSensorPrivacyServiceImpl.isCombinedToggleSensorPrivacyEnabled(sensor));
}
- if (userId == mCurrentUser) {
- onUserGlobalSensorPrivacyChanged(sensor, enabled);
- }
-
- if (listenersForUser == null) {
+ if (userId != mCurrentUser) {
return;
}
- RemoteCallbackList<ISensorPrivacyListener> listeners = listenersForUser.get(sensor);
- if (listeners == null) {
- return;
- }
- try {
- final int count = listeners.beginBroadcast();
- for (int i = 0; i < count; i++) {
- ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
- try {
- listener.onSensorPrivacyChanged(enabled);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ synchronized (mListenerLock) {
+ try {
+ final int count = mToggleSensorListeners.beginBroadcast();
+ for (int i = 0; i < count; i++) {
+ ISensorPrivacyListener listener = mToggleSensorListeners.getBroadcastItem(
+ i);
+ try {
+ listener.onSensorPrivacyChanged(toggleType, sensor, enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught an exception notifying listener " + listener + ": ",
+ e);
+ }
}
+ } finally {
+ mToggleSensorListeners.finishBroadcast();
}
- } finally {
- listeners.finishBroadcast();
- }
- }
-
- public void handleUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
- RemoteCallbackList<ISensorPrivacyListener> listeners =
- mUserGlobalIndividualSensorListeners.get(sensor);
-
- if (listeners == null) {
- return;
- }
-
- try {
- final int count = listeners.beginBroadcast();
- for (int i = 0; i < count; i++) {
- ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
- try {
- listener.onSensorPrivacyChanged(enabled);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
- }
- }
- } finally {
- listeners.finishBroadcast();
}
}
@@ -1482,7 +1436,8 @@
@Override
public boolean isSensorPrivacyEnabled(int userId, int sensor) {
return SensorPrivacyService.this
- .mSensorPrivacyServiceImpl.isIndividualSensorPrivacyEnabled(userId, sensor);
+ .mSensorPrivacyServiceImpl.isToggleSensorPrivacyEnabledInternal(userId,
+ SOFTWARE, sensor);
}
@Override
@@ -1521,6 +1476,23 @@
sensorListeners.add(listener);
}
}
+
+ @Override
+ public void setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable) {
+ final SensorPrivacyServiceImpl sps =
+ SensorPrivacyService.this.mSensorPrivacyServiceImpl;
+
+ // Convert userId to actual user Id. mCurrentUser is USER_NULL if toggle state is set
+ // before onUserStarting.
+ userId = (userId == UserHandle.USER_CURRENT ? mCurrentUser : userId);
+ final int realUserId = (userId == UserHandle.USER_NULL ? mContext.getUserId() : userId);
+
+ sps.setToggleSensorPrivacyUnchecked(HARDWARE, realUserId, OTHER, sensor, enable);
+ // Also disable the SW toggle when disabling the HW toggle
+ if (!enable) {
+ sps.setToggleSensorPrivacyUnchecked(SOFTWARE, realUserId, OTHER, sensor, enable);
+ }
+ }
}
private class CallStateHelper {
@@ -1574,9 +1546,9 @@
if (!mIsInEmergencyCall) {
mIsInEmergencyCall = true;
if (mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE)) {
- mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- mCurrentUser, OTHER, MICROPHONE, false);
+ .isToggleSensorPrivacyEnabled(SOFTWARE, MICROPHONE)) {
+ mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked(
+ SOFTWARE, mCurrentUser, OTHER, MICROPHONE, false);
mMicUnmutedForEmergencyCall = true;
} else {
mMicUnmutedForEmergencyCall = false;
@@ -1601,8 +1573,8 @@
if (mIsInEmergencyCall) {
mIsInEmergencyCall = false;
if (mMicUnmutedForEmergencyCall) {
- mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- mCurrentUser, OTHER, MICROPHONE, true);
+ mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked(
+ SOFTWARE, mCurrentUser, OTHER, MICROPHONE, true);
mMicUnmutedForEmergencyCall = false;
}
}
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
index d1ea8e9..3dcb4cf 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
@@ -16,7 +16,6 @@
package com.android.server.sensorprivacy;
-import android.hardware.SensorPrivacyManager;
import android.os.Handler;
import com.android.internal.util.dump.DualDumpOutputStream;
@@ -49,10 +48,6 @@
@Override
SensorState getStateLocked(int toggleType, int userId, int sensor) {
- if (toggleType == SensorPrivacyManager.ToggleTypes.HARDWARE) {
- // Device doesn't support hardware state
- return getDefaultSensorState();
- }
SensorState sensorState = mPersistedState.getState(toggleType, userId, sensor);
if (sensorState != null) {
return new SensorState(sensorState);
@@ -67,12 +62,6 @@
@Override
void setStateLocked(int toggleType, int userId, int sensor, boolean enabled,
Handler callbackHandler, SetStateResultCallback callback) {
- if (toggleType != SensorPrivacyManager.ToggleTypes.SOFTWARE) {
- // Implementation only supports software switch
- callbackHandler.sendMessage(PooledLambda.obtainMessage(
- SetStateResultCallback::callback, callback, false));
- return;
- }
// Changing the SensorState's mEnabled updates the timestamp of its last change.
// A nonexistent state -> unmuted should not set the timestamp.
SensorState lastState = mPersistedState.getState(toggleType, userId, sensor);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index adee325..8ec0556 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -15,7 +15,6 @@
*/
package com.android.server.stats.pull;
-
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
@@ -74,6 +73,7 @@
import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManager.HistoricalUidOps;
import android.app.INotificationManager;
+import android.app.PendingIntentStats;
import android.app.ProcessMemoryState;
import android.app.RuntimeAppOpAccessMessage;
import android.app.StatsManager;
@@ -727,6 +727,8 @@
return pullAccessibilityFloatingMenuStatsLocked(atomTag, data);
case FrameworkStatsLog.MEDIA_CAPABILITIES:
return pullMediaCapabilitiesStats(atomTag, data);
+ case FrameworkStatsLog.PENDING_INTENTS_PER_PACKAGE:
+ return pullPendingIntentsPerPackage(atomTag, data);
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -923,6 +925,7 @@
registerAccessibilityShortcutStats();
registerAccessibilityFloatingMenuStats();
registerMediaCapabilitiesStats();
+ registerPendingIntentsPerPackagePuller();
}
private void initAndRegisterNetworkStatsPullers() {
@@ -1072,7 +1075,7 @@
private void registerWifiBytesTransfer() {
int tagId = FrameworkStatsLog.WIFI_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5})
+ .setAdditiveFields(new int[]{2, 3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1085,12 +1088,12 @@
@NonNull
private List<NetworkStatsExt> collectNetworkStatsSnapshotForAtom(int atomTag) {
List<NetworkStatsExt> ret = new ArrayList<>();
- switch(atomTag) {
+ switch (atomTag) {
case FrameworkStatsLog.WIFI_BYTES_TRANSFER: {
final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_WIFI);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
- new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
+ new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
}
break;
}
@@ -1098,7 +1101,7 @@
final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_WIFI);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
+ new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
}
break;
}
@@ -1107,7 +1110,7 @@
getUidNetworkStatsSnapshotForTransport(TRANSPORT_CELLULAR);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
- new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
}
break;
}
@@ -1116,7 +1119,7 @@
getUidNetworkStatsSnapshotForTransport(TRANSPORT_CELLULAR);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
}
break;
}
@@ -1125,11 +1128,11 @@
new NetworkTemplate.Builder(MATCH_WIFI).build(), /*includeTags=*/true);
final NetworkStats cellularStats = getUidNetworkStatsSnapshotForTemplate(
new NetworkTemplate.Builder(MATCH_MOBILE)
- .setMeteredness(METERED_YES).build(), /*includeTags=*/true);
+ .setMeteredness(METERED_YES).build(), /*includeTags=*/true);
if (wifiStats != null && cellularStats != null) {
final NetworkStats stats = wifiStats.add(cellularStats);
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
- new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR},
+ new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR},
/*slicedByFgbg=*/false, /*slicedByTag=*/true,
/*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
/*subInfo=*/null, OEM_MANAGED_ALL));
@@ -1196,7 +1199,8 @@
return StatsManager.PULL_SUCCESS;
}
- @NonNull private static NetworkStats removeEmptyEntries(NetworkStats stats) {
+ @NonNull
+ private static NetworkStats removeEmptyEntries(NetworkStats stats) {
NetworkStats ret = new NetworkStats(0, 1);
for (NetworkStats.Entry e : stats) {
if (e.getRxBytes() != 0 || e.getRxPackets() != 0 || e.getTxBytes() != 0
@@ -1278,13 +1282,14 @@
}
}
- @NonNull private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForOemManaged() {
+ @NonNull
+ private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForOemManaged() {
final List<Pair<Integer, Integer>> matchRulesAndTransports = List.of(
new Pair(MATCH_ETHERNET, TRANSPORT_ETHERNET),
new Pair(MATCH_MOBILE, TRANSPORT_CELLULAR),
new Pair(MATCH_WIFI, TRANSPORT_WIFI)
);
- final int[] oemManagedTypes = new int[] {OEM_MANAGED_PAID | OEM_MANAGED_PRIVATE,
+ final int[] oemManagedTypes = new int[]{OEM_MANAGED_PAID | OEM_MANAGED_PRIVATE,
OEM_MANAGED_PAID, OEM_MANAGED_PRIVATE};
final List<NetworkStatsExt> ret = new ArrayList<>();
@@ -1301,7 +1306,7 @@
final Integer transport = ruleAndTransport.second;
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[] {transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
+ new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
/*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
/*subInfo=*/null, oemManaged));
}
@@ -1314,7 +1319,8 @@
/**
* Create a snapshot of NetworkStats for a given transport.
*/
- @Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
+ @Nullable
+ private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
NetworkTemplate template = null;
switch (transport) {
case TRANSPORT_CELLULAR:
@@ -1336,7 +1342,8 @@
* Note that this should be only used to calculate diff since the snapshot might contains
* some traffic before boot.
*/
- @Nullable private NetworkStats getUidNetworkStatsSnapshotForTemplate(
+ @Nullable
+ private NetworkStats getUidNetworkStatsSnapshotForTemplate(
@NonNull NetworkTemplate template, boolean includeTags) {
final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
@@ -1354,8 +1361,8 @@
final android.app.usage.NetworkStats queryNonTaggedStats =
mNetworkStatsManager.querySummary(
- template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
- currentTimeInMillis);
+ template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
+ currentTimeInMillis);
final NetworkStats nonTaggedStats =
NetworkStatsUtils.fromPublicNetworkStats(queryNonTaggedStats);
@@ -1363,27 +1370,28 @@
final android.app.usage.NetworkStats queryTaggedStats =
mNetworkStatsManager.queryTaggedSummary(template,
- currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
- currentTimeInMillis);
+ currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
+ currentTimeInMillis);
final NetworkStats taggedStats =
NetworkStatsUtils.fromPublicNetworkStats(queryTaggedStats);
return nonTaggedStats.add(taggedStats);
}
- @NonNull private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForSub(
+ @NonNull
+ private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForSub(
@NonNull SubInfo subInfo) {
final List<NetworkStatsExt> ret = new ArrayList<>();
for (final int ratType : getAllCollapsedRatTypes()) {
final NetworkTemplate template =
new NetworkTemplate.Builder(MATCH_MOBILE)
- .setSubscriberIds(Set.of(subInfo.subscriberId))
- .setRatType(ratType)
- .setMeteredness(METERED_YES).build();
+ .setSubscriberIds(Set.of(subInfo.subscriberId))
+ .setRatType(ratType)
+ .setMeteredness(METERED_YES).build();
final NetworkStats stats =
getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
- new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
/*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
OEM_MANAGED_ALL));
}
@@ -1412,51 +1420,55 @@
return com.android.net.module.util.CollectionUtils.toIntArray(collapsedRatTypes);
}
- @NonNull private NetworkStats sliceNetworkStatsByUid(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByUid(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
- NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
- NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+ NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
+ NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
- @NonNull private NetworkStats sliceNetworkStatsByFgbg(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByFgbg(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL,
- entry.getSet(), NetworkStats.TAG_NONE,
- NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL,
+ entry.getSet(), NetworkStats.TAG_NONE,
+ NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
- @NonNull private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
- entry.getSet(), NetworkStats.TAG_NONE,
- NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+ entry.getSet(), NetworkStats.TAG_NONE,
+ NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
- @NonNull private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
- NetworkStats.SET_ALL, entry.getTag(),
- entry.getMetered(), NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+ NetworkStats.SET_ALL, entry.getTag(),
+ entry.getMetered(), NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
@@ -1472,17 +1484,18 @@
* get the state from entry to replace the default value.
* This is useful for slicing by particular dimensions. For example, if we wished
* to slice by uid and tag, we could write the following lambda:
- * (entry) -> {
- * return new NetworkStats.Entry(null, entry.getUid(),
- * NetworkStats.SET_ALL, entry.getTag(),
- * NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- * NetworkStats.DEFAULT_NETWORK_ALL,
- * entry.getRxBytes(), entry.getRxPackets(),
- * entry.getTxBytes(), entry.getTxPackets(), 0);
- * }
+ * (entry) -> {
+ * return new NetworkStats.Entry(null, entry.getUid(),
+ * NetworkStats.SET_ALL, entry.getTag(),
+ * NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ * NetworkStats.DEFAULT_NETWORK_ALL,
+ * entry.getRxBytes(), entry.getRxPackets(),
+ * entry.getTxBytes(), entry.getTxPackets(), 0);
+ * }
* @return new NeworkStats object appropriately sliced
*/
- @NonNull private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
+ @NonNull
+ private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
@NonNull Function<NetworkStats.Entry, NetworkStats.Entry> slicer) {
NetworkStats ret = new NetworkStats(0, 1);
for (NetworkStats.Entry e : stats) {
@@ -1494,7 +1507,7 @@
private void registerWifiBytesTransferBackground() {
int tagId = FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4, 5, 6})
+ .setAdditiveFields(new int[]{3, 4, 5, 6})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1507,7 +1520,7 @@
private void registerMobileBytesTransfer() {
int tagId = FrameworkStatsLog.MOBILE_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5})
+ .setAdditiveFields(new int[]{2, 3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1520,7 +1533,7 @@
private void registerMobileBytesTransferBackground() {
int tagId = FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4, 5, 6})
+ .setAdditiveFields(new int[]{3, 4, 5, 6})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1533,7 +1546,7 @@
private void registerBytesTransferByTagAndMetered() {
int tagId = FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {4, 5, 6, 7})
+ .setAdditiveFields(new int[]{4, 5, 6, 7})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1546,7 +1559,7 @@
private void registerDataUsageBytesTransfer() {
int tagId = FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5})
+ .setAdditiveFields(new int[]{2, 3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1559,7 +1572,7 @@
private void registerOemManagedBytesTransfer() {
int tagId = FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {5, 6, 7, 8})
+ .setAdditiveFields(new int[]{5, 6, 7, 8})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1572,7 +1585,7 @@
private void registerBluetoothBytesTransfer() {
int tagId = FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3})
+ .setAdditiveFields(new int[]{2, 3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1661,7 +1674,7 @@
if (KernelCpuBpfTracking.isSupported()) {
int tagId = FrameworkStatsLog.CPU_TIME_PER_CLUSTER_FREQ;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3})
+ .setAdditiveFields(new int[]{3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1691,7 +1704,7 @@
private void registerCpuTimePerUid() {
int tagId = FrameworkStatsLog.CPU_TIME_PER_UID;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3})
+ .setAdditiveFields(new int[]{2, 3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1716,7 +1729,7 @@
if (KernelCpuBpfTracking.isSupported() || KernelCpuBpfTracking.getClusters() > 0) {
int tagId = FrameworkStatsLog.CPU_CYCLES_PER_UID_CLUSTER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4, 5})
+ .setAdditiveFields(new int[]{3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1801,7 +1814,7 @@
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
int tagId = FrameworkStatsLog.CPU_TIME_PER_UID_FREQ;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3})
+ .setAdditiveFields(new int[]{3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1855,7 +1868,7 @@
if (KernelCpuBpfTracking.isSupported()) {
int tagId = FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4})
+ .setAdditiveFields(new int[]{3, 4})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1918,7 +1931,7 @@
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
int tagId = FrameworkStatsLog.CPU_ACTIVE_TIME;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2})
+ .setAdditiveFields(new int[]{2})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1940,7 +1953,7 @@
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
int tagId = FrameworkStatsLog.CPU_CLUSTER_TIME;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3})
+ .setAdditiveFields(new int[]{3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2127,7 +2140,7 @@
private void registerProcessMemoryState() {
int tagId = FrameworkStatsLog.PROCESS_MEMORY_STATE;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {4, 5, 6, 7, 8})
+ .setAdditiveFields(new int[]{4, 5, 6, 7, 8})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2485,7 +2498,7 @@
private void registerBinderCallsStats() {
int tagId = FrameworkStatsLog.BINDER_CALLS;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {4, 5, 6, 8, 12})
+ .setAdditiveFields(new int[]{4, 5, 6, 8, 12})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2547,7 +2560,7 @@
private void registerLooperStats() {
int tagId = FrameworkStatsLog.LOOPER_STATS;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {5, 6, 7, 8, 9})
+ .setAdditiveFields(new int[]{5, 6, 7, 8, 9})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2922,7 +2935,7 @@
private void registerDiskIO() {
int tagId = FrameworkStatsLog.DISK_IO;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
+ .setAdditiveFields(new int[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
.setCoolDownMillis(3 * MILLIS_PER_SEC)
.build();
mStatsManager.setPullAtomCallback(
@@ -2994,7 +3007,7 @@
private void registerCpuTimePerThreadFreq() {
int tagId = FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {7, 9, 11, 13, 15, 17, 19, 21})
+ .setAdditiveFields(new int[]{7, 9, 11, 13, 15, 17, 19, 21})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -3092,7 +3105,7 @@
private void registerDebugElapsedClock() {
int tagId = FrameworkStatsLog.DEBUG_ELAPSED_CLOCK;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {1, 2, 3, 4})
+ .setAdditiveFields(new int[]{1, 2, 3, 4})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -3127,7 +3140,7 @@
private void registerDebugFailingElapsedClock() {
int tagId = FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {1, 2, 3, 4})
+ .setAdditiveFields(new int[]{1, 2, 3, 4})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -3559,23 +3572,23 @@
int userId = users.get(userNum).getUserHandle().getIdentifier();
int unlockKeyguardEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, userId);
int unlockDismissesKeyguard = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 1, userId);
int unlockAttentionRequired = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 0, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 0, userId);
int unlockAppEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, userId);
int unlockAlwaysRequireConfirmation = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, userId);
int unlockDiversityRequired = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, userId);
pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
unlockKeyguardEnabled != 0, unlockDismissesKeyguard != 0,
@@ -4481,7 +4494,7 @@
opacity));
}
}
- } catch (RuntimeException e) {
+ } catch (RuntimeException e) {
Slog.e(TAG, "pulling accessibility floating menu stats failed at getUsers", e);
return StatsManager.PULL_SKIP;
} finally {
@@ -4505,7 +4518,7 @@
byte[] sinkSurroundEncodings = toBytes(audioManager.getReportedSurroundFormats());
List<Integer> disabledSurroundEncodingsList = new ArrayList<>();
List<Integer> enabledSurroundEncodingsList = new ArrayList<>();
- for (int surroundEncoding: surroundEncodingsMap.keySet()) {
+ for (int surroundEncoding : surroundEncodingsMap.keySet()) {
if (!surroundEncodingsMap.get(surroundEncoding)) {
disabledSurroundEncodingsList.add(surroundEncoding);
} else {
@@ -4574,6 +4587,26 @@
return StatsManager.PULL_SUCCESS;
}
+ private void registerPendingIntentsPerPackagePuller() {
+ int tagId = FrameworkStatsLog.PENDING_INTENTS_PER_PACKAGE;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ mStatsCallbackImpl
+ );
+ }
+
+ private int pullPendingIntentsPerPackage(int atomTag, List<StatsEvent> pulledData) {
+ List<PendingIntentStats> pendingIntentStats =
+ LocalServices.getService(ActivityManagerInternal.class).getPendingIntentStats();
+ for (PendingIntentStats stats : pendingIntentStats) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, stats.uid, stats.count, stats.sizeKb));
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
private byte[] toBytes(List<Integer> audioEncodings) {
ProtoOutputStream protoOutputStream = new ProtoOutputStream();
for (int audioEncoding : audioEncodings) {
@@ -4655,8 +4688,8 @@
* string list.
*
* @param semicolonList colon-separated string, it should be
- * {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or
- * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
+ * {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or
+ * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
* @return The number of accessibility services
*/
private int countAccessibilityServices(String semicolonList) {
@@ -4778,5 +4811,4 @@
}
}
}
-
}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index a17e792..30e2617 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -146,7 +146,7 @@
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED);
- mContext.registerReceiver(this, filter, null, mHandler);
+ mContext.registerReceiver(this, filter, null, mHandler, Context.RECEIVER_NOT_EXPORTED);
mSubscriptionManager.addOnSubscriptionsChangedListener(
executor, mSubscriptionChangedListener);
mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8d99f07..1741d0f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1468,7 +1468,7 @@
a.packageName = process.mInfo.packageName;
a.applicationInfo = process.mInfo;
- a.processName = process.mInfo.processName;
+ a.processName = process.mName;
a.uiOptions = process.mInfo.uiOptions;
a.taskAffinity = "android:" + a.packageName + "/dream";
@@ -6099,7 +6099,8 @@
public boolean onForceStopPackage(String packageName, boolean doit, boolean evenPersistent,
int userId) {
synchronized (mGlobalLock) {
-
+ // In case if setWindowManager hasn't been called yet when booting.
+ if (mRootWindowContainer == null) return false;
return mRootWindowContainer.finishDisabledPackageActivities(packageName,
null /* filterByClasses */, doit, evenPersistent, userId,
// Only remove the activities without process because the activities with
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index e26748c..33b807b 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -53,7 +53,11 @@
* Returns true if the back predictability feature is enabled
*/
static boolean isEnabled() {
- return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
+ }
+
+ static boolean isScreenshotEnabled() {
+ return false;
}
/**
@@ -101,6 +105,13 @@
synchronized (task.mWmService.mGlobalLock) {
activityRecord = task.topRunningActivity();
+
+ if(!activityRecord.info.applicationInfo.isOnBackInvokedCallbackEnabled()) {
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Activity %s: enableOnBackInvokedCallback=false."
+ + " Returning null BackNavigationInfo.", activityRecord.getName());
+ return null;
+ }
+
removedWindowContainer = activityRecord;
taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
WindowState window = task.getWindow(WindowState::isFocused);
diff --git a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
index d9dc9aa..c099628 100644
--- a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
+++ b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
@@ -19,51 +19,51 @@
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
import java.util.HashMap;
final class TaskFpsCallbackController {
private final Context mContext;
- private final HashMap<IOnFpsCallbackListener, Long> mTaskFpsCallbackListeners;
- private final HashMap<IOnFpsCallbackListener, IBinder.DeathRecipient> mDeathRecipients;
+ private final HashMap<ITaskFpsCallback, Long> mTaskFpsCallbacks;
+ private final HashMap<ITaskFpsCallback, IBinder.DeathRecipient> mDeathRecipients;
TaskFpsCallbackController(Context context) {
mContext = context;
- mTaskFpsCallbackListeners = new HashMap<>();
+ mTaskFpsCallbacks = new HashMap<>();
mDeathRecipients = new HashMap<>();
}
- void registerCallback(int taskId, IOnFpsCallbackListener listener) {
- if (mTaskFpsCallbackListeners.containsKey(listener)) {
+ void registerListener(int taskId, ITaskFpsCallback callback) {
+ if (mTaskFpsCallbacks.containsKey(callback)) {
return;
}
- final long nativeListener = nativeRegister(listener, taskId);
- mTaskFpsCallbackListeners.put(listener, nativeListener);
+ final long nativeListener = nativeRegister(callback, taskId);
+ mTaskFpsCallbacks.put(callback, nativeListener);
- final IBinder.DeathRecipient deathRecipient = () -> unregisterCallback(listener);
+ final IBinder.DeathRecipient deathRecipient = () -> unregisterListener(callback);
try {
- listener.asBinder().linkToDeath(deathRecipient, 0);
- mDeathRecipients.put(listener, deathRecipient);
+ callback.asBinder().linkToDeath(deathRecipient, 0);
+ mDeathRecipients.put(callback, deathRecipient);
} catch (RemoteException e) {
// ignore
}
}
- void unregisterCallback(IOnFpsCallbackListener listener) {
- if (!mTaskFpsCallbackListeners.containsKey(listener)) {
+ void unregisterListener(ITaskFpsCallback callback) {
+ if (!mTaskFpsCallbacks.containsKey(callback)) {
return;
}
- listener.asBinder().unlinkToDeath(mDeathRecipients.get(listener), 0);
- mDeathRecipients.remove(listener);
+ callback.asBinder().unlinkToDeath(mDeathRecipients.get(callback), 0);
+ mDeathRecipients.remove(callback);
- nativeUnregister(mTaskFpsCallbackListeners.get(listener));
- mTaskFpsCallbackListeners.remove(listener);
+ nativeUnregister(mTaskFpsCallbacks.get(callback));
+ mTaskFpsCallbacks.remove(callback);
}
- private static native long nativeRegister(IOnFpsCallbackListener listener, int taskId);
+ private static native long nativeRegister(ITaskFpsCallback callback, int taskId);
private static native void nativeUnregister(long ptr);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index c880aba..dd1f29e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -876,11 +876,17 @@
if (!adjacentTaskFragments.isEmpty() && !gotTranslucentAdjacent) {
// The z-order of this TaskFragment is in middle of two adjacent TaskFragments
// and it cannot be visible if the TaskFragment on top is not translucent and
- // is fully occluding this one.
+ // is occluding this one.
+ mTmpRect.set(getBounds());
for (int j = adjacentTaskFragments.size() - 1; j >= 0; --j) {
final TaskFragment taskFragment = adjacentTaskFragments.get(j);
- if (!taskFragment.isTranslucent(starting)
- && taskFragment.getBounds().contains(this.getBounds())) {
+ final TaskFragment adjacentTaskFragment =
+ taskFragment.mAdjacentTaskFragment;
+ if (adjacentTaskFragment == this) {
+ continue;
+ }
+ if (mTmpRect.intersect(taskFragment.getBounds())
+ || mTmpRect.intersect(adjacentTaskFragment.getBounds())) {
return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
}
}
@@ -1695,7 +1701,7 @@
if (isAddingActivity && task != null) {
// TODO(b/207481538): temporary per-activity screenshoting
- if (r != null && BackNavigationController.isEnabled()) {
+ if (r != null && BackNavigationController.isScreenshotEnabled()) {
ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
r.mActivityComponent.flattenToString());
Rect outBounds = r.getBounds();
@@ -2298,7 +2304,7 @@
void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
super.removeChild(child);
- if (BackNavigationController.isEnabled()) {
+ if (BackNavigationController.isScreenshotEnabled()) {
//TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
// implemented
ActivityRecord r = child.asActivityRecord();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index af12c0b..48fab47 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -281,7 +281,7 @@
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.window.ClientWindowFrames;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
import android.window.TaskSnapshot;
import com.android.internal.R;
@@ -419,7 +419,7 @@
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
@@ -8870,7 +8870,7 @@
@Override
@RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
public void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
- IOnFpsCallbackListener listener) {
+ ITaskFpsCallback callback) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
!= PackageManager.PERMISSION_GRANTED) {
final int pid = Binder.getCallingPid();
@@ -8882,12 +8882,12 @@
throw new IllegalArgumentException("no task with taskId: " + taskId);
}
- mTaskFpsCallbackController.registerCallback(taskId, listener);
+ mTaskFpsCallbackController.registerListener(taskId, callback);
}
@Override
@RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
- public void unregisterTaskFpsCallback(IOnFpsCallbackListener listener) {
+ public void unregisterTaskFpsCallback(ITaskFpsCallback callback) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
!= PackageManager.PERMISSION_GRANTED) {
final int pid = Binder.getCallingPid();
@@ -8895,7 +8895,7 @@
+ ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER);
}
- mTaskFpsCallbackController.unregisterCallback(listener);
+ mTaskFpsCallbackController.unregisterListener(callback);
}
@Override
diff --git a/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
index 0202306..0a60e0d 100644
--- a/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
+++ b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
@@ -99,7 +99,7 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- {"nativeRegister", "(Landroid/window/IOnFpsCallbackListener;I)J", (void*)nativeRegister},
+ {"nativeRegister", "(Landroid/window/ITaskFpsCallback;I)J", (void*)nativeRegister},
{"nativeUnregister", "(J)V", (void*)nativeUnregister}};
} // namespace
@@ -113,7 +113,7 @@
gCallbackClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
gCallbackClassInfo.mDispatchOnFpsReported =
env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
- "(Landroid/window/IOnFpsCallbackListener;F)V");
+ "(Landroid/window/ITaskFpsCallback;F)V");
return 0;
}
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index be0ddc1..5b4febd 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -170,14 +170,6 @@
</xs:restriction>
</xs:simpleType>
- <!-- Maps to DisplayDeviceConfig.INTERPOLATION_* values. -->
- <xs:simpleType name="interpolation">
- <xs:restriction base="xs:string">
- <xs:enumeration value="default"/>
- <xs:enumeration value="linear"/>
- </xs:restriction>
- </xs:simpleType>
-
<xs:complexType name="thermalThrottling">
<xs:complexType>
<xs:element type="brightnessThrottlingMap" name="brightnessThrottlingMap">
@@ -216,7 +208,8 @@
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
- <xs:attribute name="interpolation" type="interpolation" use="optional"/>
+ <!-- valid value of interpolation if specified: linear -->
+ <xs:attribute name="interpolation" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="point">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 2890d68..ba83c9f 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -108,17 +108,11 @@
method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
}
- public enum Interpolation {
- method public String getRawName();
- enum_constant public static final com.android.server.display.config.Interpolation _default;
- enum_constant public static final com.android.server.display.config.Interpolation linear;
- }
-
public class NitsMap {
ctor public NitsMap();
- method public com.android.server.display.config.Interpolation getInterpolation();
+ method public String getInterpolation();
method @NonNull public final java.util.List<com.android.server.display.config.Point> getPoint();
- method public void setInterpolation(com.android.server.display.config.Interpolation);
+ method public void setInterpolation(String);
}
public class Point {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5c3721d..2e801ab 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -417,6 +417,8 @@
private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
private static final String SAFETY_CENTER_SERVICE_CLASS =
"com.android.safetycenter.SafetyCenterService";
+ private static final String BLUETOOTH_SERVICE_CLASS =
+ "com.android.server.bluetooth.BluetoothService";
private static final String SUPPLEMENTALPROCESS_SERVICE_CLASS =
"com.android.server.supplementalprocess.SupplementalProcessManagerService$Lifecycle";
@@ -1624,7 +1626,7 @@
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
} else {
t.traceBegin("StartBluetoothService");
- mSystemServiceManager.startService(BluetoothService.class);
+ mSystemServiceManager.startService(BLUETOOTH_SERVICE_CLASS);
t.traceEnd();
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 11300ce..cd2d0fc 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -509,7 +509,12 @@
ParsingPackage::setInheritKeyStoreKeys,
true
),
- getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT"))
+ getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
+ getSetByValue(
+ AndroidPackage::isOnBackInvokedCallbackEnabled,
+ ParsingPackage::setOnBackInvokedCallbackEnabled,
+ true
+ )
)
override fun initialObject() = PackageImpl.forParsing(
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index 877538c..782d519 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -20,7 +20,12 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+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.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -42,6 +47,7 @@
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
@@ -51,6 +57,7 @@
@SmallTest
@Presubmit
public class AnrHelperTest {
+ private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
private AnrHelper mAnrHelper;
private ProcessRecord mAnrApp;
@@ -106,8 +113,42 @@
mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation);
- verify(mAnrApp.mErrorState, timeout(TimeUnit.SECONDS.toMillis(5))).appNotResponding(
+ verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
eq(parentProcess), eq(aboveSystem), eq(annotation), eq(false) /* onlyDumpSelf */);
}
+
+ @Test
+ public void testSkipDuplicatedAnr() {
+ final CountDownLatch consumerLatch = new CountDownLatch(1);
+ final CountDownLatch processingLatch = new CountDownLatch(1);
+ doAnswer(invocation -> {
+ consumerLatch.countDown();
+ // Simulate that it is dumping to block the consumer thread.
+ processingLatch.await();
+ return null;
+ }).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(),
+ anyBoolean(), anyString(), anyBoolean());
+ final ApplicationInfo appInfo = new ApplicationInfo();
+ mAnrApp.mPid = 12345;
+ final Runnable reportAnr = () -> mAnrHelper.appNotResponding(mAnrApp,
+ "activityShortComponentName", appInfo, "parentShortComponentName",
+ null /* parentProcess */, false /* aboveSystem */, "annotation");
+ reportAnr.run();
+ // This should be skipped because the pid is pending in queue.
+ reportAnr.run();
+ // The first reported ANR must be processed.
+ try {
+ assertTrue(consumerLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException ignored) {
+ }
+ // This should be skipped because the pid is under processing.
+ reportAnr.run();
+
+ // Assume that the first one finishes after all incoming ANRs.
+ processingLatch.countDown();
+ // There is only one ANR reported.
+ verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding(
+ anyString(), any(), any(), any(), anyBoolean(), anyString(), anyBoolean());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index a12bc3b..de81d6b 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -28,6 +28,8 @@
import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
+import static com.android.server.UiModeManagerService.SUPPORTED_NIGHT_MODE_CUSTOM_TYPES;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.TestCase.assertFalse;
@@ -295,6 +297,24 @@
}
@Test
+ public void setNightModeCustomType_customTypeUnknown_shouldThrow() throws RemoteException {
+ assertThrows(IllegalArgumentException.class,
+ () -> mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN));
+ }
+
+ @Test
+ public void setNightModeCustomType_customTypeUnsupported_shouldThrow() throws RemoteException {
+ assertThrows(IllegalArgumentException.class,
+ () -> {
+ int maxSupportedCustomType = 0;
+ for (Integer supportedType : SUPPORTED_NIGHT_MODE_CUSTOM_TYPES) {
+ maxSupportedCustomType = Math.max(maxSupportedCustomType, supportedType);
+ }
+ mService.setNightModeCustomType(maxSupportedCustomType + 1);
+ });
+ }
+
+ @Test
public void setNightModeCustomType_bedtime_shouldHaveNoScreenOffRegistered()
throws RemoteException {
try {
@@ -777,7 +797,6 @@
}
-
@Test
public void customTime_darkThemeOn_beforeStartEnd() throws RemoteException {
LocalTime now = LocalTime.now();
@@ -1220,6 +1239,35 @@
verify(listener, never()).onProjectionStateChanged(anyInt(), any());
}
+ @Test
+ public void enableCarMode_failsForBogusPackageName() throws Exception {
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID + 1);
+
+ assertThrows(SecurityException.class, () -> mService.enableCarMode(0, 0, PACKAGE_NAME));
+ assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
+ }
+
+ @Test
+ public void disableCarMode_failsForBogusPackageName() throws Exception {
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
+ mService.enableCarMode(0, 0, PACKAGE_NAME);
+ assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID + 1);
+
+ assertThrows(SecurityException.class,
+ () -> mService.disableCarModeByCallingPackage(0, PACKAGE_NAME));
+ assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
+
+ // Clean up
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
+ mService.disableCarModeByCallingPackage(0, PACKAGE_NAME);
+ assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
+ }
+
private void requestAllPossibleProjectionTypes() throws RemoteException {
for (int i = 0; i < Integer.SIZE; ++i) {
mService.requestProjection(mBinder, 1 << i, PACKAGE_NAME);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index 1126e1e..4b6183d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -15,16 +15,22 @@
*/
package com.android.server.notification;
+import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
+import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
import android.app.Notification;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -35,6 +41,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -51,6 +58,8 @@
private static final int SIZE = 5;
private NotificationManagerService.Archive mArchive;
+ @Mock
+ private UserManager mUm;
@Before
public void setUp() {
@@ -59,6 +68,9 @@
mArchive = new NotificationManagerService.Archive(SIZE);
mArchive.updateHistoryEnabled(USER_SYSTEM, true);
mArchive.updateHistoryEnabled(USER_CURRENT, true);
+
+ when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(
+ new int[] {USER_CURRENT, USER_SYSTEM});
}
private StatusBarNotification getNotification(String pkg, int id, UserHandle user) {
@@ -70,7 +82,6 @@
pkg, pkg, id, null, 0, 0, n, user, null, System.currentTimeMillis());
}
-
@Test
public void testRecordAndRead() {
List<String> expected = new ArrayList<>();
@@ -81,7 +92,7 @@
mArchive.record(sbn, REASON_CANCEL);
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -89,6 +100,22 @@
}
@Test
+ public void testCrossUser() {
+ mArchive.record(getNotification("pkg", 1, UserHandle.of(USER_SYSTEM)), REASON_CANCEL);
+ mArchive.record(getNotification("pkg", 2, UserHandle.of(USER_CURRENT)), REASON_CANCEL);
+ mArchive.record(getNotification("pkg", 3, UserHandle.of(USER_ALL)), REASON_CANCEL);
+ mArchive.record(getNotification("pkg", 4, UserHandle.of(USER_NULL)), REASON_CANCEL);
+
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
+ assertThat(actual).hasSize(3);
+ for (StatusBarNotification sbn : actual) {
+ if (sbn.getUserId() == USER_NULL) {
+ fail("leaked notification from wrong user");
+ }
+ }
+ }
+
+ @Test
public void testRecordAndRead_overLimit() {
List<String> expected = new ArrayList<>();
for (int i = 0; i < (SIZE * 2); i++) {
@@ -99,7 +126,8 @@
}
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray((SIZE * 2), true));
+ List<StatusBarNotification> actual = Arrays.asList(
+ mArchive.getArray(mUm, (SIZE * 2), true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -119,7 +147,7 @@
}
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -140,7 +168,7 @@
}
mArchive.updateHistoryEnabled(USER_CURRENT, false);
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -165,7 +193,7 @@
}
mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test0");
mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + (SIZE - 2));
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -215,7 +243,7 @@
fail("Concurrent modification exception");
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index dfcab2b..018a916 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -430,6 +430,7 @@
when(mPermissionPolicyInternal.canShowPermissionPromptForTask(
any(ActivityManager.RecentTaskInfo.class))).thenReturn(false);
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
+ when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
ActivityManager.AppTask task = mock(ActivityManager.AppTask.class);
List<ActivityManager.AppTask> taskList = new ArrayList<>();
@@ -7643,8 +7644,9 @@
waitForIdle();
// A notification exists for the given record
- StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
- assertEquals(1, notifsBefore.length);
+ List<StatusBarNotification> notifsBefore =
+ mBinderService.getAppActiveNotifications(PKG, nr.getSbn().getUserId()).getList();
+ assertEquals(1, notifsBefore.size());
reset(mPackageManager);
@@ -9131,4 +9133,33 @@
// make sure we don't bother if the migration is not enabled
assertThat(mService.getAllUsersNotificationPermissions()).isNull();
}
+
+ @Test
+ public void testGetActiveNotification_filtersUsers() throws Exception {
+ when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0, 10});
+
+ NotificationRecord nr0 =
+ generateNotificationRecord(mTestNotificationChannel, 0);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId());
+
+ NotificationRecord nr10 =
+ generateNotificationRecord(mTestNotificationChannel, 10);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag10",
+ nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId());
+
+ NotificationRecord nr11 =
+ generateNotificationRecord(mTestNotificationChannel, 11);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag11",
+ nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId());
+ waitForIdle();
+
+ StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+ assertEquals(2, notifs.length);
+ for (StatusBarNotification sbn : notifs) {
+ if (sbn.getUserId() == 11) {
+ fail("leaked data across users");
+ }
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index d922f40..5a6ca6d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -293,6 +293,7 @@
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
+ when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 3d89805..c21a5b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.window.BackNavigationInfo.typeToString;
@@ -117,6 +118,9 @@
private Task createTopTaskWithActivity() {
Task task = createTask(mDefaultDisplay);
ActivityRecord record = createActivityRecord(task);
+ // enable OnBackInvokedCallbacks
+ record.info.applicationInfo.privateFlagsExt |=
+ PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
createWindow(null, FIRST_APPLICATION_WINDOW, record, "window");
when(record.mSurfaceControl.isValid()).thenReturn(true);
mAtm.setFocusedTask(task.mTaskId, record);
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 9f4fee8..364d592 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -43,6 +44,7 @@
import android.view.translation.TranslationCapability;
import android.view.translation.TranslationContext;
import android.view.translation.TranslationSpec;
+import android.view.translation.UiTranslationController;
import android.view.translation.UiTranslationManager.UiTranslationState;
import android.view.translation.UiTranslationSpec;
@@ -253,7 +255,10 @@
try (TransferPipe tp = new TransferPipe()) {
activityTokens.getApplicationThread().dumpActivity(tp.getWriteFd(),
activityTokens.getActivityToken(), prefix,
- new String[]{"--translation"});
+ new String[] {
+ Activity.DUMP_ARG_DUMP_DUMPABLE,
+ UiTranslationController.DUMPABLE_NAME
+ });
tp.go(fd);
} catch (IOException e) {
pw.println(prefix + "Failure while dumping the activity: " + e);
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index d0825ba..f07a406 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -384,7 +384,7 @@
}
/**
- * Enables USB data when disabled due to {@link UsbPortStatus#USB_DATA_STATUS_DISABLED_DOCK}
+ * Enables USB data when disabled due to {@link UsbPortStatus#DATA_STATUS_DISABLED_DOCK}
*/
public void enableUsbDataWhileDocked(@NonNull String portId, long transactionId,
IUsbOperationInternal callback, IndentingPrintWriter pw) {
@@ -844,7 +844,7 @@
portInfo.contaminantDetectionStatus,
portInfo.usbDataStatus,
portInfo.powerTransferLimited,
- portInfo.powerBrickStatus, pw);
+ portInfo.powerBrickConnectionStatus, pw);
}
} else {
for (RawPortInfo currentPortInfo : newPortInfo) {
@@ -859,7 +859,7 @@
currentPortInfo.contaminantDetectionStatus,
currentPortInfo.usbDataStatus,
currentPortInfo.powerTransferLimited,
- currentPortInfo.powerBrickStatus, pw);
+ currentPortInfo.powerBrickConnectionStatus, pw);
}
}
@@ -895,9 +895,9 @@
int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus,
- int[] usbDataStatus,
+ int usbDataStatus,
boolean powerTransferLimited,
- int powerBrickStatus,
+ int powerBrickConnectionStatus,
IndentingPrintWriter pw) {
// Only allow mode switch capability for dual role ports.
// Validate that the current mode matches the supported modes we expect.
@@ -957,7 +957,7 @@
currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus);
+ powerTransferLimited, powerBrickConnectionStatus);
mPorts.put(portId, portInfo);
} else {
// Validate that ports aren't changing definition out from under us.
@@ -995,7 +995,7 @@
currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus)) {
+ powerTransferLimited, powerBrickConnectionStatus)) {
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
} else {
portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1222,7 +1222,7 @@
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED,
- new int[]{UsbPortStatus.USB_DATA_STATUS_UNKNOWN}, false,
+ UsbPortStatus.DATA_STATUS_UNKNOWN, false,
UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN);
dispositionChanged = true;
}
@@ -1238,31 +1238,12 @@
return dispositionChanged;
}
- private boolean dataStatusEquals(int[] dataStatusL, int[] dataStatusR) {
- if (dataStatusL == null && dataStatusR == null) {
- return true;
- }
- if ((dataStatusL == null && dataStatusR != null)
- || (dataStatusL != null && dataStatusR == null)) {
- return false;
- }
- if (dataStatusL.length != dataStatusR.length) {
- return false;
- }
- for (int i = 0; i < dataStatusL.length; i++) {
- if (dataStatusL[i] != dataStatusR[i]) {
- return false;
- }
- }
- return true;
- }
-
public boolean setStatus(int currentMode, boolean canChangeMode,
int currentPowerRole, boolean canChangePowerRole,
int currentDataRole, boolean canChangeDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus,
- int contaminantDetectionStatus, int[] usbDataStatus,
- boolean powerTransferLimited, int powerBrickStatus) {
+ int contaminantDetectionStatus, int usbDataStatus,
+ boolean powerTransferLimited, int powerBrickConnectionStatus) {
boolean dispositionChanged = false;
mCanChangeMode = canChangeMode;
@@ -1278,15 +1259,16 @@
!= contaminantProtectionStatus
|| mUsbPortStatus.getContaminantDetectionStatus()
!= contaminantDetectionStatus
- || !dataStatusEquals(mUsbPortStatus.getUsbDataStatus(), usbDataStatus)
+ || mUsbPortStatus.getUsbDataStatus()
+ != usbDataStatus
|| mUsbPortStatus.isPowerTransferLimited()
!= powerTransferLimited
- || mUsbPortStatus.getPowerBrickStatus()
- != powerBrickStatus) {
+ || mUsbPortStatus.getPowerBrickConnectionStatus()
+ != powerBrickConnectionStatus) {
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus);
+ powerTransferLimited, powerBrickConnectionStatus);
dispositionChanged = true;
}
diff --git a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
index dd25620..128a051 100644
--- a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
+++ b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
@@ -37,9 +37,9 @@
public int contaminantProtectionStatus;
public boolean supportsEnableContaminantPresenceDetection;
public int contaminantDetectionStatus;
- public int[] usbDataStatus;
+ public int usbDataStatus;
public boolean powerTransferLimited;
- public int powerBrickStatus;
+ public int powerBrickConnectionStatus;
public RawPortInfo(String portId, int supportedModes) {
this.portId = portId;
@@ -49,9 +49,10 @@
this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
this.supportsEnableContaminantPresenceDetection = false;
this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
- this.usbDataStatus[0] = UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
+ this.usbDataStatus = UsbPortStatus.DATA_STATUS_UNKNOWN;
+
this.powerTransferLimited = false;
- this.powerBrickStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
+ this.powerBrickConnectionStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
}
public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
@@ -62,9 +63,9 @@
int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus,
- int[] usbDataStatus,
+ int usbDataStatus,
boolean powerTransferLimited,
- int powerBrickStatus) {
+ int powerBrickConnectionStatus) {
this.portId = portId;
this.supportedModes = supportedModes;
this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
@@ -82,7 +83,7 @@
this.contaminantDetectionStatus = contaminantDetectionStatus;
this.usbDataStatus = usbDataStatus;
this.powerTransferLimited = powerTransferLimited;
- this.powerBrickStatus = powerBrickStatus;
+ this.powerBrickConnectionStatus = powerBrickConnectionStatus;
}
@Override
@@ -105,10 +106,9 @@
dest.writeInt(contaminantProtectionStatus);
dest.writeBoolean(supportsEnableContaminantPresenceDetection);
dest.writeInt(contaminantDetectionStatus);
- dest.writeInt(usbDataStatus.length);
- dest.writeIntArray(usbDataStatus);
+ dest.writeInt(usbDataStatus);
dest.writeBoolean(powerTransferLimited);
- dest.writeInt(powerBrickStatus);
+ dest.writeInt(powerBrickConnectionStatus);
}
public static final Parcelable.Creator<RawPortInfo> CREATOR =
@@ -128,10 +128,9 @@
int contaminantProtectionStatus = in.readInt();
boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
int contaminantDetectionStatus = in.readInt();
- int[] usbDataStatus = new int[in.readInt()];
- in.readIntArray(usbDataStatus);
+ int usbDataStatus = in.readInt();
boolean powerTransferLimited = in.readBoolean();
- int powerBrickStatus = in.readInt();
+ int powerBrickConnectionStatus = in.readInt();
return new RawPortInfo(id, supportedModes,
supportedContaminantProtectionModes, currentMode, canChangeMode,
currentPowerRole, canChangePowerRole,
@@ -140,7 +139,7 @@
contaminantProtectionStatus,
supportsEnableContaminantPresenceDetection,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus);
+ powerTransferLimited, powerBrickConnectionStatus);
}
@Override
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index f468db3..1db018e 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -73,6 +73,42 @@
private boolean mSystemReady;
private long mTransactionId;
+ /**
+ * USB data status is not known.
+ */
+ public static final int USB_DATA_STATUS_UNKNOWN = 0;
+
+ /**
+ * USB data is enabled.
+ */
+ public static final int USB_DATA_STATUS_ENABLED = 1;
+
+ /**
+ * USB data is disabled as the port is too hot.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2;
+
+ /**
+ * USB data is disabled due to contaminated port.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3;
+
+ /**
+ * USB data is disabled due to docking event.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_DOCK = 4;
+
+ /**
+ * USB data is disabled by
+ * {@link UsbPort#enableUsbData UsbPort.enableUsbData}.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_FORCE = 5;
+
+ /**
+ * USB data is disabled for debug.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6;
+
public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
synchronized (mLock) {
if (mProxy == null) {
@@ -489,12 +525,34 @@
return supportedContaminantProtectionModes;
}
- private int[] toIntArray(byte[] input) {
- int[] output = new int[input.length];
- for (int i = 0; i < input.length; i++) {
- output[i] = input[i];
+ private int toUsbDataStatusInt(byte[] usbDataStatusHal) {
+ int usbDataStatus = UsbPortStatus.DATA_STATUS_UNKNOWN;
+ for (int i = 0; i < usbDataStatusHal.length; i++) {
+ switch (usbDataStatusHal[i]) {
+ case USB_DATA_STATUS_ENABLED:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_ENABLED;
+ break;
+ case USB_DATA_STATUS_DISABLED_OVERHEAT:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT;
+ break;
+ case USB_DATA_STATUS_DISABLED_CONTAMINANT:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT;
+ break;
+ case USB_DATA_STATUS_DISABLED_DOCK:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
+ break;
+ case USB_DATA_STATUS_DISABLED_FORCE:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+ break;
+ case USB_DATA_STATUS_DISABLED_DEBUG:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
+ break;
+ default:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_UNKNOWN;
+ }
}
- return output;
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "AIDL UsbDataStatus:" + usbDataStatus);
+ return usbDataStatus;
}
@Override
@@ -528,7 +586,7 @@
toContaminantProtectionStatus(current.contaminantProtectionStatus),
current.supportsEnableContaminantPresenceDetection,
current.contaminantDetectionStatus,
- toIntArray(current.usbDataStatus),
+ toUsbDataStatusInt(current.usbDataStatus),
current.powerTransferLimited,
current.powerBrickStatus);
newPortInfo.add(temp);
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
index 64e8adc..c7f0775 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -33,8 +33,8 @@
import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_FORCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
import static com.android.server.usb.UsbPortManager.logAndPrint;
@@ -85,7 +85,7 @@
private HALCallback mHALCallback;
private boolean mSystemReady;
// Workaround since HIDL HAL versions report UsbDataEnabled status in UsbPortStatus;
- private static int sUsbDataStatus = USB_DATA_STATUS_UNKNOWN;
+ private static int sUsbDataStatus = DATA_STATUS_UNKNOWN;
public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
int version;
@@ -375,7 +375,7 @@
}
}
if (success) {
- sUsbDataStatus = enable ? USB_DATA_STATUS_UNKNOWN : USB_DATA_STATUS_DISABLED_FORCE;
+ sUsbDataStatus = enable ? DATA_STATUS_UNKNOWN : DATA_STATUS_DISABLED_FORCE;
}
try {
callback.onOperationComplete(success
@@ -421,7 +421,7 @@
current.canChangePowerRole,
current.currentDataRole, current.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
- false, CONTAMINANT_DETECTION_NOT_SUPPORTED, new int[sUsbDataStatus],
+ false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
@@ -455,7 +455,7 @@
current.status.canChangePowerRole,
current.status.currentDataRole, current.status.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
- false, CONTAMINANT_DETECTION_NOT_SUPPORTED, new int[sUsbDataStatus],
+ false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
@@ -493,7 +493,7 @@
current.contaminantProtectionStatus,
current.supportsEnableContaminantPresenceDetection,
current.contaminantDetectionStatus,
- new int[sUsbDataStatus],
+ sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
diff --git a/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl
new file mode 100644
index 0000000..542c6ad
--- /dev/null
+++ b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2022, 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.telephony;
+
+parcelable ActivityStatsTechSpecificInfo;
diff --git a/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java
new file mode 100644
index 0000000..e5a20ea
--- /dev/null
+++ b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2022 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.telephony;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ServiceState.FrequencyRange;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Technology specific activity stats info. List of the activity stats for each RATs (2G, 3G, 4G and
+ * 5G) and frequency ranges (HIGH for sub6 and MMWAVE) in case of 5G. In case implementation doesn't
+ * have RAT specific activity stats then send only one activity stats info with RAT unknown.
+ *
+ * @hide
+ */
+public final class ActivityStatsTechSpecificInfo implements Parcelable {
+ private static final int TX_POWER_LEVELS = 5;
+
+ private int mRat;
+ private int mFrequencyRange;
+ private int[] mTxTimeMs;
+ private int mRxTimeMs;
+
+ /** @hide */
+ public ActivityStatsTechSpecificInfo(
+ int rat, @FrequencyRange int frequencyRange, @NonNull int[] txTimeMs, int rxTimeMs) {
+ Objects.requireNonNull(txTimeMs);
+ if (txTimeMs.length != TX_POWER_LEVELS) {
+ throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
+ }
+ mRat = rat;
+ mFrequencyRange = frequencyRange;
+ mTxTimeMs = txTimeMs;
+ mRxTimeMs = rxTimeMs;
+ }
+
+ /**
+ * Returns the radio access technology for this activity stats info.
+ *
+ * The returned value is define in {@link AccessNetworkConstants.AccessNetworkType};
+ * @hide
+ */
+ public int getRat() {
+ return mRat;
+ }
+
+ /**
+ * Returns the rough frequency range for this activity stats info.
+ *
+ * The returned value is define in {@link ServiceState.FrequencyRange};
+ * @hide
+ */
+ public @FrequencyRange int getFrequencyRange() {
+ return mFrequencyRange;
+ }
+
+ /**
+ * Gets the amount of time the modem spent transmitting at a certain power level.
+ *
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the given
+ * power level.
+ */
+ public @DurationMillisLong long getTransmitTimeMillis(int powerLevel) {
+ return mTxTimeMs[powerLevel];
+ }
+
+ /**
+ * @return The raw array of transmit power durations
+ * @hide
+ */
+ @NonNull
+ public int[] getTransmitTimeMillis() {
+ return mTxTimeMs;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
+ *
+ * @return Time in milliseconds.
+ * @hide
+ */
+ public @DurationMillisLong long getReceiveTimeMillis() {
+ return mRxTimeMs;
+ }
+ /** @hide */
+ public void setRat(int rat) {
+ mRat = rat;
+ }
+
+ /** @hide */
+ public void setFrequencyRange(@FrequencyRange int frequencyRange) {
+ mFrequencyRange = frequencyRange;
+ }
+
+ /** @hide */
+ public void setReceiveTimeMillis(int receiveTimeMillis) {
+ mRxTimeMs = receiveTimeMillis;
+ }
+
+ /**
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ *
+ * @hide
+ */
+ public void setReceiveTimeMillis(long receiveTimeMillis) {
+ mRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /** @hide */
+ public void setTransmitTimeMillis(int[] txTimeMs) {
+ mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+ }
+
+ /** @hide */
+ public boolean isTxPowerValid() {
+ return Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
+ }
+
+ /** @hide */
+ public boolean isRxPowerValid() {
+ return getReceiveTimeMillis() >= 0;
+ }
+
+ /** @hide */
+ public boolean isTxPowerEmpty() {
+ boolean isTxPowerEmpty =
+ mTxTimeMs == null
+ || mTxTimeMs.length == 0
+ || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
+ return isTxPowerEmpty;
+ }
+
+ /** @hide */
+ public boolean isRxPowerEmpty() {
+ return getReceiveTimeMillis() == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mRat, mFrequencyRange, mRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ActivityStatsTechSpecificInfo)) return false;
+ ActivityStatsTechSpecificInfo that = (ActivityStatsTechSpecificInfo) o;
+ return mRat == that.mRat
+ && mFrequencyRange == that.mFrequencyRange
+ && Arrays.equals(mTxTimeMs, that.mTxTimeMs)
+ && mRxTimeMs == that.mRxTimeMs;
+ }
+
+ private static String ratToString(int type) {
+ switch (type) {
+ case AccessNetworkConstants.AccessNetworkType.UNKNOWN:
+ return "UNKNOWN";
+ case AccessNetworkConstants.AccessNetworkType.GERAN:
+ return "GERAN";
+ case AccessNetworkConstants.AccessNetworkType.UTRAN:
+ return "UTRAN";
+ case AccessNetworkConstants.AccessNetworkType.EUTRAN:
+ return "EUTRAN";
+ case AccessNetworkConstants.AccessNetworkType.CDMA2000:
+ return "CDMA2000";
+ case AccessNetworkConstants.AccessNetworkType.IWLAN:
+ return "IWLAN";
+ case AccessNetworkConstants.AccessNetworkType.NGRAN:
+ return "NGRAN";
+ default:
+ return Integer.toString(type);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("{mRat=")
+ .append(ratToString(mRat))
+ .append(",mFrequencyRange=")
+ .append(ServiceState.frequencyRangeToString(mFrequencyRange))
+ .append(",mTxTimeMs[]=")
+ .append(Arrays.toString(mTxTimeMs))
+ .append(",mRxTimeMs=")
+ .append(mRxTimeMs)
+ .append("}")
+ .toString();
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<
+ ActivityStatsTechSpecificInfo>
+ CREATOR =
+ new Parcelable.Creator<ActivityStatsTechSpecificInfo>() {
+ public ActivityStatsTechSpecificInfo createFromParcel(@NonNull Parcel in) {
+ int rat = in.readInt();
+ int frequencyRange = in.readInt();
+ int[] txTimeMs = new int[TX_POWER_LEVELS];
+ in.readIntArray(txTimeMs);
+ int rxTimeMs = in.readInt();
+ return new ActivityStatsTechSpecificInfo(
+ rat, frequencyRange, txTimeMs, rxTimeMs);
+ }
+
+ public ActivityStatsTechSpecificInfo[] newArray(int size) {
+ return new ActivityStatsTechSpecificInfo[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mRat);
+ dest.writeInt(mFrequencyRange);
+ dest.writeIntArray(mTxTimeMs);
+ dest.writeInt(mRxTimeMs);
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2c39863..9f53d73 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -8124,6 +8124,13 @@
"telephony_data_handover_retry_rules_string_array";
/**
+ * Indicates whether delay tearing down IMS data network until voice call ends.
+ * @hide
+ */
+ public static final String KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL =
+ "delay_ims_tear_down_until_call_end_bool";
+
+ /**
* The patterns of missed incoming call sms. This is the regular expression used for
* matching the missed incoming call's date, time, and caller id. The pattern should match
* fields for at least month, day, hour, and minute. Year is optional although it is encouraged.
@@ -8968,6 +8975,7 @@
KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY, new String[] {
"retry_interval=1000|2000|4000|8000|16000, maximum_retries=5"
});
+ sDefaults.putBoolean(KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, false);
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 837124f..ca6dc2d 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -22,6 +22,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Objects;
@@ -76,7 +78,8 @@
/**
* @hide
*/
- DataSpecificRegistrationInfo(
+ @VisibleForTesting
+ public DataSpecificRegistrationInfo(
int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
boolean isEnDcAvailable, @Nullable VopsSupportInfo vops) {
this.maxDataCalls = maxDataCalls;
@@ -186,7 +189,7 @@
/**
* @return The VOPS (Voice over Packet Switched) support information.
*
- * The instance of {@link LTEVopsSupportInfo}, or {@link NrVopsSupportInfo},
+ * The instance of {@link LteVopsSupportInfo}, or {@link NrVopsSupportInfo},
* null if there is there is no VOPS support information available.
*/
@Nullable
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index ec6c25d..730a9d1 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -25,6 +25,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.telephony.ServiceState.FrequencyRange;
import android.util.Range;
import java.lang.annotation.Retention;
@@ -94,8 +95,10 @@
private long mTimestamp;
private int mSleepTimeMs;
private int mIdleTimeMs;
- private int[] mTxTimeMs;
- private int mRxTimeMs;
+ private int[] mTotalTxTimeMs;
+ private int mTotalRxTimeMs;
+ private int mSizeOfSpecificInfo;
+ private ActivityStatsTechSpecificInfo[] mActivityStatsTechSpecificInfo;
/**
* @hide
@@ -110,8 +113,17 @@
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- mTxTimeMs = txTimeMs;
- mRxTimeMs = rxTimeMs;
+ mTotalTxTimeMs = txTimeMs;
+ mTotalRxTimeMs = rxTimeMs;
+
+ mActivityStatsTechSpecificInfo = new ActivityStatsTechSpecificInfo[1];
+ mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
+ mActivityStatsTechSpecificInfo[0] =
+ new ActivityStatsTechSpecificInfo(
+ AccessNetworkConstants.AccessNetworkType.UNKNOWN,
+ ServiceState.FREQUENCY_RANGE_UNKNOWN,
+ txTimeMs,
+ rxTimeMs);
}
/**
@@ -124,14 +136,49 @@
this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
}
+ /** @hide */
+ public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
+ @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
+ mTimestamp = timestamp;
+ mSleepTimeMs = sleepTimeMs;
+ mIdleTimeMs = idleTimeMs;
+ mActivityStatsTechSpecificInfo = activityStatsTechSpecificInfo;
+ mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
+ mTotalTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ for (int i = 0; i < getNumTxPowerLevels(); i++) {
+ for (int j = 0; j < getSpecificInfoLength(); j++) {
+ mTotalTxTimeMs[i] = mTotalTxTimeMs[i]
+ + (int) mActivityStatsTechSpecificInfo[j].getTransmitTimeMillis(i);
+ }
+ }
+ mTotalRxTimeMs = 0;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ mTotalRxTimeMs =
+ mTotalRxTimeMs + (int) mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+ }
+ }
+
+ /**
+ * Provided for convenience in manipulation since the API exposes long values but internal
+ * representations are ints.
+ * @hide
+ */
+ public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
+ @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
+ this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, activityStatsTechSpecificInfo);
+ }
+
@Override
public String toString() {
return "ModemActivityInfo{"
- + " mTimestamp=" + mTimestamp
- + " mSleepTimeMs=" + mSleepTimeMs
- + " mIdleTimeMs=" + mIdleTimeMs
- + " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
- + " mRxTimeMs=" + mRxTimeMs
+ + " mTimestamp="
+ + mTimestamp
+ + " mSleepTimeMs="
+ + mSleepTimeMs
+ + " mIdleTimeMs="
+ + mIdleTimeMs
+ + " mActivityStatsTechSpecificInfo="
+ + Arrays.toString(mActivityStatsTechSpecificInfo)
+ "}";
}
@@ -145,11 +192,17 @@
long timestamp = in.readLong();
int sleepTimeMs = in.readInt();
int idleTimeMs = in.readInt();
- int[] txTimeMs = new int[TX_POWER_LEVELS];
- in.readIntArray(txTimeMs);
- int rxTimeMs = in.readInt();
- return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
- txTimeMs, rxTimeMs);
+ Parcelable[] tempSpecifiers =
+ in.createTypedArray(ActivityStatsTechSpecificInfo.CREATOR);
+ ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo;
+ activityStatsTechSpecificInfo =
+ new ActivityStatsTechSpecificInfo[tempSpecifiers.length];
+ for (int i = 0; i < tempSpecifiers.length; i++) {
+ activityStatsTechSpecificInfo[i] =
+ (ActivityStatsTechSpecificInfo) tempSpecifiers[i];
+ }
+ return new ModemActivityInfo(
+ timestamp, sleepTimeMs, idleTimeMs, activityStatsTechSpecificInfo);
}
public ModemActivityInfo[] newArray(int size) {
@@ -165,15 +218,14 @@
dest.writeLong(mTimestamp);
dest.writeInt(mSleepTimeMs);
dest.writeInt(mIdleTimeMs);
- dest.writeIntArray(mTxTimeMs);
- dest.writeInt(mRxTimeMs);
+ dest.writeTypedArray(mActivityStatsTechSpecificInfo, flags);
}
/**
* Gets the timestamp at which this modem activity info was recorded.
*
- * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this
- * {@link ModemActivityInfo} was recorded.
+ * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this {@link
+ * ModemActivityInfo} was recorded.
*/
public @ElapsedRealtimeLong long getTimestampMillis() {
return mTimestamp;
@@ -188,14 +240,41 @@
* Gets the amount of time the modem spent transmitting at a certain power level.
*
* @param powerLevel The power level to query.
- * @return The amount of time, in milliseconds, that the modem spent transmitting at the
- * given power level.
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the given
+ * power level.
*/
public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
@TxPowerLevel int powerLevel) {
- return mTxTimeMs[powerLevel];
+ long txTimeMsAtPowerLevel = 0;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ txTimeMsAtPowerLevel +=
+ mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+ }
+ return txTimeMsAtPowerLevel;
}
+ /** @hide */
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel, int rat) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+ }
+ }
+ return 0;
+ }
+
+ /** @hide */
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel, int rat, @FrequencyRange int freq) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+ }
+ }
+ return 0;
+ }
/**
* Gets the range of transmit powers corresponding to a certain power level.
*
@@ -208,17 +287,64 @@
}
/** @hide */
- public void setTransmitTimeMillis(int[] txTimeMs) {
- mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+ public int getSpecificInfoRat(int index) {
+ return mActivityStatsTechSpecificInfo[index].getRat();
}
+ /** @hide */
+ public int getSpecificInfoFrequencyRange(int index) {
+ return mActivityStatsTechSpecificInfo[index].getFrequencyRange();
+ }
+ /** @hide */
+ public void setTransmitTimeMillis(int[] txTimeMs) {
+ mTotalTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+ }
+ /** @hide */
+ public void setTransmitTimeMillis(int rat, int[] txTimeMs) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
+ }
+ }
+ }
+ /** @hide */
+ public void setTransmitTimeMillis(int rat, int freq, int[] txTimeMs) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
+ }
+ }
+ }
/**
* @return The raw array of transmit power durations
* @hide
*/
@NonNull
public int[] getTransmitTimeMillis() {
- return mTxTimeMs;
+ return mTotalTxTimeMs;
+ }
+
+ /** @hide */
+ public int[] getTransmitTimeMillis(@AccessNetworkConstants.RadioAccessNetworkType int rat) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
+ }
+ }
+ return new int[5];
+ }
+
+ /** @hide */
+ public int[] getTransmitTimeMillis(
+ @AccessNetworkConstants.RadioAccessNetworkType int rat, @FrequencyRange int freq) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
+ }
+ }
+ return new int[5];
}
/**
@@ -238,6 +364,7 @@
/**
* Provided for convenience, since the API surface needs to return longs but internal
* representations are ints.
+ *
* @hide
*/
public void setSleepTimeMillis(long sleepTimeMillis) {
@@ -257,14 +384,63 @@
*/
public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
- txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i];
+
+ ActivityStatsTechSpecificInfo[] mDeltaSpecificInfo;
+ mDeltaSpecificInfo = new ActivityStatsTechSpecificInfo[other.getSpecificInfoLength()];
+
+ boolean matched;
+ for (int i = 0; i < other.getSpecificInfoLength(); i++) {
+ matched = false;
+ for (int j = 0; j < getSpecificInfoLength(); j++) {
+ int rat = mActivityStatsTechSpecificInfo[j].getRat();
+ if (rat == other.mActivityStatsTechSpecificInfo[i].getRat() && !matched) {
+ if (mActivityStatsTechSpecificInfo[j].getRat()
+ == AccessNetworkConstants.AccessNetworkType.NGRAN) {
+ if (other.mActivityStatsTechSpecificInfo[i].getFrequencyRange()
+ == mActivityStatsTechSpecificInfo[j].getFrequencyRange()) {
+ int freq = mActivityStatsTechSpecificInfo[j].getFrequencyRange();
+ for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ txTimeMs[lvl] =
+ (int) (other.getTransmitDurationMillisAtPowerLevel(
+ lvl, rat, freq)
+ - getTransmitDurationMillisAtPowerLevel(
+ lvl, rat, freq));
+ }
+ matched = true;
+ mDeltaSpecificInfo[i] =
+ new ActivityStatsTechSpecificInfo(
+ rat,
+ freq,
+ txTimeMs,
+ (int) (other.getReceiveTimeMillis(rat, freq)
+ - getReceiveTimeMillis(rat, freq)));
+ }
+ } else {
+ for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ txTimeMs[lvl] =
+ (int) (other.getTransmitDurationMillisAtPowerLevel(lvl, rat)
+ - getTransmitDurationMillisAtPowerLevel(lvl, rat));
+ }
+ matched = true;
+ mDeltaSpecificInfo[i] =
+ new ActivityStatsTechSpecificInfo(
+ rat,
+ ServiceState.FREQUENCY_RANGE_UNKNOWN,
+ txTimeMs,
+ (int) (other.getReceiveTimeMillis(rat)
+ - getReceiveTimeMillis(rat)));
+ }
+ }
+ }
+ if (!matched) {
+ mDeltaSpecificInfo[i] = other.mActivityStatsTechSpecificInfo[i];
+ }
}
- return new ModemActivityInfo(other.getTimestampMillis(),
+ return new ModemActivityInfo(
+ other.getTimestampMillis(),
other.getSleepTimeMillis() - getSleepTimeMillis(),
other.getIdleTimeMillis() - getIdleTimeMillis(),
- txTimeMs,
- other.getReceiveTimeMillis() - getReceiveTimeMillis());
+ mDeltaSpecificInfo);
}
/**
@@ -285,6 +461,7 @@
/**
* Provided for convenience, since the API surface needs to return longs but internal
* representations are ints.
+ *
* @hide
*/
public void setIdleTimeMillis(long idleTimeMillis) {
@@ -297,21 +474,66 @@
* @return Time in milliseconds.
*/
public @DurationMillisLong long getReceiveTimeMillis() {
- return mRxTimeMs;
+ return mTotalRxTimeMs;
+ }
+
+ /** @hide */
+ public @DurationMillisLong long getReceiveTimeMillis(int rat) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+ }
+ }
+ return 0;
+ }
+ /** @hide */
+ public @DurationMillisLong long getReceiveTimeMillis(int rat, int freq) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+ }
+ }
+ return 0;
}
/** @hide */
public void setReceiveTimeMillis(int rxTimeMillis) {
- mRxTimeMs = rxTimeMillis;
+ mTotalRxTimeMs = rxTimeMillis;
}
/**
* Provided for convenience, since the API surface needs to return longs but internal
* representations are ints.
+ *
* @hide
*/
public void setReceiveTimeMillis(long receiveTimeMillis) {
- mRxTimeMs = (int) receiveTimeMillis;
+ mTotalRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /** @hide */
+ public void setReceiveTimeMillis(int rat, long receiveTimeMillis) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
+ }
+ }
+ }
+
+ /** @hide */
+ public void setReceiveTimeMillis(int rat, int freq, long receiveTimeMillis) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
+ }
+ }
+ }
+
+ /** @hide */
+ public int getSpecificInfoLength() {
+ return mSizeOfSpecificInfo;
}
/**
@@ -323,23 +545,42 @@
*/
@TestApi
public boolean isValid() {
- boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
-
- return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
- && (getReceiveTimeMillis() >= 0) && !isEmpty());
+ if (mActivityStatsTechSpecificInfo == null) {
+ return false;
+ } else {
+ boolean isTxPowerValid = true;
+ boolean isRxPowerValid = true;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (!mActivityStatsTechSpecificInfo[i].isTxPowerValid()) {
+ isTxPowerValid = false;
+ }
+ if (!mActivityStatsTechSpecificInfo[i].isRxPowerValid()) {
+ isRxPowerValid = false;
+ }
+ }
+ return isTxPowerValid
+ && isRxPowerValid
+ && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0) && !isEmpty());
+ }
}
/** @hide */
@TestApi
public boolean isEmpty() {
- boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
- || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
-
- return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
- && (getReceiveTimeMillis() == 0));
+ boolean isTxPowerEmpty = false;
+ boolean isRxPowerEmpty = false;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) {
+ isTxPowerEmpty = true;
+ }
+ if (mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) {
+ isRxPowerEmpty = true;
+ }
+ }
+ return isTxPowerEmpty
+ && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0) && isRxPowerEmpty);
}
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -348,14 +589,15 @@
return mTimestamp == that.mTimestamp
&& mSleepTimeMs == that.mSleepTimeMs
&& mIdleTimeMs == that.mIdleTimeMs
- && mRxTimeMs == that.mRxTimeMs
- && Arrays.equals(mTxTimeMs, that.mTxTimeMs);
+ && mSizeOfSpecificInfo == that.mSizeOfSpecificInfo
+ && Arrays.equals(
+ mActivityStatsTechSpecificInfo, that.mActivityStatsTechSpecificInfo);
}
@Override
public int hashCode() {
- int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs);
- result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mTotalRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTotalTxTimeMs);
return result;
}
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c18443e..c701e44 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -242,13 +242,16 @@
* @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the
* information is not available.
* @param rplmn the registered plmn or the last plmn for attempted registration if reg failed.
+ * @param voiceSpecificInfo Voice specific registration information.
+ * @param dataSpecificInfo Data specific registration information.
*/
private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
- @RegistrationState int registrationState,
- @NetworkType int accessNetworkTechnology, int rejectCause,
- boolean emergencyOnly,
- @Nullable @ServiceType List<Integer> availableServices,
- @Nullable CellIdentity cellIdentity, @Nullable String rplmn) {
+ @RegistrationState int registrationState,
+ @NetworkType int accessNetworkTechnology, int rejectCause,
+ boolean emergencyOnly, @Nullable @ServiceType List<Integer> availableServices,
+ @Nullable CellIdentity cellIdentity, @Nullable String rplmn,
+ @Nullable VoiceSpecificRegistrationInfo voiceSpecificInfo,
+ @Nullable DataSpecificRegistrationInfo dataSpecificInfo) {
mDomain = domain;
mTransportType = transportType;
mRegistrationState = registrationState;
@@ -262,6 +265,10 @@
mEmergencyOnly = emergencyOnly;
mNrState = NR_STATE_NONE;
mRplmn = rplmn;
+ mVoiceSpecificInfo = voiceSpecificInfo;
+ mDataSpecificInfo = dataSpecificInfo;
+
+ updateNrState();
}
/**
@@ -276,10 +283,9 @@
boolean cssSupported, int roamingIndicator, int systemIsInPrl,
int defaultRoamingIndicator) {
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
- emergencyOnly, availableServices, cellIdentity, rplmn);
-
- mVoiceSpecificInfo = new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
- systemIsInPrl, defaultRoamingIndicator);
+ emergencyOnly, availableServices, cellIdentity, rplmn,
+ new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
+ systemIsInPrl, defaultRoamingIndicator), null);
}
/**
@@ -295,11 +301,9 @@
boolean isNrAvailable, boolean isEndcAvailable,
@Nullable VopsSupportInfo vopsSupportInfo) {
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
- emergencyOnly, availableServices, cellIdentity, rplmn);
- mDataSpecificInfo = new DataSpecificRegistrationInfo(
- maxDataCalls, isDcNrRestricted, isNrAvailable,
- isEndcAvailable, vopsSupportInfo);
- updateNrState();
+ emergencyOnly, availableServices, cellIdentity, rplmn, null,
+ new DataSpecificRegistrationInfo(maxDataCalls, isDcNrRestricted, isNrAvailable,
+ isEndcAvailable, vopsSupportInfo));
}
private NetworkRegistrationInfo(Parcel source) {
@@ -804,6 +808,12 @@
@NonNull
private String mRplmn = "";
+ @Nullable
+ private DataSpecificRegistrationInfo mDataSpecificRegistrationInfo;
+
+ @Nullable
+ private VoiceSpecificRegistrationInfo mVoiceSpecificRegistrationInfo;
+
/**
* Default constructor for Builder.
*/
@@ -930,6 +940,30 @@
}
/**
+ * Set voice specific registration information.
+ *
+ * @param info The voice specific registration information.
+ * @return The builder.
+ * @hide
+ */
+ public @NonNull Builder setVoiceSpecificInfo(@NonNull VoiceSpecificRegistrationInfo info) {
+ mVoiceSpecificRegistrationInfo = info;
+ return this;
+ }
+
+ /**
+ * Set data specific registration information.
+ *
+ * @param info The data specific registration information.
+ * @return The builder.
+ * @hide
+ */
+ public @NonNull Builder setDataSpecificInfo(@NonNull DataSpecificRegistrationInfo info) {
+ mDataSpecificRegistrationInfo = info;
+ return this;
+ }
+
+ /**
* Build the NetworkRegistrationInfo.
* @return the NetworkRegistrationInfo object.
* @hide
@@ -938,7 +972,8 @@
public @NonNull NetworkRegistrationInfo build() {
return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
- mCellIdentity, mRplmn);
+ mCellIdentity, mRplmn, mVoiceSpecificRegistrationInfo,
+ mDataSpecificRegistrationInfo);
}
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 65f5632..6fe9bf9 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1205,7 +1205,15 @@
}
}
- private void init() {
+ /**
+ * Initialize the service state. Set everything to the default value.
+ *
+ * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is
+ * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device
+ * is on AP-assisted mode, where IWLAN should be reported through WLAN.
+ * {@link NetworkRegistrationInfo}.
+ */
+ private void init(boolean legacyMode) {
if (DBG) Rlog.d(LOG_TAG, "init");
mVoiceRegState = STATE_OUT_OF_SERVICE;
mDataRegState = STATE_OUT_OF_SERVICE;
@@ -1237,6 +1245,13 @@
.setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
.build());
+ if (!legacyMode) {
+ addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
+ .build());
+ }
}
mOperatorAlphaLongRaw = null;
mOperatorAlphaShortRaw = null;
@@ -1245,15 +1260,32 @@
}
public void setStateOutOfService() {
- init();
+ init(true);
}
public void setStateOff() {
- init();
+ init(true);
mVoiceRegState = STATE_POWER_OFF;
mDataRegState = STATE_POWER_OFF;
}
+ /**
+ * Set the service state to out-of-service
+ *
+ * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is
+ * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device
+ * is on AP-assisted mode, where IWLAN should be reported through WLAN.
+ * @param powerOff {@code true} if this is a power off case (i.e. Airplane mode on).
+ * @hide
+ */
+ public void setOutOfService(boolean legacyMode, boolean powerOff) {
+ init(legacyMode);
+ if (powerOff) {
+ mVoiceRegState = STATE_POWER_OFF;
+ mDataRegState = STATE_POWER_OFF;
+ }
+ }
+
public void setState(int state) {
setVoiceRegState(state);
if (DBG) Rlog.e(LOG_TAG, "[ServiceState] setState deprecated use setVoiceRegState()");
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
index 429541c..71e576a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
@@ -44,6 +44,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 219749605)
class LaunchAppShowImeAndDialogThemeAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@@ -119,4 +120,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 5f0176e..ba5698c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -61,6 +61,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group2
+@FlakyTest(bugId = 219757170)
class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@@ -87,7 +88,7 @@
}
transitions {
device.reopenAppFromOverview(wmHelper)
- wmHelper.waitImeShown()
+ require(wmHelper.waitImeShown()) { "IME didn't show in time" }
}
teardown {
test {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 065b1c2..3b3a303 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,16 +16,19 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
+import android.platform.test.annotations.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,7 +57,13 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppFromLauncherTransition(testSpec) {
+open class OpenAppColdTest(testSpec: FlickerTestParameter)
+ : OpenAppFromLauncherTransition(testSpec) {
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt
new file mode 100644
index 0000000..849e3ae
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launching an app from launcher
+ *
+ * To run this test: `atest FlickerTests:OpenAppColdTest`
+ *
+ * Actions:
+ * Make sure no apps are running on the device
+ * Launch an app [testApp] and wait animation to complete
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppColdTest_ShellTransit(testSpec: FlickerTestParameter) : OpenAppColdTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 797919b..18d017d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -17,21 +17,22 @@
package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import android.view.Display
import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -62,8 +63,13 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppFromOverviewTest(testSpec: FlickerTestParameter)
+open class OpenAppFromOverviewTest(testSpec: FlickerTestParameter)
: OpenAppFromLauncherTransition(testSpec) {
+ @Before
+ open fun before() {
+ assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt
new file mode 100644
index 0000000..24716ff
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching an app from the recents app view (the overview)
+ *
+ * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ *
+ * Actions:
+ * Launch [testApp]
+ * Press recents
+ * Relaunch an app [testApp] by selecting it in the overview screen, and wait animation to
+ * complete (only this action is traced)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppFromOverviewTest_ShellTransit(testSpec: FlickerTestParameter)
+ : OpenAppFromOverviewTest(testSpec) {
+ @Before
+ override fun before() {
+ assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index f75c50e..0ba5369 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -16,19 +16,22 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,11 +60,16 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppNonResizeableTest(testSpec: FlickerTestParameter)
+open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter)
: OpenAppFromLockTransition(testSpec) {
override val testApp = NonResizeableAppHelper(instrumentation)
private val colorFadComponent = FlickerComponentName("", "ColorFade BLAST#")
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Checks that the nav bar layer starts invisible, becomes visible during unlocking animation
* and remains visible at the end
@@ -148,6 +156,11 @@
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
+ @FlakyTest(bugId = 218470989)
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest_ShellTransit.kt
new file mode 100644
index 0000000..f8afcd9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest_ShellTransit.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching an app while the device is locked
+ *
+ * To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
+ *
+ * Actions:
+ * Lock the device.
+ * Launch an app on top of the lock screen [testApp] and wait animation to complete
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppNonResizeableTest_ShellTransit(testSpec: FlickerTestParameter)
+ : OpenAppNonResizeableTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 3159bf1..2562098 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -17,14 +17,17 @@
package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.helpers.setRotation
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,8 +57,13 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppWarmTest(testSpec: FlickerTestParameter)
+open class OpenAppWarmTest(testSpec: FlickerTestParameter)
: OpenAppFromLauncherTransition(testSpec) {
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt
new file mode 100644
index 0000000..0ce73f4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test warm launching an app from launcher
+ *
+ * To run this test: `atest FlickerTests:OpenAppWarmTest`
+ *
+ * Actions:
+ * Launch [testApp]
+ * Press home
+ * Relaunch an app [testApp] and wait animation to complete (only this action is traced)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppWarmTest_ShellTransit(testSpec: FlickerTestParameter)
+ : OpenAppWarmTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 5301e02..f21b1d6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -33,12 +33,15 @@
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,7 +64,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParameter) {
+open class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp1 = SimpleAppHelper(instrumentation)
@@ -69,6 +72,11 @@
private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
@@ -326,4 +334,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
new file mode 100644
index 0000000..07fe274
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.quickswitch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching back to previous app from last opened app
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest`
+ *
+ * Actions:
+ * Launch an app [testApp1]
+ * Launch another app [testApp2]
+ * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
+ *
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219690120)
+class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(testSpec: FlickerTestParameter)
+ : QuickSwitchBetweenTwoAppsBackTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 3ae484b..15fd5e1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -17,17 +17,20 @@
package com.android.server.wm.flicker.rotation
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import android.view.WindowManager
import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -76,11 +79,16 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
-class SeamlessAppRotationTest(
+open class SeamlessAppRotationTest(
testSpec: FlickerTestParameter
) : RotationTransition(testSpec) {
override val testApp = SeamlessRotationAppHelper(instrumentation)
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
override val transition: FlickerBuilder.() -> Unit
get() = {
super.transition(this)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest_ShellTransit.kt
new file mode 100644
index 0000000..be55751
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest_ShellTransit.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.rotation
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test opening an app and cycling through app rotations using seamless rotations
+ *
+ * Currently runs:
+ * 0 -> 90 degrees
+ * 0 -> 90 degrees (with starved UI thread)
+ * 90 -> 0 degrees
+ * 90 -> 0 degrees (with starved UI thread)
+ *
+ * Actions:
+ * Launch an app in fullscreen and supporting seamless rotation (via intent)
+ * Set initial device orientation
+ * Start tracing
+ * Change device orientation
+ * Stop tracing
+ *
+ * To run this test: `atest FlickerTests:SeamlessAppRotationTest`
+ *
+ * To run only the presubmit assertions add: `--
+ * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
+ * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit`
+ *
+ * To run only the postsubmit assertions add: `--
+ * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
+ * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit`
+ *
+ * To run only the flaky assertions add: `--
+ * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest`
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [RotationTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+@FlakyTest(bugId = 219689723)
+class SeamlessAppRotationTest_ShellTransit(
+ testSpec: FlickerTestParameter
+) : SeamlessAppRotationTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 978bf3e..7b1f7a5 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -174,7 +174,7 @@
private IntentFilter getIntentFilter() {
final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
+ verify(mContext).registerReceiver(any(), captor.capture(), any(), any(), anyInt());
return captor.getValue();
}
@@ -258,7 +258,8 @@
eq(mTelephonySubscriptionTracker),
any(IntentFilter.class),
any(),
- eq(mHandler));
+ eq(mHandler),
+ eq(Context.RECEIVER_NOT_EXPORTED));
final IntentFilter filter = getIntentFilter();
assertEquals(2, filter.countActions());
assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));