summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/IoUtils.java2
-rw-r--r--cmds/statsd/src/atoms.proto39
-rw-r--r--core/java/android/app/ActivityThread.java16
-rw-r--r--core/java/android/app/LoadedApk.java28
-rw-r--r--core/java/android/content/pm/PackageInstaller.java12
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java12
-rw-r--r--core/java/android/os/GraphicsEnvironment.java166
-rw-r--r--core/java/android/os/UserManager.java7
-rwxr-xr-xcore/java/android/provider/Settings.java9
-rw-r--r--core/java/android/provider/Telephony.java40
-rw-r--r--core/java/android/service/autofill/InlineSuggestionRoot.java4
-rw-r--r--core/java/android/view/GestureDetector.java14
-rw-r--r--core/java/android/webkit/WebChromeClient.java8
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java18
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java61
-rw-r--r--core/java/com/android/internal/app/ChooserGridLayoutManager.java11
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java11
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java63
-rw-r--r--core/java/com/android/internal/app/ResolverViewPager.java12
-rw-r--r--core/java/com/android/internal/logging/UiEventLogger.java24
-rw-r--r--core/java/com/android/internal/logging/UiEventLoggerImpl.java27
-rw-r--r--core/java/com/android/internal/logging/testing/UiEventLoggerFake.java30
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp12
-rw-r--r--core/proto/android/server/connectivity/data_stall_event.proto1
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/tests/PackageInstallerSessions/Android.bp42
-rw-r--r--core/tests/PackageInstallerSessions/AndroidManifest.xml29
-rw-r--r--core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt188
-rw-r--r--data/keyboards/Vendor_045e_Product_0b12.kl59
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_bar.xml10
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar.xml3
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml2
-rw-r--r--packages/SystemUI/res/layout/partial_conversation_info.xml33
-rw-r--r--packages/SystemUI/res/layout/priority_onboarding_half_shell.xml176
-rw-r--r--packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml9
-rw-r--r--packages/SystemUI/res/values-sw320dp/dimens.xml36
-rw-r--r--packages/SystemUI/res/values/dimens.xml18
-rw-r--r--packages/SystemUI/res/values/strings.xml7
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java86
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java93
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java13
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java7
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java46
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java83
-rw-r--r--services/core/java/com/android/server/location/UserInfoHelper.java213
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/DataLoaderManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java130
-rw-r--r--services/core/java/com/android/server/pm/PersistentPreferredActivity.java19
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java48
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java20
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java7
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java6
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java145
-rw-r--r--telephony/java/android/telephony/SmsCbMessage.java8
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java9
84 files changed, 1683 insertions, 864 deletions
diff --git a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
index 0ae44603516e..569a78c0ab41 100644
--- a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
+++ b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
/**
* Utility class for IO.
+ *
+ * @hide
*/
public class IoUtils {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 36a8b2cfc084..9abae528b474 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -444,6 +444,8 @@ message Atom {
TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"];
MediaOutputOpSwitchReported mediaoutput_op_switch_reported =
277 [(module) = "settings"];
+ CellBroadcastMessageFiltered cb_message_filtered =
+ 278 [(module) = "cellbroadcast"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -9134,8 +9136,10 @@ message IntegrityRulesPushed {
/**
* Logs when a cell broadcast message is received on the device.
*
- * Logged from CellBroadcastService module:
+ * Logged from Cell Broadcast module and platform:
* packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ * packages/apps/CellBroadcastReceiver/
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
*/
message CellBroadcastMessageReported {
// The type of Cell Broadcast message
@@ -9146,8 +9150,40 @@ message CellBroadcastMessageReported {
CDMA_SPC = 3;
}
+ // The parts of the cell broadcast message pipeline
+ enum ReportSource {
+ UNKNOWN_SOURCE = 0;
+ FRAMEWORK = 1;
+ CB_SERVICE = 2;
+ CB_RECEIVER_APP = 3;
+ }
+
// GSM, CDMA, CDMA-SCP
optional CbType type = 1;
+
+ // The source of the report
+ optional ReportSource source = 2;
+}
+
+/**
+ * Logs when a cell broadcast message is filtered out, or otherwise intentionally not sent to CBR.
+ *
+ * Logged from CellBroadcastService module:
+ * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ */
+message CellBroadcastMessageFiltered {
+ enum FilterReason {
+ NOT_FILTERED = 0;
+ DUPLICATE_MESSAGE = 1;
+ GEOFENCED_MESSAGE = 2;
+ AREA_INFO_MESSAGE = 3;
+ }
+
+ // GSM, CDMA, CDMA-SCP
+ optional CellBroadcastMessageReported.CbType type = 1;
+
+ // The source of the report
+ optional FilterReason filter = 2;
}
/**
@@ -9174,6 +9210,7 @@ message CellBroadcastMessageError {
UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12;
UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13;
UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14;
+ NO_CONNECTION_TO_CB_SERVICE = 15;
}
// What kind of error occurred
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cffa59c06a53..d275159e9f87 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7388,6 +7388,10 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ public Bundle getCoreSettings() {
+ return mCoreSettings;
+ }
+
public int getIntCoreSetting(String key, int defaultValue) {
synchronized (mResourcesManager) {
if (mCoreSettings != null) {
@@ -7397,6 +7401,18 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ /**
+ * Get the string value of the given key from core settings.
+ */
+ public String getStringCoreSetting(String key, String defaultValue) {
+ synchronized (mResourcesManager) {
+ if (mCoreSettings != null) {
+ return mCoreSettings.getString(key, defaultValue);
+ }
+ return defaultValue;
+ }
+ }
+
float getFloatCoreSetting(String key, float defaultValue) {
synchronized (mResourcesManager) {
if (mCoreSettings != null) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 10f7835b3d69..f9b48e710148 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -38,6 +38,7 @@ import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
+import android.os.GraphicsEnvironment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
@@ -46,6 +47,7 @@ import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.security.net.config.NetworkSecurityConfigProvider;
import android.sysprop.VndkProperties;
import android.text.TextUtils;
@@ -824,6 +826,32 @@ public final class LoadedApk {
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
+ if (mActivityThread != null) {
+ final String gpuDebugApp = mActivityThread.getStringCoreSetting(
+ Settings.Global.GPU_DEBUG_APP, "");
+ if (!gpuDebugApp.isEmpty() && mPackageName.equals(gpuDebugApp)) {
+
+ // The current application is used to debug, attempt to get the debug layers.
+ try {
+ // Get the ApplicationInfo from PackageManager so that metadata fields present.
+ final ApplicationInfo ai = ActivityThread.getPackageManager()
+ .getApplicationInfo(mPackageName, PackageManager.GET_META_DATA,
+ UserHandle.myUserId());
+ final String debugLayerPath = GraphicsEnvironment.getInstance()
+ .getDebugLayerPathsFromSettings(mActivityThread.getCoreSettings(),
+ ActivityThread.getPackageManager(), mPackageName, ai);
+ if (debugLayerPath != null) {
+ libraryPermittedPath += File.pathSeparator + debugLayerPath;
+ }
+ } catch (RemoteException e) {
+ // Unlikely to fail for applications, but in case of failure, something is wrong
+ // inside the system server, hence just skip.
+ Slog.e(ActivityThread.TAG,
+ "RemoteException when fetching debug layer paths for: " + mPackageName);
+ }
+ }
+ }
+
// If we're not asked to include code, we construct a classloader that has
// no code path included. We still need to set up the library search paths
// and permitted path because NativeActivity relies on it (it attempts to
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index ed75504529b9..fc4ccd072e75 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1449,6 +1449,13 @@ public class PackageInstaller {
/** {@hide} */
public static final int UID_UNKNOWN = -1;
+ /**
+ * This value is derived from the maximum file name length. No package above this limit
+ * can ever be successfully installed on the device.
+ * @hide
+ */
+ public static final int MAX_PACKAGE_NAME_LENGTH = 255;
+
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int mode = MODE_INVALID;
@@ -1642,6 +1649,8 @@ public class PackageInstaller {
/**
* Optionally set a label representing the app being installed.
+ *
+ * This value will be trimmed to the first 1000 characters.
*/
public void setAppLabel(@Nullable CharSequence appLabel) {
this.appLabel = (appLabel != null) ? appLabel.toString() : null;
@@ -1711,7 +1720,8 @@ public class PackageInstaller {
*
* <p>Initially, all restricted permissions are whitelisted but you can change
* which ones are whitelisted by calling this method or the corresponding ones
- * on the {@link PackageManager}.
+ * on the {@link PackageManager}. Only soft or hard restricted permissions on the current
+ * Android version are supported and any invalid entries will be removed.
*
* @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
* @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index f354bdb5a08b..65ce1e7ef079 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -49,8 +49,16 @@ import java.util.Objects;
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
- /** The maximum length of a safe label, in characters */
- private static final int MAX_SAFE_LABEL_LENGTH = 50000;
+
+ /**
+ * The maximum length of a safe label, in characters
+ *
+ * TODO(b/157997155): It may make sense to expose this publicly so that apps can check for the
+ * value and truncate the strings/use a different label, without having to hardcode and make
+ * assumptions about the value.
+ * @hide
+ */
+ public static final int MAX_SAFE_LABEL_LENGTH = 1000;
/** @hide */
public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 034e6a7a06c4..df58a6c636f5 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -93,8 +94,8 @@ public class GraphicsEnvironment {
private static final int GAME_DRIVER_GLOBAL_OPT_IN_OFF = 3;
private ClassLoader mClassLoader;
- private String mLayerPath;
- private String mDebugLayerPath;
+ private String mLibrarySearchPaths;
+ private String mLibraryPermittedPaths;
/**
* Set up GraphicsEnvironment
@@ -185,118 +186,131 @@ public class GraphicsEnvironment {
}
/**
- * Store the layer paths available to the loader.
+ * Store the class loader for namespace lookup later.
*/
public void setLayerPaths(ClassLoader classLoader,
- String layerPath,
- String debugLayerPath) {
+ String searchPaths,
+ String permittedPaths) {
// We have to store these in the class because they are set up before we
// have access to the Context to properly set up GraphicsEnvironment
mClassLoader = classLoader;
- mLayerPath = layerPath;
- mDebugLayerPath = debugLayerPath;
+ mLibrarySearchPaths = searchPaths;
+ mLibraryPermittedPaths = permittedPaths;
+ }
+
+ /**
+ * Returns the debug layer paths from settings.
+ * Returns null if:
+ * 1) The application process is not debuggable or layer injection metadata flag is not
+ * true; Or
+ * 2) ENABLE_GPU_DEBUG_LAYERS is not true; Or
+ * 3) Package name is not equal to GPU_DEBUG_APP.
+ */
+ public String getDebugLayerPathsFromSettings(
+ Bundle coreSettings, IPackageManager pm, String packageName,
+ ApplicationInfo ai) {
+ if (!debugLayerEnabled(coreSettings, packageName, ai)) {
+ return null;
+ }
+ Log.i(TAG, "GPU debug layers enabled for " + packageName);
+ String debugLayerPaths = "";
+
+ // Grab all debug layer apps and add to paths.
+ final String gpuDebugLayerApps =
+ coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP, "");
+ if (!gpuDebugLayerApps.isEmpty()) {
+ Log.i(TAG, "GPU debug layer apps: " + gpuDebugLayerApps);
+ // If a colon is present, treat this as multiple apps, so Vulkan and GLES
+ // layer apps can be provided at the same time.
+ final String[] layerApps = gpuDebugLayerApps.split(":");
+ for (int i = 0; i < layerApps.length; i++) {
+ String paths = getDebugLayerAppPaths(pm, layerApps[i]);
+ if (!paths.isEmpty()) {
+ // Append the path so files placed in the app's base directory will
+ // override the external path
+ debugLayerPaths += paths + File.pathSeparator;
+ }
+ }
+ }
+ return debugLayerPaths;
}
/**
* Return the debug layer app's on-disk and in-APK lib directories
*/
- private static String getDebugLayerAppPaths(PackageManager pm, String app) {
+ private static String getDebugLayerAppPaths(IPackageManager pm, String packageName) {
final ApplicationInfo appInfo;
try {
- appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Debug layer app '" + app + "' not installed");
-
- return null;
+ appInfo = pm.getApplicationInfo(packageName, PackageManager.MATCH_ALL,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ return "";
+ }
+ if (appInfo == null) {
+ Log.w(TAG, "Debug layer app '" + packageName + "' not installed");
}
final String abi = chooseAbi(appInfo);
-
final StringBuilder sb = new StringBuilder();
sb.append(appInfo.nativeLibraryDir)
- .append(File.pathSeparator);
- sb.append(appInfo.sourceDir)
+ .append(File.pathSeparator)
+ .append(appInfo.sourceDir)
.append("!/lib/")
.append(abi);
final String paths = sb.toString();
-
if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
return paths;
}
+ private boolean debugLayerEnabled(Bundle coreSettings, String packageName, ApplicationInfo ai) {
+ // Only enable additional debug functionality if the following conditions are met:
+ // 1. App is debuggable or device is rooted or layer injection metadata flag is true
+ // 2. ENABLE_GPU_DEBUG_LAYERS is true
+ // 3. Package name is equal to GPU_DEBUG_APP
+ if (!isDebuggable() && !canInjectLayers(ai)) {
+ return false;
+ }
+ final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+ if (enable == 0) {
+ return false;
+ }
+ final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP, "");
+ if (packageName == null
+ || (gpuDebugApp.isEmpty() || packageName.isEmpty())
+ || !gpuDebugApp.equals(packageName)) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Set up layer search paths for all apps
- * If debuggable, check for additional debug settings
*/
private void setupGpuLayers(
Context context, Bundle coreSettings, PackageManager pm, String packageName,
ApplicationInfo ai) {
+ final boolean enabled = debugLayerEnabled(coreSettings, packageName, ai);
String layerPaths = "";
+ if (enabled) {
+ layerPaths = mLibraryPermittedPaths;
- // Only enable additional debug functionality if the following conditions are met:
- // 1. App is debuggable or device is rooted or layer injection metadata flag is true
- // 2. ENABLE_GPU_DEBUG_LAYERS is true
- // 3. Package name is equal to GPU_DEBUG_APP
+ final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
+ Log.i(TAG, "Vulkan debug layer list: " + layers);
+ if (layers != null && !layers.isEmpty()) {
+ setDebugLayers(layers);
+ }
- if (isDebuggable() || canInjectLayers(ai)) {
-
- final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
-
- if (enable != 0) {
-
- final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
-
- if ((gpuDebugApp != null && packageName != null)
- && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
- && gpuDebugApp.equals(packageName)) {
- Log.i(TAG, "GPU debug layers enabled for " + packageName);
-
- // Prepend the debug layer path as a searchable path.
- // This will ensure debug layers added will take precedence over
- // the layers specified by the app.
- layerPaths = mDebugLayerPath + ":";
-
- // If there is a debug layer app specified, add its path.
- final String gpuDebugLayerApp =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
-
- if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
- Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
- // If a colon is present, treat this as multiple apps, so Vulkan and GLES
- // layer apps can be provided at the same time.
- String[] layerApps = gpuDebugLayerApp.split(":");
- for (int i = 0; i < layerApps.length; i++) {
- String paths = getDebugLayerAppPaths(pm, layerApps[i]);
- if (paths != null) {
- // Append the path so files placed in the app's base directory will
- // override the external path
- layerPaths += paths + ":";
- }
- }
- }
-
- final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
-
- Log.i(TAG, "Vulkan debug layer list: " + layers);
- if (layers != null && !layers.isEmpty()) {
- setDebugLayers(layers);
- }
-
- final String layersGLES =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
-
- Log.i(TAG, "GLES debug layer list: " + layersGLES);
- if (layersGLES != null && !layersGLES.isEmpty()) {
- setDebugLayersGLES(layersGLES);
- }
- }
+ final String layersGLES =
+ coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
+ Log.i(TAG, "GLES debug layer list: " + layersGLES);
+ if (layersGLES != null && !layersGLES.isEmpty()) {
+ setDebugLayersGLES(layersGLES);
}
}
// Include the app's lib directory in all cases
- layerPaths += mLayerPath;
-
+ layerPaths += mLibrarySearchPaths;
setLayerPaths(mClassLoader, layerPaths);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7845200f4bf7..a8391c2b5461 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4090,13 +4090,6 @@ public class UserManager {
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
- if (ActivityManager.isLowRamDeviceStatic()) {
- // Low-ram devices are Svelte. Most of the time they don't get multi-user.
- if ((Resources.getSystem().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK)
- != Configuration.UI_MODE_TYPE_TELEVISION) {
- return 1;
- }
- }
return SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1b19e1290121..52764d568f29 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1778,6 +1778,15 @@ public final class Settings {
= "android.settings.NOTIFICATION_SETTINGS";
/**
+ * Activity Action: Show conversation settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CONVERSATION_SETTINGS
+ = "android.settings.CONVERSATION_SETTINGS";
+
+ /**
* Activity Action: Show notification history screen.
*
* @hide
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index b34268d04238..a2489b9b68d9 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4325,6 +4325,15 @@ public final class Telephony {
public static final String ETWS_WARNING_TYPE = "etws_warning_type";
/**
+ * ETWS (Earthquake and Tsunami Warning System) primary message or not (ETWS alerts only).
+ * <p>See {@link android.telephony.SmsCbEtwsInfo}</p>
+ * <P>Type: BOOLEAN</P>
+ *
+ * @hide // TODO: Unhide this for S.
+ */
+ public static final String ETWS_IS_PRIMARY = "etws_is_primary";
+
+ /**
* CMAS (Commercial Mobile Alert System) message class (CMAS alerts only).
* <p>See {@link android.telephony.SmsCbCmasInfo}</p>
* <P>Type: INTEGER</P>
@@ -4464,37 +4473,6 @@ public final class Telephony {
CMAS_URGENCY,
CMAS_CERTAINTY
};
-
- /**
- * Query columns for instantiating {@link android.telephony.SmsCbMessage} objects.
- * @hide
- */
- public static final String[] QUERY_COLUMNS_FWK = {
- _ID,
- SLOT_INDEX,
- SUBSCRIPTION_ID,
- GEOGRAPHICAL_SCOPE,
- PLMN,
- LAC,
- CID,
- SERIAL_NUMBER,
- SERVICE_CATEGORY,
- LANGUAGE_CODE,
- MESSAGE_BODY,
- MESSAGE_FORMAT,
- MESSAGE_PRIORITY,
- ETWS_WARNING_TYPE,
- CMAS_MESSAGE_CLASS,
- CMAS_CATEGORY,
- CMAS_RESPONSE_TYPE,
- CMAS_SEVERITY,
- CMAS_URGENCY,
- CMAS_CERTAINTY,
- RECEIVED_TIME,
- MESSAGE_BROADCASTED,
- GEOMETRIES,
- MAXIMUM_WAIT_TIME
- };
}
/**
diff --git a/core/java/android/service/autofill/InlineSuggestionRoot.java b/core/java/android/service/autofill/InlineSuggestionRoot.java
index c879653859d8..16c3f1d4e476 100644
--- a/core/java/android/service/autofill/InlineSuggestionRoot.java
+++ b/core/java/android/service/autofill/InlineSuggestionRoot.java
@@ -58,7 +58,9 @@ public class InlineSuggestionRoot extends FrameLayout {
case MotionEvent.ACTION_DOWN: {
mDownX = event.getX();
mDownY = event.getY();
- } break;
+ }
+ // Intentionally fall through to the next case so that when the window is obscured
+ // we transfer the touch to the remote IME window and don't handle it locally.
case MotionEvent.ACTION_MOVE: {
final float distance = MathUtils.dist(mDownX, mDownY,
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index a9af59543c78..f6c72c4eefbc 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -289,11 +289,6 @@ public class GestureDetector {
private VelocityTracker mVelocityTracker;
/**
- * True if the detector can throw exception when touch steam is unexpected .
- */
- private boolean mExceptionForTouchStream;
-
- /**
* Consistency verifier for debugging purposes.
*/
private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
@@ -472,8 +467,6 @@ public class GestureDetector {
mTouchSlopSquare = touchSlop * touchSlop;
mDoubleTapTouchSlopSquare = doubleTapTouchSlop * doubleTapTouchSlop;
mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
- mExceptionForTouchStream = context != null
- && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R;
}
/**
@@ -646,13 +639,6 @@ public class GestureDetector {
break;
case MotionEvent.ACTION_MOVE:
- if (mExceptionForTouchStream && !mStillDown) {
- throw new IllegalStateException("Incomplete event stream received: "
- + "Received ACTION_MOVE before ACTION_DOWN. ACTION_DOWN must precede "
- + "ACTION_MOVE following ACTION_UP or ACTION_CANCEL, or when this "
- + "GestureDetector has not yet received any events.");
- }
-
if (mInLongPress || mInContextClick) {
break;
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 7042f29fc4e4..4a6551176198 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -205,6 +205,8 @@ public class WebChromeClient {
* <p>Note that if the {@link WebChromeClient} is set to be {@code null},
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and Javascript execution will continue immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -240,6 +242,8 @@ public class WebChromeClient {
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and the default value of {@code false} will be returned to
* the JavaScript code immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -274,6 +278,8 @@ public class WebChromeClient {
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and {@code null} will be returned to the JavaScript code
* immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -308,6 +314,8 @@ public class WebChromeClient {
* <p>Note that if the {@link WebChromeClient} is set to be {@code null},
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and the navigation will be resumed immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 493865ac563f..b723db287823 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -151,6 +151,13 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
mOnProfileSelectedListener.onProfileSelected(position);
}
}
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (mOnProfileSelectedListener != null) {
+ mOnProfileSelectedListener.onProfilePageStateChanged(state);
+ }
+ }
});
viewPager.setAdapter(this);
viewPager.setCurrentItem(mCurrentPage);
@@ -606,6 +613,17 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
* {@link #PROFILE_WORK} if the work profile was selected.
*/
void onProfileSelected(int profileIndex);
+
+
+ /**
+ * Callback for when the scroll state changes. Useful for discovering when the user begins
+ * dragging, when the pager is automatically settling to the current page, or when it is
+ * fully stopped/idle.
+ * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
+ * or {@link ViewPager#SCROLL_STATE_SETTLING}
+ * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
+ */
+ void onProfilePageStateChanged(int state);
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2a43287a3ae3..049a76c89815 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -102,6 +102,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
@@ -129,6 +130,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.GridLayoutManager;
import com.android.internal.widget.RecyclerView;
import com.android.internal.widget.ResolverDrawerLayout;
+import com.android.internal.widget.ViewPager;
import com.google.android.collect.Lists;
@@ -204,6 +206,10 @@ public class ChooserActivity extends ResolverActivity implements
public static final int SELECTION_TYPE_STANDARD = 3;
public static final int SELECTION_TYPE_COPY = 4;
+ private static final int SCROLL_STATUS_IDLE = 0;
+ private static final int SCROLL_STATUS_SCROLLING_VERTICAL = 1;
+ private static final int SCROLL_STATUS_SCROLLING_HORIZONTAL = 2;
+
// statsd logger wrapper
protected ChooserActivityLogger mChooserActivityLogger;
@@ -293,6 +299,7 @@ public class ChooserActivity extends ResolverActivity implements
protected MetricsLogger mMetricsLogger;
private ContentPreviewCoordinator mPreviewCoord;
+ private int mScrollStatus = SCROLL_STATUS_IDLE;
@VisibleForTesting
protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter;
@@ -2680,7 +2687,7 @@ public class ChooserActivity extends ResolverActivity implements
offset = Math.min(offset, minHeight);
}
} else {
- ViewGroup currentEmptyStateView = getCurrentEmptyStateView();
+ ViewGroup currentEmptyStateView = getActiveEmptyStateView();
if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
offset += currentEmptyStateView.getHeight();
}
@@ -2705,7 +2712,7 @@ public class ChooserActivity extends ResolverActivity implements
return -1;
}
- private ViewGroup getCurrentEmptyStateView() {
+ private ViewGroup getActiveEmptyStateView() {
int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage();
return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView();
}
@@ -2822,10 +2829,20 @@ public class ChooserActivity extends ResolverActivity implements
final float defaultElevation = elevatedView.getElevation();
final float chooserHeaderScrollElevation =
getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
-
mChooserMultiProfilePagerAdapter.getActiveAdapterView().addOnScrollListener(
new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView view, int scrollState) {
+ if (scrollState == RecyclerView.SCROLL_STATE_IDLE) {
+ if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+ mScrollStatus = SCROLL_STATUS_IDLE;
+ setHorizontalScrollingEnabled(true);
+ }
+ } else if (scrollState == RecyclerView.SCROLL_STATE_DRAGGING) {
+ if (mScrollStatus == SCROLL_STATUS_IDLE) {
+ mScrollStatus = SCROLL_STATUS_SCROLLING_VERTICAL;
+ setHorizontalScrollingEnabled(false);
+ }
+ }
}
public void onScrolled(RecyclerView view, int dx, int dy) {
@@ -3026,8 +3043,42 @@ public class ChooserActivity extends ResolverActivity implements
currentRootAdapter.updateDirectShareExpansion();
}
- void prepareIntentForCrossProfileLaunch(Intent intent) {
- intent.fixUris(UserHandle.myUserId());
+ @Override
+ protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ if (shouldShowTabs()) {
+ mChooserMultiProfilePagerAdapter
+ .setEmptyStateBottomOffset(insets.getSystemWindowInsetBottom());
+ mChooserMultiProfilePagerAdapter.setupContainerPadding(
+ getActiveEmptyStateView().findViewById(R.id.resolver_empty_state_container));
+ }
+ return super.onApplyWindowInsets(v, insets);
+ }
+
+ private void setHorizontalScrollingEnabled(boolean enabled) {
+ ResolverViewPager viewPager = findViewById(R.id.profile_pager);
+ viewPager.setSwipingEnabled(enabled);
+ }
+
+ private void setVerticalScrollEnabled(boolean enabled) {
+ ChooserGridLayoutManager layoutManager =
+ (ChooserGridLayoutManager) mChooserMultiProfilePagerAdapter.getActiveAdapterView()
+ .getLayoutManager();
+ layoutManager.setVerticalScrollEnabled(enabled);
+ }
+
+ @Override
+ void onHorizontalSwipeStateChanged(int state) {
+ if (state == ViewPager.SCROLL_STATE_DRAGGING) {
+ if (mScrollStatus == SCROLL_STATUS_IDLE) {
+ mScrollStatus = SCROLL_STATUS_SCROLLING_HORIZONTAL;
+ setVerticalScrollEnabled(false);
+ }
+ } else if (state == ViewPager.SCROLL_STATE_IDLE) {
+ if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+ mScrollStatus = SCROLL_STATUS_IDLE;
+ setVerticalScrollEnabled(true);
+ }
+ }
}
/**
diff --git a/core/java/com/android/internal/app/ChooserGridLayoutManager.java b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
index 317a987cf359..c50ebd9562c9 100644
--- a/core/java/com/android/internal/app/ChooserGridLayoutManager.java
+++ b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
@@ -28,6 +28,8 @@ import com.android.internal.widget.RecyclerView;
*/
public class ChooserGridLayoutManager extends GridLayoutManager {
+ private boolean mVerticalScrollEnabled = true;
+
/**
* Constructor used when layout manager is set in XML by RecyclerView attribute
* "layoutManager". If spanCount is not specified in the XML, it defaults to a
@@ -67,4 +69,13 @@ public class ChooserGridLayoutManager extends GridLayoutManager {
// Do not count the footer view in the official count
return super.getRowCountForAccessibility(recycler, state) - 1;
}
+
+ void setVerticalScrollEnabled(boolean verticalScrollEnabled) {
+ mVerticalScrollEnabled = verticalScrollEnabled;
+ }
+
+ @Override
+ public boolean canScrollVertically() {
+ return mVerticalScrollEnabled && super.canScrollVertically();
+ }
}
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 774be3c9c4b8..ffa6041721c6 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -38,6 +38,7 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
private final ChooserProfileDescriptor[] mItems;
private final boolean mIsSendAction;
+ private int mBottomOffset;
ChooserMultiProfilePagerAdapter(Context context,
ChooserActivity.ChooserGridAdapter adapter,
@@ -245,6 +246,16 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
}
}
+ void setEmptyStateBottomOffset(int bottomOffset) {
+ mBottomOffset = bottomOffset;
+ }
+
+ @Override
+ protected void setupContainerPadding(View container) {
+ container.setPadding(container.getPaddingLeft(), container.getPaddingTop(),
+ container.getPaddingRight(), container.getPaddingBottom() + mBottomOffset);
+ }
+
class ChooserProfileDescriptor extends ProfileDescriptor {
private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index e65d1fe9ce53..61a52bcc03f9 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -18,6 +18,7 @@ package com.android.internal.app;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+import static com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER;
import static com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE;
import android.annotation.Nullable;
@@ -246,6 +247,7 @@ public class IntentForwarderActivity extends Activity {
int selectedProfile = findSelectedProfile(className);
sanitizeIntent(intentReceived);
intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile);
+ intentReceived.putExtra(EXTRA_CALLING_USER, UserHandle.of(callingUserId));
startActivityAsCaller(intentReceived, null, null, false, userId);
finish();
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f96f560fc60f..f8eec57bbd6b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -184,6 +184,18 @@ public class ResolverActivity extends Activity implements
static final String EXTRA_SELECTED_PROFILE =
"com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE";
+ /**
+ * {@link UserHandle} extra to indicate the user of the user that the starting intent
+ * originated from.
+ * <p>This is not necessarily the same as {@link #getUserId()} or {@link UserHandle#myUserId()},
+ * as there are edge cases when the intent resolver is launched in the other profile.
+ * For example, when we have 0 resolved apps in current profile and multiple resolved
+ * apps in the other profile, opening a link from the current profile launches the intent
+ * resolver in the other one. b/148536209 for more info.
+ */
+ static final String EXTRA_CALLING_USER =
+ "com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER";
+
static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
@@ -470,17 +482,20 @@ public class ResolverActivity extends Activity implements
// the intent resolver is started in the other profile. Since this is the only case when
// this happens, we check for it here and set the current profile's tab.
int selectedProfile = getCurrentProfile();
- UserHandle intentUser = UserHandle.of(getLaunchingUserId());
+ UserHandle intentUser = getIntent().hasExtra(EXTRA_CALLING_USER)
+ ? getIntent().getParcelableExtra(EXTRA_CALLING_USER)
+ : getUser();
if (!getUser().equals(intentUser)) {
if (getPersonalProfileUserHandle().equals(intentUser)) {
selectedProfile = PROFILE_PERSONAL;
} else if (getWorkProfileUserHandle().equals(intentUser)) {
selectedProfile = PROFILE_WORK;
}
- }
- int selectedProfileExtra = getSelectedProfileExtra();
- if (selectedProfileExtra != -1) {
- selectedProfile = selectedProfileExtra;
+ } else {
+ int selectedProfileExtra = getSelectedProfileExtra();
+ if (selectedProfileExtra != -1) {
+ selectedProfile = selectedProfileExtra;
+ }
}
// We only show the default app for the profile of the current user. The filterLastUsed
// flag determines whether to show a default app and that app is not shown in the
@@ -535,22 +550,6 @@ public class ResolverActivity extends Activity implements
return selectedProfile;
}
- /**
- * Returns the user id of the user that the starting intent originated from.
- * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()},
- * as there are edge cases when the intent resolver is launched in the other profile.
- * For example, when we have 0 resolved apps in current profile and multiple resolved apps
- * in the other profile, opening a link from the current profile launches the intent resolver
- * in the other one. b/148536209 for more info.
- */
- private int getLaunchingUserId() {
- int contentUserHint = getIntent().getContentUserHint();
- if (contentUserHint == UserHandle.USER_CURRENT) {
- return UserHandle.myUserId();
- }
- return contentUserHint;
- }
-
protected @Profile int getCurrentProfile() {
return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK);
}
@@ -1250,7 +1249,9 @@ public class ResolverActivity extends Activity implements
return true;
}
- void prepareIntentForCrossProfileLaunch(Intent intent) {}
+ private void prepareIntentForCrossProfileLaunch(Intent intent) {
+ intent.fixUris(UserHandle.myUserId());
+ }
private boolean isLaunchingTargetInOtherProfile() {
return mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
@@ -1653,10 +1654,18 @@ public class ResolverActivity extends Activity implements
viewPager.setVisibility(View.VISIBLE);
tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
mMultiProfilePagerAdapter.setOnProfileSelectedListener(
- index -> {
- tabHost.setCurrentTab(index);
- resetButtonBar();
- resetCheckedItem();
+ new AbstractMultiProfilePagerAdapter.OnProfileSelectedListener() {
+ @Override
+ public void onProfileSelected(int index) {
+ tabHost.setCurrentTab(index);
+ resetButtonBar();
+ resetCheckedItem();
+ }
+
+ @Override
+ public void onProfilePageStateChanged(int state) {
+ onHorizontalSwipeStateChanged(state);
+ }
});
mMultiProfilePagerAdapter.setOnSwitchOnWorkSelectedListener(
() -> {
@@ -1668,6 +1677,8 @@ public class ResolverActivity extends Activity implements
findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
}
+ void onHorizontalSwipeStateChanged(int state) {}
+
private void maybeHideDivider() {
if (!isIntentPicker()) {
return;
diff --git a/core/java/com/android/internal/app/ResolverViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index 4eb6e3bd2071..9cdfc2f5c763 100644
--- a/core/java/com/android/internal/app/ResolverViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -18,6 +18,7 @@ package com.android.internal.app;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import com.android.internal.widget.ViewPager;
@@ -30,6 +31,8 @@ import com.android.internal.widget.ViewPager;
*/
public class ResolverViewPager extends ViewPager {
+ private boolean mSwipingEnabled = true;
+
public ResolverViewPager(Context context) {
super(context);
}
@@ -70,4 +73,13 @@ public class ResolverViewPager extends ViewPager {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+
+ void setSwipingEnabled(boolean swipingEnabled) {
+ mSwipingEnabled = swipingEnabled;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return mSwipingEnabled && super.onInterceptTouchEvent(ev);
+ }
}
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
index 67ffd4d93404..5212265f6c8a 100644
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ b/core/java/com/android/internal/logging/UiEventLogger.java
@@ -60,4 +60,28 @@ public interface UiEventLogger {
*/
void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
@Nullable InstanceId instance);
+
+ /**
+ * Log an event with ranked-choice information along with package.
+ * Does nothing if event.getId() <= 0.
+ * @param event an enum implementing UiEventEnum interface.
+ * @param uid the uid of the relevant app, if known (0 otherwise).
+ * @param packageName the package name of the relevant app, if known (null otherwise).
+ * @param position the position picked.
+ */
+ void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
+ int position);
+
+ /**
+ * Log an event with ranked-choice information along with package and instance ID.
+ * Does nothing if event.getId() <= 0.
+ * @param event an enum implementing UiEventEnum interface.
+ * @param uid the uid of the relevant app, if known (0 otherwise).
+ * @param packageName the package name of the relevant app, if known (null otherwise).
+ * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
+ * logWithPosition().
+ * @param position the position picked.
+ */
+ void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
+ @Nullable String packageName, @Nullable InstanceId instance, int position);
}
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index 4d171ec8a3a8..c9156c13aae3 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -48,4 +48,31 @@ public class UiEventLoggerImpl implements UiEventLogger {
log(event, uid, packageName);
}
}
+
+ @Override
+ public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+ final int eventID = event.getId();
+ if (eventID > 0) {
+ FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+ /* event_id = 1 */ eventID,
+ /* package_name = 2 */ packageName,
+ /* instance_id = 3 */ 0,
+ /* position_picked = 4 */ position);
+ }
+ }
+
+ @Override
+ public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+ InstanceId instance, int position) {
+ final int eventID = event.getId();
+ if ((eventID > 0) && (instance != null)) {
+ FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+ /* event_id = 1 */ eventID,
+ /* package_name = 2 */ packageName,
+ /* instance_id = 3 */ instance.getId(),
+ /* position_picked = 4 */ position);
+ } else {
+ logWithPosition(event, uid, packageName, position);
+ }
+ }
}
diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
index 180ab0810f5b..2d09434807a6 100644
--- a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
+++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
@@ -35,13 +35,15 @@ public class UiEventLoggerFake implements UiEventLogger {
public final int eventId;
public final int uid;
public final String packageName;
- public final InstanceId instanceId; // Used only for WithInstanceId variant
+ public final InstanceId instanceId; // Used only for WithInstanceId variants
+ public final int position; // Used only for Position variants
FakeUiEvent(int eventId, int uid, String packageName) {
this.eventId = eventId;
this.uid = uid;
this.packageName = packageName;
this.instanceId = null;
+ this.position = 0;
}
FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId) {
@@ -49,6 +51,15 @@ public class UiEventLoggerFake implements UiEventLogger {
this.uid = uid;
this.packageName = packageName;
this.instanceId = instanceId;
+ this.position = 0;
+ }
+
+ FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId, int position) {
+ this.eventId = eventId;
+ this.uid = uid;
+ this.packageName = packageName;
+ this.instanceId = instanceId;
+ this.position = position;
}
}
@@ -92,4 +103,21 @@ public class UiEventLoggerFake implements UiEventLogger {
mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance));
}
}
+
+ @Override
+ public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+ final int eventId = event.getId();
+ if (eventId > 0) {
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName, null, position));
+ }
+ }
+
+ @Override
+ public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+ InstanceId instance, int position) {
+ final int eventId = event.getId();
+ if (eventId > 0) {
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance, position));
+ }
+ }
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index fc2005a31696..3d8cae8e74d0 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -526,8 +526,16 @@ static void UnsetChldSignalHandler() {
// Calls POSIX setgroups() using the int[] object as an argument.
// A nullptr argument is tolerated.
-static void SetGids(JNIEnv* env, jintArray managed_gids, fail_fn_t fail_fn) {
+static void SetGids(JNIEnv* env, jintArray managed_gids, jboolean is_child_zygote,
+ fail_fn_t fail_fn) {
if (managed_gids == nullptr) {
+ if (is_child_zygote) {
+ // For child zygotes like webview and app zygote, we want to clear out
+ // any supplemental groups the parent zygote had.
+ if (setgroups(0, NULL) == -1) {
+ fail_fn(CREATE_ERROR("Failed to remove supplementary groups for child zygote"));
+ }
+ }
return;
}
@@ -1665,7 +1673,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
}
}
- SetGids(env, gids, fail_fn);
+ SetGids(env, gids, is_child_zygote, fail_fn);
SetRLimits(env, rlimits, fail_fn);
if (need_pre_initialize_native_bridge) {
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index 23fcf6ebc2cc..787074ba494e 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -32,6 +32,7 @@ enum ApBand {
AP_BAND_UNKNOWN = 0;
AP_BAND_2GHZ = 1;
AP_BAND_5GHZ = 2;
+ AP_BAND_6GHZ = 3;
}
// Refer to definition in TelephonyManager.java.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fd8460f9c478..464a47002b17 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3656,7 +3656,8 @@
<p>The package installer v2 APIs are still a work in progress and we're
currently validating they work in all scenarios.
<p>Not for use by third-party applications.
- TODO(b/152310230): remove this permission once the APIs are confirmed to be sufficient.
+ TODO(b/152310230): use this permission to protect only Incremental installations
+ once the APIs are confirmed to be sufficient.
@hide
-->
<permission android:name="com.android.permission.USE_INSTALLER_V2"
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
new file mode 100644
index 000000000000..e74f30ee10a4
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright 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.
+//
+
+android_test {
+ name: "FrameworksCorePackageInstallerSessionsTests",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "frameworks-base-testutils",
+ "platform-test-annotations",
+ "testng",
+ "truth-prebuilt",
+ ],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "framework",
+ "framework-res",
+ ],
+
+ platform_apis: true,
+ sdk_version: "core_platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/PackageInstallerSessions/AndroidManifest.xml b/core/tests/PackageInstallerSessions/AndroidManifest.xml
new file mode 100644
index 000000000000..5b22d2b4f3e3
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.package_installer_sessions"
+ >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.coretests.package_installer_sessions"/>
+</manifest>
diff --git a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
new file mode 100644
index 000000000000..494c92a8aa3f
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
@@ -0,0 +1,188 @@
+/*
+ * 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 android.content.pm
+
+import android.content.Context
+import android.content.pm.PackageInstaller.SessionParams
+import android.platform.test.annotations.Presubmit
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.LargeTest
+import com.android.compatibility.common.util.ShellIdentityUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.testng.Assert.assertThrows
+import kotlin.random.Random
+
+/**
+ * For verifying public [PackageInstaller] session APIs. This differs from
+ * [com.android.server.pm.PackageInstallerSessionTest] in services because that mocks the session,
+ * whereas this test uses the installer on device.
+ */
+@Presubmit
+class PackageSessionTests {
+
+ companion object {
+ /**
+ * Permissions marked "hardRestricted" or "softRestricted" in core/res/AndroidManifest.xml.
+ */
+ private val RESTRICTED_PERMISSIONS = listOf(
+ "android.permission.SEND_SMS",
+ "android.permission.RECEIVE_SMS",
+ "android.permission.READ_SMS",
+ "android.permission.RECEIVE_WAP_PUSH",
+ "android.permission.RECEIVE_MMS",
+ "android.permission.READ_CELL_BROADCASTS",
+ "android.permission.ACCESS_BACKGROUND_LOCATION",
+ "android.permission.READ_CALL_LOG",
+ "android.permission.WRITE_CALL_LOG",
+ "android.permission.PROCESS_OUTGOING_CALLS"
+ )
+ }
+
+ private val context: Context = InstrumentationRegistry.getContext()
+
+ private val installer = context.packageManager.packageInstaller
+
+ @Before
+ @After
+ fun abandonAllSessions() {
+ installer.mySessions.asSequence()
+ .map { it.sessionId }
+ .forEach {
+ try {
+ installer.abandonSession(it)
+ } catch (ignored: Exception) {
+ // Querying for sessions checks by calling package name, but abandoning
+ // checks by UID, which won't match if this test failed to clean up
+ // on a previous install + run + uninstall, so ignore these failures.
+ }
+ }
+ }
+
+ @Test
+ fun truncateAppLabel() {
+ val longLabel = invalidAppLabel()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setAppLabel(longLabel)
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.appLabel)
+ .isEqualTo(longLabel.take(PackageItemInfo.MAX_SAFE_LABEL_LENGTH))
+ }
+ }
+
+ @Test
+ fun removeInvalidAppPackageName() {
+ val longName = invalidPackageName()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setAppPackageName(longName)
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.appPackageName)
+ .isEqualTo(null)
+ }
+ }
+
+ @Test
+ fun removeInvalidInstallerPackageName() {
+ val longName = invalidPackageName()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setInstallerPackageName(longName)
+ }
+
+ createSession(params) {
+ // If a custom installer name is dropped, it defaults to the caller
+ assertThat(installer.getSessionInfo(it)?.installerPackageName)
+ .isEqualTo(context.packageName)
+ }
+ }
+
+ @Test
+ fun truncateWhitelistPermissions() {
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setWhitelistedRestrictedPermissions(invalidPermissions())
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.whitelistedRestrictedPermissions!!)
+ .containsExactlyElementsIn(RESTRICTED_PERMISSIONS)
+ }
+ }
+
+ @LargeTest
+ @Test
+ fun allocateMaxSessionsWithPermission() {
+ ShellIdentityUtils.invokeWithShellPermissions {
+ repeat(1024) { createDummySession() }
+ assertThrows(IllegalStateException::class.java) { createDummySession() }
+ }
+ }
+
+ @LargeTest
+ @Test
+ fun allocateMaxSessionsNoPermission() {
+ repeat(50) { createDummySession() }
+ assertThrows(IllegalStateException::class.java) { createDummySession() }
+ }
+
+ private fun createDummySession() {
+ installer.createSession(SessionParams(SessionParams.MODE_FULL_INSTALL)
+ .apply {
+ setAppPackageName(invalidPackageName())
+ setAppLabel(invalidAppLabel())
+ setWhitelistedRestrictedPermissions(invalidPermissions())
+ })
+ }
+
+ private fun invalidPackageName(maxLength: Int = SessionParams.MAX_PACKAGE_NAME_LENGTH): String {
+ return (0 until (maxLength + 10))
+ .asSequence()
+ .mapIndexed { index, _ ->
+ // A package name needs at least one separator
+ if (index == 2) {
+ '.'
+ } else {
+ Random.nextInt('z' - 'a').toChar() + 'a'.toInt()
+ }
+ }
+ .joinToString(separator = "")
+ }
+
+ private fun invalidAppLabel() = (0 until PackageItemInfo.MAX_SAFE_LABEL_LENGTH + 10)
+ .asSequence()
+ .map { Random.nextInt(Char.MAX_VALUE.toInt()).toChar() }
+ .joinToString(separator = "")
+
+ private fun invalidPermissions() = RESTRICTED_PERMISSIONS.toMutableSet()
+ .apply {
+ // Add some invalid permission names
+ repeat(10) { add(invalidPackageName(300)) }
+ }
+
+ private fun createSession(params: SessionParams, block: (Int) -> Unit = {}) {
+ val sessionId = installer.createSession(params)
+ try {
+ block(sessionId)
+ } finally {
+ installer.abandonSession(sessionId)
+ }
+ }
+}
diff --git a/data/keyboards/Vendor_045e_Product_0b12.kl b/data/keyboards/Vendor_045e_Product_0b12.kl
new file mode 100644
index 000000000000..0b44c7434af2
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_0b12.kl
@@ -0,0 +1,59 @@
+# 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.
+
+#
+# XBox USB Controller
+#
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+
+# Two overlapping rectangles
+key 314 BUTTON_SELECT
+
+# The branded "X" button in the center of the controller
+key 316 BUTTON_MODE
+
+# Three parallel horizontal lines (hamburger menu)
+key 315 BUTTON_START
+
+#Button below the "X" button
+key 167 MEDIA_RECORD
+
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 2a715d0c3494..93174983b116 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -29,9 +29,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="20dp"
+ android:gravity="center"
+ android:layoutDirection="ltr"
android:paddingEnd="20dp"
- android:gravity="center">
+ android:paddingStart="20dp">
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/home"
@@ -135,9 +136,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="@dimen/car_keyline_1"
- android:paddingEnd="@dimen/car_keyline_1"
android:gravity="center"
+ android:layoutDirection="ltr"
+ android:paddingEnd="@dimen/car_keyline_1"
+ android:paddingStart="@dimen/car_keyline_1"
android:visibility="gone"
/>
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 60e0d7e430df..cdc29eec21cd 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -27,7 +27,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1">
+ android:layout_weight="1"
+ android:layoutDirection="ltr">
<FrameLayout
android:id="@+id/left_hvac_container"
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index d039c9f646df..1b5062efa23e 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -140,8 +140,8 @@
<string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Адкрытая сетка"</string>
<string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Бяспечная сетка"</string>
<string name="process_kernel_label" msgid="950292573930336765">"АС Android"</string>
- <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя прыкладанні"</string>
- <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя прыкладанні і карыстальнiкi"</string>
+ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя праграмы"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя праграмы і карыстальнiкi"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Абнаўленні сістэмы"</string>
<string name="tether_settings_title_usb" msgid="3728686573430917722">"USB-мадэм"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Партатыўны хот-спот"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 65f456e20e4e..d003ef0b9c71 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -449,7 +449,7 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
- <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiiresti laadimine"</string>
+ <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Aeglaselt laadimine"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Vooluvõrgus, praegu ei saa laadida"</string>
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index b34822291815..803b0c61e6da 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -52,39 +52,20 @@
android:gravity="center_vertical"
android:layout_alignEnd="@id/conversation_icon"
android:layout_toEndOf="@id/conversation_icon">
- <LinearLayout
+ <TextView
+ android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannel"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/parent_channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannel"/>
-
- </LinearLayout>
+ android:ellipsize="end"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
<TextView
- android:id="@+id/pkg_name"
+ android:id="@+id/parent_channel_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
android:ellipsize="end"
android:textDirection="locale"
- android:maxLines="1"/>
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
<TextView
android:id="@+id/group_name"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
index c27b3a9b3bf4..bf2eac3c8ff3 100644
--- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
+++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
@@ -38,157 +38,67 @@
android:background="@drawable/rounded_bg_full"
>
- <!-- We have a known number of rows that can be shown; just design them all here -->
- <LinearLayout
- android:id="@+id/show_at_top_tip"
+ <ImageView
+ android:id="@+id/conversation_icon"
+ android:layout_width="@dimen/notification_guts_conversation_icon_size"
+ android:layout_height="@dimen/notification_guts_conversation_icon_size"
+ android:layout_gravity="center_horizontal" />
+
+ <TextView
+ android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
- <ImageView
- android:id="@+id/bell_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_notifications_alert"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/show_at_top_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_show_at_top_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/show_avatar_tip"
+ android:gravity="center_horizontal"
+ android:layout_marginTop="16dp"
+ android:text="@string/priority_onboarding_title"
+ style="@style/TextAppearance.NotificationImportanceChannel"
+ />
+
+ <View
+ android:id="@+id/divider"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
- <ImageView
- android:id="@+id/avatar_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_person"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/avatar_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_show_avatar_text"
- style="@style/TextAppearance.NotificationInfo"
- />
+ android:layout_height="0.5dp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="20dp"
+ android:background="@color/material_grey_300" />
- </LinearLayout>
-
- <!-- These rows show optionally -->
-
- <LinearLayout
- android:id="@+id/floating_bubble_tip"
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
-
- <ImageView
- android:id="@+id/bubble_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_create_bubble"
- android:tint="?android:attr/colorControlNormal" />
+ android:gravity="start"
+ android:text="@string/priority_onboarding_behavior"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ />
- <TextView
- android:id="@+id/bubble_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_appear_as_bubble_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/ignore_dnd_tip"
+ <TextView
+ android:id="@+id/behaviors"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
-
- <ImageView
- android:id="@+id/dnd_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/moon"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/dnd_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_ignores_dnd_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
+ android:gravity="start"
+ android:layout_marginTop="8dp"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ />
<!-- Bottom button container -->
<RelativeLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
+ android:layout_marginTop="32dp"
android:orientation="horizontal"
>
<TextView
+ android:id="@+id/settings_button"
+ android:text="@string/priority_onboarding_settings_button_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:gravity="start|center_vertical"
+ android:minWidth="@dimen/notification_importance_toggle_size"
+ android:minHeight="@dimen/notification_importance_toggle_size"
+ android:maxWidth="125dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
android:id="@+id/done_button"
android:text="@string/priority_onboarding_done_button_title"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
index af6f9bb827f6..0c4d5a26f95b 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
@@ -16,21 +16,20 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+ android:layout_width="250dp"
android:layout_height="48dp"
android:orientation="vertical"
- android:padding="10dp"
- android:layout_weight="1">
+ android:padding="13dp">
<TextView
android:id="@+id/screen_recording_dialog_source_text"
- android:layout_width="match_parent"
+ android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<TextView
android:id="@+id/screen_recording_dialog_source_description"
- android:layout_width="wrap_content"
+ android:layout_width="250dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
diff --git a/packages/SystemUI/res/values-sw320dp/dimens.xml b/packages/SystemUI/res/values-sw320dp/dimens.xml
deleted file mode 100644
index c110113e91f4..000000000000
--- a/packages/SystemUI/res/values-sw320dp/dimens.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-<resources>
- <!-- Global actions grid -->
- <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
- <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
-
- <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
- <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
- <dimen name="global_actions_grid_item_width">64dp</dimen>
- <dimen name="global_actions_grid_item_height">64dp</dimen>
-
- <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
- <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
- <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
-
- <!-- Home Controls -->
- <dimen name="global_actions_side_margin">10dp</dimen>
-</resources>
-
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e26f31cdf5ad..c46460853683 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -224,6 +224,7 @@
<dimen name="notification_guts_conversation_icon_size">56dp</dimen>
<dimen name="notification_guts_conversation_action_height">56dp</dimen>
<dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
+ <dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
@@ -1031,8 +1032,23 @@
<dimen name="global_actions_grid_container_shadow_offset">20dp</dimen>
<dimen name="global_actions_grid_container_negative_shadow_offset">-20dp</dimen>
+ <!-- Global actions grid -->
+ <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
+ <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
+
+ <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
+ <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
+ <dimen name="global_actions_grid_item_width">64dp</dimen>
+ <dimen name="global_actions_grid_item_height">64dp</dimen>
+
+ <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
+ <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
+ <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
+ <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
+ <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
+
<!-- Margins at the left and right of the power menu and home controls widgets. -->
- <dimen name="global_actions_side_margin">16dp</dimen>
+ <dimen name="global_actions_side_margin">10dp</dimen>
<!-- Amount to shift the layout when exiting/entering for controls activities -->
<dimen name="global_actions_controls_y_translation">20dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 97a0d032c4a7..39237ac246eb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2667,6 +2667,11 @@
<string name="inattentive_sleep_warning_title">Standby</string>
<!-- Priority conversation onboarding screen -->
+ <!-- title of priority onboarding [CHAR LIMIT=75] -->
+ <string name="priority_onboarding_title">Conversation set to priority</string>
+ <!-- Text explaining that the following actions are the behaviors of priority conversations.
+ E.g. priority conversations will show at the top of the conversation section [CHAR LIMIT=75] -->
+ <string name="priority_onboarding_behavior">Priority conversations will:</string>
<!-- Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=75] -->
<string name="priority_onboarding_show_at_top_text">Show at top of conversation section</string>
<!-- Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=75] -->
@@ -2677,6 +2682,8 @@
<string name="priority_onboarding_ignores_dnd_text">Interrupt Do Not Disturb</string>
<!-- Title for the affirmative button [CHAR LIMIT=50] -->
<string name="priority_onboarding_done_button_title">Got it</string>
+ <!-- Title for the settings button button [CHAR LIMIT=50] -->
+ <string name="priority_onboarding_settings_button_title">Settings</string>
<!-- Window Magnification strings -->
<!-- Title for Magnification Overlay Window [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
new file mode 100644
index 000000000000..b79fcbd43972
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
@@ -0,0 +1,86 @@
+/*
+ * 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.systemui.shared.recents.utilities;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.ParcelableColorSpace;
+import android.hardware.HardwareBuffer;
+import android.os.Bundle;
+
+import java.util.Objects;
+
+/**
+ * Utils for working with Bitmaps.
+ */
+public final class BitmapUtil {
+ private static final String KEY_BUFFER = "bitmap_util_buffer";
+ private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
+
+ private BitmapUtil(){ }
+
+ /**
+ * Creates a Bundle that represents the given Bitmap.
+ * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
+ * copies when passing across processes, only pass to processes you trust.
+ *
+ * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
+ * returned Bundle should be treated as a standalone object.
+ *
+ * @param bitmap to convert to bundle
+ * @return a Bundle representing the bitmap, should only be parsed by
+ * {@link #bundleToHardwareBitmap(Bundle)}
+ */
+ public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
+ if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
+ throw new IllegalArgumentException(
+ "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
+ }
+
+ // Bitmap assumes SRGB for null color space
+ ParcelableColorSpace colorSpace =
+ bitmap.getColorSpace() == null
+ ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
+ : new ParcelableColorSpace(bitmap.getColorSpace());
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
+ bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
+
+ return bundle;
+ }
+
+ /**
+ * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
+ *
+ * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
+ * Bitmap on to any other source.
+ *
+ * @param bundle containing the bitmap
+ * @return a hardware Bitmap
+ */
+ public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
+ if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
+ throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
+ }
+
+ HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
+ ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+
+ return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer), colorSpace);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index dd613263e5c2..73783ae7ece2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -15,6 +15,7 @@
*/
package com.android.systemui.shared.system;
+import android.graphics.HardwareRenderer;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewRootImpl;
@@ -50,7 +51,13 @@ public class ViewRootImplCompat {
public void registerRtFrameCallback(LongConsumer callback) {
if (mViewRoot != null) {
- mViewRoot.registerRtFrameCallback(callback::accept);
+ mViewRoot.registerRtFrameCallback(
+ new HardwareRenderer.FrameDrawingCallback() {
+ @Override
+ public void onFrameDraw(long l) {
+ callback.accept(l);
+ }
+ });
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 87990cd3bffa..ccb506de6d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -124,7 +124,7 @@ public final class Prefs {
String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
/** Tracks whether the user has seen the onboarding screen for priority conversations */
- String HAS_SEEN_PRIORITY_ONBOARDING = "HasSeenPriorityOnboarding";
+ String HAS_SEEN_PRIORITY_ONBOARDING = "HaveShownPriorityOnboarding";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index fd9fda3662a3..93f0c7f41ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -44,6 +44,7 @@ import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
+import com.android.systemui.globalactions.GlobalActionsDialog
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -79,6 +80,7 @@ class ControlsControllerImpl @Inject constructor (
}
private var userChanging: Boolean = true
+ private var userStructure: UserStructure
private var seedingInProgress = false
private val seedingCallbacks = mutableListOf<Consumer<Boolean>>()
@@ -97,7 +99,7 @@ class ControlsControllerImpl @Inject constructor (
internal var auxiliaryPersistenceWrapper: AuxiliaryPersistenceWrapper
init {
- val userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser)
persistenceWrapper = optionalWrapper.orElseGet {
ControlsFavoritePersistenceWrapper(
@@ -116,7 +118,7 @@ class ControlsControllerImpl @Inject constructor (
private fun setValuesForUser(newUser: UserHandle) {
Log.d(TAG, "Changing to user: $newUser")
currentUser = newUser
- val userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser)
persistenceWrapper.changeFileAndBackupManager(
userStructure.file,
BackupManager(userStructure.userContext)
@@ -192,6 +194,16 @@ class ControlsControllerImpl @Inject constructor (
it.componentName
}.toSet()
+ // When a component is uninstalled, allow seeding to happen again if the user
+ // reinstalls the app
+ val prefs = userStructure.userContext.getSharedPreferences(
+ GlobalActionsDialog.PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
+ val completedSeedingPackageSet = prefs.getStringSet(
+ GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
+ val favoritePackageSet = favoriteComponentSet.map { it.packageName }
+ prefs.edit().putStringSet(GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED,
+ completedSeedingPackageSet.intersect(favoritePackageSet)).apply()
+
var changed = false
favoriteComponentSet.subtract(serviceInfoSet).forEach {
changed = true
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 35ebac5b1ed5..d31b6eb9d857 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -129,7 +129,10 @@ class ControlsUiControllerImpl @Inject constructor (
SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName)
}
uiExecutor.execute {
- onResult(lastItems)
+ parent.removeAllViews()
+ if (lastItems.size > 0) {
+ onResult(lastItems)
+ }
}
}
}
@@ -189,8 +192,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showSeedingView(items: List<SelectionItem>) {
- parent.removeAllViews()
-
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
@@ -198,8 +199,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showInitialSetupView(items: List<SelectionItem>) {
- parent.removeAllViews()
-
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
@@ -263,7 +262,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showControlsView(items: List<SelectionItem>) {
- parent.removeAllViews()
controlViewsById.clear()
createListView()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index f97015282222..9ec14523a809 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -64,6 +64,10 @@ class DetailDialog(
}
override fun onActivityViewDestroyed(view: ActivityView) {}
+
+ override fun onTaskRemovalStarted(taskId: Int) {
+ dismiss()
+ }
}
init {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 0ec4cc555b9d..4003f41b33dc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -268,7 +268,7 @@ class ToggleRangeBehavior : Behavior {
private fun format(primaryFormat: String, backupFormat: String, value: Float): String {
return try {
- String.format(primaryFormat, value)
+ String.format(primaryFormat, findNearestStep(value))
} catch (e: IllegalFormatException) {
Log.w(ControlsUiController.TAG, "Illegal format in range template", e)
if (backupFormat == "") {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 95a9006c854a..951dc9936e1c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -71,7 +71,7 @@ public class DozeFactory {
DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
ProximitySensor proximitySensor,
DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler,
- DelayableExecutor delayableExecutor,
+ @Main DelayableExecutor delayableExecutor,
BiometricUnlockController biometricUnlockController,
BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
mFalsingManager = falsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 1b13d4a49fec..7e009b459ede 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -183,8 +183,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
- private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
- private static final String PREFS_CONTROLS_FILE = "controls_prefs";
+ public static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
+ public static final String PREFS_CONTROLS_FILE = "controls_prefs";
private static final int SEEDING_MAX = 2;
private final Context mContext;
@@ -391,7 +391,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
if (controlsComponent.getControlsListingController().isPresent()) {
controlsComponent.getControlsListingController().get()
- .addCallback(list -> mControlsServiceInfos = list);
+ .addCallback(list -> {
+ mControlsServiceInfos = list;
+ // This callback may occur after the dialog has been shown.
+ // If so, add controls into the already visible space
+ if (mDialog != null && !mDialog.isShowingControls()
+ && shouldShowControls()) {
+ mDialog.showControls(mControlsUiControllerOptional.get());
+ }
+ });
}
// Need to be user-specific with the context to make sure we read the correct prefs
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index b272b60f3593..bfdd5c8bcbd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -64,10 +64,12 @@ import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActiv
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipUI;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -83,8 +85,6 @@ import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -101,8 +101,9 @@ import dagger.Lazy;
* Class to send information from overview to launcher with a binder.
*/
@Singleton
-public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
- NavigationModeController.ModeChangedListener, Dumpable {
+public class OverviewProxyService extends CurrentUserTracker implements
+ CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener,
+ Dumpable {
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
@@ -123,7 +124,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private final NotificationShadeWindowController mStatusBarWinController;
private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
private final ComponentName mRecentsComponentName;
- private final DeviceProvisionedController mDeviceProvisionedController;
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
private final ScreenshotHelper mScreenshotHelper;
@@ -480,7 +480,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
return;
}
- mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
+ mCurrentBoundedUserId = getCurrentUserId();
mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
Bundle params = new Bundle();
@@ -523,22 +523,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
};
- private final DeviceProvisionedListener mDeviceProvisionedCallback =
- new DeviceProvisionedListener() {
- @Override
- public void onUserSetupChanged() {
- if (mDeviceProvisionedController.isCurrentUserSetup()) {
- internalConnectToCurrentUser();
- }
- }
-
- @Override
- public void onUserSwitched() {
- mConnectionBackoffAttempts = 0;
- internalConnectToCurrentUser();
- }
- };
-
private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
// This is the death handler for the binder from the launcher service
@@ -548,18 +532,18 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
- DeviceProvisionedController provisionController,
NavigationBarController navBarController, NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
PipUI pipUI, Optional<Divider> dividerOptional,
- Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
+ Optional<Lazy<StatusBar>> statusBarOptionalLazy,
+ BroadcastDispatcher broadcastDispatcher) {
+ super(broadcastDispatcher);
mContext = context;
mPipUI = pipUI;
mStatusBarOptionalLazy = statusBarOptionalLazy;
mHandler = new Handler();
mNavBarController = navBarController;
mStatusBarWinController = statusBarWinController;
- mDeviceProvisionedController = provisionController;
mConnectionBackoffAttempts = 0;
mDividerOptional = dividerOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
@@ -580,7 +564,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// Listen for device provisioned/user setup
updateEnabledState();
- mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
+ startTracking();
// Listen for launcher package changes
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
@@ -604,6 +588,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
});
}
+ @Override
+ public void onUserSwitched(int newUserId) {
+ mConnectionBackoffAttempts = 0;
+ internalConnectToCurrentUser();
+ }
+
public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton,
boolean gestureSwipeLeft) {
try {
@@ -709,10 +699,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
disconnectFromLauncherService();
// If user has not setup yet or already connected, do not try to connect
- if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
- Log.v(TAG_OPS, "Cannot attempt connection, is setup "
- + mDeviceProvisionedController.isCurrentUserSetup() + ", is enabled "
- + isEnabled());
+ if (!isEnabled()) {
+ Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled());
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
@@ -722,7 +710,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
mBound = mContext.bindServiceAsUser(launcherServiceIntent,
mOverviewServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
- UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+ UserHandle.of(getCurrentUserId()));
} catch (SecurityException e) {
Log.e(TAG_OPS, "Unable to bind because of security error", e);
}
@@ -881,8 +869,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
pw.println(TAG_OPS + " state:");
pw.print(" recentsComponentName="); pw.println(mRecentsComponentName);
pw.print(" isConnected="); pw.println(mOverviewProxy != null);
- pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
- .isCurrentUserSetup());
pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
pw.print(" quickStepIntent="); pw.println(mQuickStepIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 960c50129a56..3e268f63d65e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -225,8 +225,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
res.getString(R.string.screenrecord_name));
String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
- ? res.getString(R.string.screenrecord_ongoing_screen_and_audio)
- : res.getString(R.string.screenrecord_ongoing_screen_only);
+ ? res.getString(R.string.screenrecord_ongoing_screen_only)
+ : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
mRecordingNotificationBuilder = new Notification.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_screenrecord)
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
index 752f4fddf24b..edbc3cfdece5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -38,6 +38,7 @@ import java.nio.ByteBuffer;
public class ScreenInternalAudioRecorder {
private static String TAG = "ScreenAudioRecorder";
private static final int TIMEOUT = 500;
+ private static final float MIC_VOLUME_SCALE = 1.4f;
private final Context mContext;
private AudioRecord mAudioRecord;
private AudioRecord mAudioRecordMic;
@@ -148,6 +149,10 @@ public class ScreenInternalAudioRecorder {
readShortsInternal = mAudioRecord.read(bufferInternal, 0,
bufferInternal.length);
readShortsMic = mAudioRecordMic.read(bufferMic, 0, bufferMic.length);
+
+ // modify the volume
+ bufferMic = scaleValues(bufferMic,
+ readShortsMic, MIC_VOLUME_SCALE);
readBytes = Math.min(readShortsInternal, readShortsMic) * 2;
buffer = addAndConvertBuffers(bufferInternal, readShortsInternal, bufferMic,
readShortsMic);
@@ -168,6 +173,19 @@ public class ScreenInternalAudioRecorder {
});
}
+ private short[] scaleValues(short[] buff, int len, float scale) {
+ for (int i = 0; i < len; i++) {
+ int oldValue = buff[i];
+ int newValue = (int) (buff[i] * scale);
+ if (newValue > Short.MAX_VALUE) {
+ newValue = Short.MAX_VALUE;
+ } else if (newValue < Short.MIN_VALUE) {
+ newValue = Short.MIN_VALUE;
+ }
+ buff[i] = (short) (newValue);
+ }
+ return buff;
+ }
private byte[] addAndConvertBuffers(short[] a1, int a1Limit, short[] a2, int a2Limit) {
int size = Math.max(a1Limit, a2Limit);
if (size < 0) return new byte[0];
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index c967648c544e..8551c88d133a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -55,9 +55,9 @@ import java.util.Date;
*/
public class ScreenMediaRecorder {
private static final int TOTAL_NUM_TRACKS = 1;
- private static final int VIDEO_BIT_RATE = 10000000;
private static final int VIDEO_FRAME_RATE = 30;
- private static final int AUDIO_BIT_RATE = 16;
+ private static final int VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO = 6;
+ private static final int AUDIO_BIT_RATE = 196000;
private static final int AUDIO_SAMPLE_RATE = 44100;
private static final int MAX_DURATION_MS = 60 * 60 * 1000;
private static final long MAX_FILESIZE_BYTES = 5000000000L;
@@ -108,7 +108,7 @@ public class ScreenMediaRecorder {
// Set up audio source
if (mAudioSource == MIC) {
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
}
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
@@ -121,10 +121,13 @@ public class ScreenMediaRecorder {
wm.getDefaultDisplay().getRealMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
+ int refereshRate = (int) wm.getDefaultDisplay().getRefreshRate();
+ int vidBitRate = screenHeight * screenWidth * refereshRate / VIDEO_FRAME_RATE
+ * VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO;
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoSize(screenWidth, screenHeight);
- mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
- mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
+ mMediaRecorder.setVideoFrameRate(refereshRate);
+ mMediaRecorder.setVideoEncodingBitRate(vidBitRate);
mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index abd7e7159260..d057a8a43c43 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -24,12 +24,9 @@ import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE;
import android.app.Activity;
import android.app.PendingIntent;
import android.os.Bundle;
-import android.util.Log;
import android.view.Gravity;
-import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
@@ -88,8 +85,8 @@ public class ScreenRecordDialog extends Activity {
});
mModes = new ArrayList<>();
- mModes.add(INTERNAL);
mModes.add(MIC);
+ mModes.add(INTERNAL);
mModes.add(MIC_AND_INTERNAL);
mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
index 2e0e746594b4..3e78489e5707 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
@@ -88,12 +88,6 @@ public class ScreenRecordingAdapter extends ArrayAdapter<ScreenRecordingAudioSou
return layout;
}
- private void setDescription(LinearLayout layout, int description) {
- if (description != Resources.ID_NULL) {
- ((TextView) layout.getChildAt(1)).setText(description);
- }
- }
-
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
switch (getItem(position)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index daa4ffe88b4f..e9d89589172e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -53,6 +53,7 @@ import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -115,6 +116,7 @@ public class NotificationConversationInfo extends LinearLayout implements
private OnSnoozeClickListener mOnSnoozeClickListener;
private OnSettingsClickListener mOnSettingsClickListener;
private NotificationGuts mGutsContainer;
+ private OnConversationSettingsClickListener mOnConversationSettingsClickListener;
@VisibleForTesting
boolean mSkipPost = false;
@@ -164,6 +166,10 @@ public class NotificationConversationInfo extends LinearLayout implements
private OnClickListener mOnDone = v -> {
mPressedApply = true;
+ // If the user selected Priority, maybe show the priority onboarding
+ if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
+ showPriorityOnboarding();
+ }
mGutsContainer.closeControls(v, true);
};
@@ -175,6 +181,10 @@ public class NotificationConversationInfo extends LinearLayout implements
void onClick(View v, NotificationChannel channel, int appUid);
}
+ public interface OnConversationSettingsClickListener {
+ void onClick();
+ }
+
public interface OnAppSettingsClickListener {
void onClick(View v, Intent intent);
}
@@ -190,14 +200,6 @@ public class NotificationConversationInfo extends LinearLayout implements
}
mSelectedAction = selectedAction;
- onSelectedActionChanged();
- }
-
- private void onSelectedActionChanged() {
- // If the user selected Priority, maybe show the priority onboarding
- if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
- showPriorityOnboarding();
- }
}
public void bindNotification(
@@ -216,7 +218,8 @@ public class NotificationConversationInfo extends LinearLayout implements
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
boolean isDeviceProvisioned,
@Main Handler mainHandler,
- @Background Handler bgHandler) {
+ @Background Handler bgHandler,
+ OnConversationSettingsClickListener onConversationSettingsClickListener) {
mSelectedAction = -1;
mINotificationManager = iNotificationManager;
mVisualStabilityManager = visualStabilityManager;
@@ -231,6 +234,7 @@ public class NotificationConversationInfo extends LinearLayout implements
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mOnSnoozeClickListener = onSnoozeClickListener;
+ mOnConversationSettingsClickListener = onConversationSettingsClickListener;
mIconFactory = conversationIconFactory;
mUserContext = userContext;
mBubbleMetadata = bubbleMetadata;
@@ -323,7 +327,6 @@ public class NotificationConversationInfo extends LinearLayout implements
ImageView image = findViewById(R.id.conversation_icon);
image.setImageDrawable(mIconFactory.getConversationDrawable(
mShortcutInfo, mPackageName, mAppUid, important));
-
}
private void bindPackage() {
@@ -521,9 +524,9 @@ public class NotificationConversationInfo extends LinearLayout implements
boolean ignoreDnd = false;
try {
- ignoreDnd = (mINotificationManager
- .getConsolidatedNotificationPolicy().priorityConversationSenders
- & NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT) != 0;
+ ignoreDnd = mINotificationManager
+ .getConsolidatedNotificationPolicy().priorityConversationSenders ==
+ NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
} catch (RemoteException e) {
Log.e(TAG, "Could not check conversation senders", e);
}
@@ -538,6 +541,8 @@ public class NotificationConversationInfo extends LinearLayout implements
.setView(onboardingView)
.setIgnoresDnd(ignoreDnd)
.setShowsAsBubble(showAsBubble)
+ .setIcon(((ImageView) findViewById(R.id.conversation_icon)).getDrawable())
+ .setOnSettingsClick(mOnConversationSettingsClickListener)
.build();
controller.init();
@@ -613,8 +618,7 @@ public class NotificationConversationInfo extends LinearLayout implements
try {
switch (mAction) {
case ACTION_FAVORITE:
- mChannelToUpdate.setImportantConversation(
- !mChannelToUpdate.isImportantConversation());
+ mChannelToUpdate.setImportantConversation(true);
if (mChannelToUpdate.isImportantConversation()) {
mChannelToUpdate.setAllowBubbles(true);
if (mAppBubble == BUBBLE_PREFERENCE_NONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index a64dcdffff1e..1074adc3383d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -216,6 +216,11 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
}
}
+ private void startConversationSettingsActivity(int uid, ExpandableNotificationRow row) {
+ final Intent intent = new Intent(Settings.ACTION_CONVERSATION_SETTINGS);
+ mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
+ }
+
private boolean bindGuts(final ExpandableNotificationRow row) {
row.ensureGutsInflated();
return bindGuts(row, mGutsMenuItem);
@@ -438,6 +443,12 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mListContainer.getSwipeActionHelper().snooze(sbn, hours);
};
+ final NotificationConversationInfo.OnConversationSettingsClickListener
+ onConversationSettingsListener =
+ () -> {
+ startConversationSettingsActivity(sbn.getUid(), row);
+ };
+
if (!userHandle.equals(UserHandle.ALL)
|| mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
@@ -468,7 +479,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mBuilderProvider,
mDeviceProvisionedController.isDeviceProvisioned(),
mMainHandler,
- mBgHandler);
+ mBgHandler,
+ onConversationSettingsListener);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index 84bc181a77c4..f1fe54ad4024 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -241,7 +241,6 @@ public class PartialConversationInfo extends LinearLayout implements
} catch (PackageManager.NameNotFoundException e) {
mPkgIcon = mPm.getDefaultActivityIcon();
}
- ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
}
private void bindDelegate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
index d1b405256f39..88c325880241 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
@@ -21,19 +21,21 @@ import android.content.Context
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.text.SpannableStringBuilder
+import android.text.style.BulletSpan
import android.view.Gravity
import android.view.View
-import android.view.View.GONE
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.Window
import android.view.WindowInsets.Type.statusBars
import android.view.WindowManager
-import android.widget.LinearLayout
+import android.widget.ImageView
import android.widget.TextView
import com.android.systemui.Prefs
import com.android.systemui.R
-import java.lang.IllegalStateException
+import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener
import javax.inject.Inject
/**
@@ -43,7 +45,9 @@ class PriorityOnboardingDialogController @Inject constructor(
val view: View,
val context: Context,
val ignoresDnd: Boolean,
- val showsAsBubble: Boolean
+ val showsAsBubble: Boolean,
+ val icon : Drawable,
+ val onConversationSettingsClickListener : OnConversationSettingsClickListener
) {
private lateinit var dialog: Dialog
@@ -62,11 +66,21 @@ class PriorityOnboardingDialogController @Inject constructor(
dialog.dismiss()
}
+ private fun settings() {
+ // Log that the user has seen the onboarding
+ Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true)
+ dialog.dismiss()
+ onConversationSettingsClickListener?.onClick()
+ }
+
class Builder @Inject constructor() {
private lateinit var view: View
private lateinit var context: Context
private var ignoresDnd = false
private var showAsBubble = false
+ private lateinit var icon: Drawable
+ private lateinit var onConversationSettingsClickListener
+ : OnConversationSettingsClickListener
fun setView(v: View): Builder {
view = v
@@ -88,9 +102,20 @@ class PriorityOnboardingDialogController @Inject constructor(
return this
}
+ fun setIcon(draw : Drawable) : Builder {
+ icon = draw
+ return this
+ }
+
+ fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder {
+ onConversationSettingsClickListener = onClick
+ return this
+ }
+
fun build(): PriorityOnboardingDialogController {
val controller = PriorityOnboardingDialogController(
- view, context, ignoresDnd, showAsBubble)
+ view, context, ignoresDnd, showAsBubble, icon,
+ onConversationSettingsClickListener)
return controller
}
}
@@ -113,13 +138,32 @@ class PriorityOnboardingDialogController @Inject constructor(
done()
}
- if (!ignoresDnd) {
- findViewById<LinearLayout>(R.id.ignore_dnd_tip).visibility = GONE
+ findViewById<TextView>(R.id.settings_button)?.setOnClickListener {
+ settings()
}
- if (!showsAsBubble) {
- findViewById<LinearLayout>(R.id.floating_bubble_tip).visibility = GONE
+ findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon)
+
+ val gapWidth = dialog.context.getResources().getDimensionPixelSize(
+ R.dimen.conversation_onboarding_bullet_gap_width)
+ val description = SpannableStringBuilder()
+ description.append(context.getText(R.string.priority_onboarding_show_at_top_text),
+ BulletSpan(gapWidth), /* flags */0)
+ description.append(System.lineSeparator())
+ description.append(context.getText(R.string.priority_onboarding_show_avatar_text),
+ BulletSpan(gapWidth), /* flags */0)
+ if (showsAsBubble) {
+ description.append(System.lineSeparator())
+ description.append(context.getText(
+ R.string.priority_onboarding_appear_as_bubble_text),
+ BulletSpan(gapWidth), /* flags */0)
+ }
+ if (ignoresDnd) {
+ description.append(System.lineSeparator())
+ description.append(context.getText(R.string.priority_onboarding_ignores_dnd_text),
+ BulletSpan(gapWidth), /* flags */0)
}
+ findViewById<TextView>(R.id.behaviors).setText(description)
window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
@@ -129,7 +173,7 @@ class PriorityOnboardingDialogController @Inject constructor(
attributes = attributes.apply {
format = PixelFormat.TRANSLUCENT
- title = ChannelEditorDialogController::class.java.simpleName
+ title = PriorityOnboardingDialogController::class.java.simpleName
gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
fitInsetsTypes = attributes.fitInsetsTypes and statusBars().inv()
width = MATCH_PARENT
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 46c873db8a08..4337e20c0a39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -40,6 +40,7 @@ import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseRelativeLayout;
import com.android.systemui.statusbar.policy.KeyButtonView;
+import java.io.PrintWriter;
import java.util.Objects;
public class NavigationBarInflaterView extends FrameLayout
@@ -469,4 +470,10 @@ public class NavigationBarInflaterView extends FrameLayout
private static float convertDpToPx(Context context, float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
+
+ public void dump(PrintWriter pw) {
+ pw.println("NavigationBarInflaterView {");
+ pw.println(" mCurrentLayout: " + mCurrentLayout);
+ pw.println(" }");
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 2978772cac5e..6b37ac317cdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1198,6 +1198,9 @@ public class NavigationBarView extends FrameLayout implements
pw.println(" }");
+ if (mNavigationInflaterView != null) {
+ mNavigationInflaterView.dump(pw);
+ }
mContextualButtonGroup.dump(pw);
mRecentsOnboarding.dump(pw);
mRegionSamplingHelper.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f58cce58af74..76c51d61459a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -572,6 +572,9 @@ public class NotificationIconAreaController implements DarkReceiver,
.setInterpolator(Interpolators.LINEAR)
.setDuration(AOD_ICONS_APPEAR_DURATION)
.start();
+ } else {
+ mAodIcons.setAlpha(1.0f);
+ mAodIcons.setTranslationY(0);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index b1f67ce8a581..4122cf5466e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -256,7 +256,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon);
assertEquals(mIconDrawable, view.getDrawable());
}
@@ -280,7 +280,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -331,7 +331,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertTrue(textView.getText().toString().contains(group.getName()));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -356,7 +356,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
assertEquals(GONE, textView.getVisibility());
@@ -380,7 +380,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
}
@@ -415,7 +415,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(VISIBLE, nameView.getVisibility());
assertTrue(nameView.getText().toString().contains("Proxied"));
@@ -443,7 +443,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
@@ -469,7 +469,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -496,7 +496,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
false,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -521,7 +521,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.silence);
assertThat(view.isSelected()).isTrue();
}
@@ -549,7 +549,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -580,7 +580,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -610,7 +610,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -654,7 +654,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mTestableLooper.processAllMessages();
@@ -697,7 +697,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View silence = mNotificationInfo.findViewById(R.id.silence);
@@ -741,7 +741,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -778,7 +778,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -793,6 +793,45 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
}
@Test
+ public void testFavorite_thenDefaultThenFavorite_andSave_nothingChanged() throws Exception {
+ mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
+ mConversationChannel.setImportance(IMPORTANCE_HIGH);
+ mConversationChannel.setImportantConversation(true);
+
+ mNotificationInfo.bindNotification(
+ mShortcutManager,
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ mBubbleMetadata,
+ null,
+ null,
+ mIconFactory,
+ mContext,
+ mBuilderProvider,
+ true,
+ mTestHandler,
+ mTestHandler, null);
+
+ View fave = mNotificationInfo.findViewById(R.id.priority);
+ fave.performClick();
+ mNotificationInfo.findViewById(R.id.default_behavior).performClick();
+ fave.performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
+ mTestableLooper.processAllMessages();
+
+ ArgumentCaptor<NotificationChannel> captor =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), anyInt(), captor.capture());
+ assertEquals(IMPORTANCE_HIGH, captor.getValue().getImportance());
+ assertTrue(captor.getValue().isImportantConversation());
+ }
+
+ @Test
public void testDefault_andSave() throws Exception {
mConversationChannel.setAllowBubbles(true);
mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
@@ -813,7 +852,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -849,7 +888,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -885,7 +924,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -920,7 +959,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View silence = mNotificationInfo.findViewById(R.id.silence);
silence.performClick();
@@ -954,7 +993,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -979,7 +1018,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -1014,10 +1053,14 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+ verify(controller, never()).show();
+
+ // and then done
+ mNotificationInfo.findViewById(R.id.done).performClick();
// THEN the user is presented with the priority onboarding screen
verify(controller, atLeastOnce()).show();
@@ -1050,7 +1093,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index e56ef5b92f87..f327967ebd73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -161,25 +161,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
}
@Test
- public void testBindNotification_SetsTextApplicationName() throws Exception {
- when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
- mInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mChannelEditorDialogController,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- true,
- false);
- final TextView textView = mInfo.findViewById(R.id.pkg_name);
- assertTrue(textView.getText().toString().contains("App Name"));
- assertEquals(VISIBLE, mInfo.findViewById(R.id.header).getVisibility());
- }
-
- @Test
public void testBindNotification_SetsName() {
mInfo.bindNotification(
mMockPackageManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index be43e19cfc70..177e845bfead 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
@@ -56,6 +57,8 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
@Mock
NotificationMediaManager mNotificationMediaManager;
@Mock
+ NotificationIconContainer mNotificationIconContainer;
+ @Mock
DozeParameters mDozeParameters;
@Mock
NotificationShadeWindowView mNotificationShadeWindowView;
@@ -67,7 +70,7 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
when(mStatusBar.getNotificationShadeWindowView()).thenReturn(mNotificationShadeWindowView);
when(mNotificationShadeWindowView.findViewById(anyInt())).thenReturn(
- mock(NotificationIconContainer.class));
+ mNotificationIconContainer);
mController = new NotificationIconAreaController(mContext, mStatusBar,
mStatusBarStateController, mWakeUpCoordinator, mKeyguardBypassController,
@@ -87,4 +90,12 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
assertTrue(mController.shouldShouldLowPriorityIcons());
}
+
+ @Test
+ public void testAppearResetsTranslation() {
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
+ mController.appearAodIcons();
+ verify(mNotificationIconContainer).setTranslationY(0);
+ verify(mNotificationIconContainer).setAlpha(1.0f);
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1634f6e62897..0ab571854c72 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1374,10 +1374,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
return;
}
- String action = blocked ? "BLOCKED" : "UNBLOCKED";
- log(String.format("Blocked status changed to %s for %d(%d) on netId %d", blocked,
- nri.mUid, nri.request.requestId, net.netId));
- mNetworkInfoBlockingLogs.log(action + " " + nri.mUid);
+ final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ mNetworkInfoBlockingLogs.log(String.format(
+ "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.netId));
}
/**
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index efd3c3e9bfc1..27d9ba08e4a2 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1908,8 +1908,11 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#adjustVolume(int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller) {
+ boolean hasModifyAudioSettings =
+ mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED;
adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
- caller, Binder.getCallingUid(), hasModifyAudioSettings(), VOL_ADJUST_NORMAL);
+ caller, Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
}
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
@@ -2014,10 +2017,13 @@ public class AudioService extends IAudioService.Stub
+ "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
return;
}
+ final boolean hasModifyAudioSettings =
+ mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED;
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
direction/*val1*/, flags/*val2*/, callingPackage));
adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
- Binder.getCallingUid(), hasModifyAudioSettings(), VOL_ADJUST_NORMAL);
+ Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
}
protected void adjustStreamVolume(int streamType, int direction, int flags,
@@ -2528,10 +2534,13 @@ public class AudioService extends IAudioService.Stub
+ " MODIFY_AUDIO_ROUTING callingPackage=" + callingPackage);
return;
}
+ final boolean hasModifyAudioSettings =
+ mContext.checkCallingOrSelfPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED;
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
index/*val1*/, flags/*val2*/, callingPackage));
setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
- Binder.getCallingUid(), hasModifyAudioSettings());
+ Binder.getCallingUid(), hasModifyAudioSettings);
}
private boolean canChangeAccessibilityVolume() {
@@ -3197,7 +3206,8 @@ public class AudioService extends IAudioService.Stub
ensureValidStreamType(streamType);
final boolean isPrivileged =
Binder.getCallingUid() == Process.SYSTEM_UID
- || (hasModifyAudioSettings())
+ || (mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED)
|| (mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
== PackageManager.PERMISSION_GRANTED);
return (mStreamStates[streamType].getMinIndex(isPrivileged) + 5) / 10;
@@ -4755,18 +4765,9 @@ public class AudioService extends IAudioService.Stub
handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
}
- private boolean hasModifyAudioSettings() {
- return mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- private boolean hasModifyAudioSettings(int pid, int uid) {
- return mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
- == PackageManager.PERMISSION_GRANTED;
- }
-
boolean checkAudioSettingsPermission(String method) {
- if (hasModifyAudioSettings()) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED) {
return true;
}
String msg = "Audio Settings Permission Denial: " + method + " from pid="
@@ -7688,10 +7689,13 @@ public class AudioService extends IAudioService.Stub
@Override
public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
String callingPackage, int uid, int pid) {
+ final boolean hasModifyAudioSettings =
+ mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
// direction and stream type swap here because the public
// adjustSuggested has a different order than the other methods.
adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
- callingPackage, uid, hasModifyAudioSettings(pid, uid), VOL_ADJUST_NORMAL);
+ callingPackage, uid, hasModifyAudioSettings, VOL_ADJUST_NORMAL);
}
@Override
@@ -7702,15 +7706,21 @@ public class AudioService extends IAudioService.Stub
direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
.append(" uid:").append(uid).toString()));
}
+ final boolean hasModifyAudioSettings =
+ mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
adjustStreamVolume(streamType, direction, flags, callingPackage,
- callingPackage, uid, hasModifyAudioSettings(pid, uid), VOL_ADJUST_NORMAL);
+ callingPackage, uid, hasModifyAudioSettings, VOL_ADJUST_NORMAL);
}
@Override
public void setStreamVolumeForUid(int streamType, int direction, int flags,
String callingPackage, int uid, int pid) {
+ final boolean hasModifyAudioSettings =
+ mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
+ == PackageManager.PERMISSION_GRANTED;
setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid,
- hasModifyAudioSettings(pid, uid));
+ hasModifyAudioSettings);
}
@Override
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index ccbe96f30e04..067bdcb111fb 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -28,6 +28,9 @@ import static android.os.PowerManager.locationPowerSaveModeToString;
import static com.android.server.location.CallerIdentity.PERMISSION_COARSE;
import static com.android.server.location.CallerIdentity.PERMISSION_FINE;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@@ -64,6 +67,7 @@ import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -101,7 +105,7 @@ import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.CallerIdentity.PermissionLevel;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
-import com.android.server.location.UserInfoHelper.UserListener;
+import com.android.server.location.UserInfoHelper.UserListener.UserChange;
import com.android.server.location.gnss.GnssManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -132,11 +136,13 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
public static class Lifecycle extends SystemService {
+ private final UserInfoHelper mUserInfoHelper;
private final LocationManagerService mService;
public Lifecycle(Context context) {
super(context);
- mService = new LocationManagerService(context);
+ mUserInfoHelper = new SystemUserInfoHelper(context);
+ mService = new LocationManagerService(context, mUserInfoHelper);
}
@Override
@@ -161,6 +167,29 @@ public class LocationManagerService extends ILocationManager.Stub {
mService.onSystemThirdPartyAppsCanStart();
}
}
+
+ @Override
+ public void onUserStarting(TargetUser user) {
+ mUserInfoHelper.dispatchOnUserStarted(user.getUserIdentifier());
+ }
+
+ @Override
+ public void onUserSwitching(TargetUser from, TargetUser to) {
+ mUserInfoHelper.dispatchOnCurrentUserChanged(from.getUserIdentifier(),
+ to.getUserIdentifier());
+ }
+
+ @Override
+ public void onUserStopped(TargetUser user) {
+ mUserInfoHelper.dispatchOnUserStopped(user.getUserIdentifier());
+ }
+
+ private static class SystemUserInfoHelper extends UserInfoHelper {
+
+ SystemUserInfoHelper(Context context) {
+ super(context);
+ }
+ }
}
public static final String TAG = "LocationManagerService";
@@ -232,7 +261,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@PowerManager.LocationPowerSaveMode
private int mBatterySaverMode;
- private LocationManagerService(Context context) {
+ private LocationManagerService(Context context, UserInfoHelper userInfoHelper) {
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = FgThread.getHandler();
mLocalService = new LocalService();
@@ -240,7 +269,7 @@ public class LocationManagerService extends ILocationManager.Stub {
LocalServices.addService(LocationManagerInternal.class, mLocalService);
mAppOpsHelper = new AppOpsHelper(mContext);
- mUserInfoHelper = new UserInfoHelper(mContext);
+ mUserInfoHelper = userInfoHelper;
mSettingsHelper = new SettingsHelper(mContext, mHandler);
mAppForegroundHelper = new AppForegroundHelper(mContext);
mLocationUsageLogger = new LocationUsageLogger();
@@ -342,7 +371,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// initialize the current users. we would get the user started notifications for these
// users eventually anyways, but this takes care of it as early as possible.
for (int userId: mUserInfoHelper.getCurrentUserIds()) {
- onUserChanged(userId, UserListener.USER_STARTED);
+ onUserChanged(userId, USER_STARTED);
}
}
}
@@ -596,32 +625,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
+ private void onUserChanged(@UserIdInt int userId, @UserChange int change) {
switch (change) {
- case UserListener.USER_SWITCHED:
- if (D) {
- Log.d(TAG, "user " + userId + " current status changed");
- }
+ case CURRENT_USER_CHANGED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onEnabledChangedLocked(userId);
}
}
break;
- case UserListener.USER_STARTED:
- if (D) {
- Log.d(TAG, "user " + userId + " started");
- }
+ case USER_STARTED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onUserStarted(userId);
}
}
break;
- case UserListener.USER_STOPPED:
- if (D) {
- Log.d(TAG, "user " + userId + " stopped");
- }
+ case USER_STOPPED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onUserStopped(userId);
@@ -957,10 +977,22 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.increaseIndent();
// for now we only dump for the parent user
- int userId = mUserInfoHelper.getCurrentUserIds()[0];
- pw.println("last location=" + mLastLocation.get(userId));
- pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
- pw.println("enabled=" + isEnabled(userId));
+ int[] userIds = mUserInfoHelper.getCurrentUserIds();
+ if (userIds.length == 1) {
+ int userId = userIds[0];
+ pw.println("last location=" + mLastLocation.get(userId));
+ pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+ pw.println("enabled=" + isEnabled(userId));
+ } else {
+ for (int userId : userIds) {
+ pw.println("user " + userId + ":");
+ pw.increaseIndent();
+ pw.println("last location=" + mLastLocation.get(userId));
+ pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+ pw.println("enabled=" + isEnabled(userId));
+ pw.decreaseIndent();
+ }
+ }
}
mProvider.dump(fd, pw, args);
@@ -1666,6 +1698,9 @@ public class LocationManagerService extends ILocationManager.Stub {
* Note: must be constructed with lock held.
*/
private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
mProvider = provider;
mRealRequest = request;
@@ -1703,6 +1738,10 @@ public class LocationManagerService extends ILocationManager.Stub {
* Method to be called when a record will no longer be used.
*/
private void disposeLocked(boolean removeReceiver) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
CallerIdentity identity = mReceiver.mCallerIdentity;
mRequestStatistics.stopRequesting(identity.packageName, identity.featureId, mProvider);
diff --git a/services/core/java/com/android/server/location/UserInfoHelper.java b/services/core/java/com/android/server/location/UserInfoHelper.java
index a3dcc40bdf2d..53bff8eacb4c 100644
--- a/services/core/java/com/android/server/location/UserInfoHelper.java
+++ b/services/core/java/com/android/server/location/UserInfoHelper.java
@@ -20,48 +20,48 @@ import static android.os.UserManager.DISALLOW_SHARE_LOCATION;
import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
+import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Binder;
-import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
+import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Provides accessors and listeners for all user info.
*/
-public class UserInfoHelper {
+public abstract class UserInfoHelper {
/**
* Listener for current user changes.
*/
public interface UserListener {
- int USER_SWITCHED = 1;
+ int CURRENT_USER_CHANGED = 1;
int USER_STARTED = 2;
int USER_STOPPED = 3;
- @IntDef({USER_SWITCHED, USER_STARTED, USER_STOPPED})
+ @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED})
@Retention(RetentionPolicy.SOURCE)
@interface UserChange {}
@@ -75,143 +75,101 @@ public class UserInfoHelper {
private final CopyOnWriteArrayList<UserListener> mListeners;
@GuardedBy("this")
- @Nullable private UserManager mUserManager;
-
- @UserIdInt private volatile int mCurrentUserId;
-
+ @Nullable private ActivityManagerInternal mActivityManagerInternal;
@GuardedBy("this")
- @UserIdInt private int mCachedParentUserId;
- @GuardedBy("this")
- private int[] mCachedProfileUserIds;
+ @Nullable private UserManager mUserManager;
public UserInfoHelper(Context context) {
mContext = context;
mListeners = new CopyOnWriteArrayList<>();
-
- mCurrentUserId = UserHandle.USER_NULL;
- mCachedParentUserId = UserHandle.USER_NULL;
- mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
}
/** Called when system is ready. */
+ @CallSuper
public synchronized void onSystemReady() {
- if (mUserManager != null) {
+ if (mActivityManagerInternal != null) {
return;
}
+ mActivityManagerInternal = Objects.requireNonNull(
+ LocalServices.getService(ActivityManagerInternal.class));
mUserManager = mContext.getSystemService(UserManager.class);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- intentFilter.addAction(Intent.ACTION_USER_STARTED);
- intentFilter.addAction(Intent.ACTION_USER_STOPPED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action == null) {
- return;
- }
- int userId;
- switch (action) {
- case Intent.ACTION_USER_SWITCHED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onCurrentUserChanged(userId);
- }
- break;
- case Intent.ACTION_USER_STARTED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onUserStarted(userId);
- }
- break;
- case Intent.ACTION_USER_STOPPED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onUserStopped(userId);
- }
- break;
- case Intent.ACTION_MANAGED_PROFILE_ADDED:
- case Intent.ACTION_MANAGED_PROFILE_REMOVED:
- onUserProfilesChanged();
- break;
- }
- }
- }, UserHandle.ALL, intentFilter, null, FgThread.getHandler());
-
- mCurrentUserId = ActivityManager.getCurrentUser();
}
/**
* Adds a listener for user changed events. Callbacks occur on an unspecified thread.
*/
- public void addListener(UserListener listener) {
+ public final void addListener(UserListener listener) {
mListeners.add(listener);
}
/**
* Removes a listener for user changed events.
*/
- public void removeListener(UserListener listener) {
+ public final void removeListener(UserListener listener) {
mListeners.remove(listener);
}
- private void onCurrentUserChanged(@UserIdInt int newUserId) {
- if (newUserId == mCurrentUserId) {
- return;
- }
-
+ protected void dispatchOnUserStarted(@UserIdInt int userId) {
if (D) {
- Log.d(TAG, "current user switched from u" + mCurrentUserId + " to u" + newUserId);
+ Log.d(TAG, "u" + userId + " started");
}
- int oldUserId = mCurrentUserId;
- mCurrentUserId = newUserId;
-
- onUserChanged(oldUserId, UserListener.USER_SWITCHED);
- onUserChanged(newUserId, UserListener.USER_SWITCHED);
+ for (UserListener listener : mListeners) {
+ listener.onUserChanged(userId, USER_STARTED);
+ }
}
- private void onUserStarted(@UserIdInt int userId) {
+ protected void dispatchOnUserStopped(@UserIdInt int userId) {
if (D) {
- Log.d(TAG, "u" + userId + " started");
+ Log.d(TAG, "u" + userId + " stopped");
}
- onUserChanged(userId, UserListener.USER_STARTED);
+ for (UserListener listener : mListeners) {
+ listener.onUserChanged(userId, USER_STOPPED);
+ }
}
- private void onUserStopped(@UserIdInt int userId) {
+ protected void dispatchOnCurrentUserChanged(@UserIdInt int fromUserId,
+ @UserIdInt int toUserId) {
+ int[] fromUserIds = getProfileIds(fromUserId);
+ int[] toUserIds = getProfileIds(toUserId);
if (D) {
- Log.d(TAG, "u" + userId + " stopped");
+ Log.d(TAG, "current user changed from u" + Arrays.toString(fromUserIds) + " to u"
+ + Arrays.toString(toUserIds));
}
- onUserChanged(userId, UserListener.USER_STOPPED);
- }
-
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
for (UserListener listener : mListeners) {
- listener.onUserChanged(userId, change);
+ for (int userId : fromUserIds) {
+ listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+ }
}
- }
- private synchronized void onUserProfilesChanged() {
- // this intent is only sent to the current user
- if (mCachedParentUserId == mCurrentUserId) {
- mCachedParentUserId = UserHandle.USER_NULL;
- mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
+ for (UserListener listener : mListeners) {
+ for (int userId : toUserIds) {
+ listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+ }
}
}
/**
* Returns an array of current user ids. This will always include the current user, and will
- * also include any profiles of the current user.
+ * also include any profiles of the current user. The caller must never mutate the returned
+ * array.
*/
public int[] getCurrentUserIds() {
- return getProfileUserIdsForParentUser(mCurrentUserId);
+ synchronized (this) {
+ if (mActivityManagerInternal == null) {
+ return new int[] {};
+ }
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mActivityManagerInternal.getCurrentProfileIds();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
@@ -219,54 +177,47 @@ public class UserInfoHelper {
* user.
*/
public boolean isCurrentUserId(@UserIdInt int userId) {
- int currentUserId = mCurrentUserId;
- return userId == currentUserId || ArrayUtils.contains(
- getProfileUserIdsForParentUser(currentUserId), userId);
- }
+ synchronized (this) {
+ if (mActivityManagerInternal == null) {
+ return false;
+ }
+ }
- @GuardedBy("this")
- private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
- if (parentUserId != mCachedParentUserId) {
- long identity = Binder.clearCallingIdentity();
- try {
- Preconditions.checkState(mUserManager != null);
-
- // more expensive check - check that argument really is a parent user id
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkArgument(
- mUserManager.getProfileParent(parentUserId) == null);
- }
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mActivityManagerInternal.isCurrentProfile(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
- mCachedParentUserId = parentUserId;
- mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ private int[] getProfileIds(@UserIdInt int userId) {
+ synchronized (this) {
+ Preconditions.checkState(mUserManager != null);
}
- return mCachedProfileUserIds;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mUserManager.getEnabledProfileIds(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Dump info for debugging.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- boolean systemRunning;
- synchronized (this) {
- systemRunning = mUserManager != null;
- }
-
- if (systemRunning) {
- int[] currentUserIds = getProfileUserIdsForParentUser(mCurrentUserId);
- pw.println("current users: " + Arrays.toString(currentUserIds));
- for (int userId : currentUserIds) {
- if (mUserManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
+ int[] currentUserProfiles = getCurrentUserIds();
+ pw.println("current users: " + Arrays.toString(currentUserProfiles));
+ UserManager userManager = mContext.getSystemService(UserManager.class);
+ if (userManager != null) {
+ for (int userId : currentUserProfiles) {
+ if (userManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
UserHandle.of(userId))) {
pw.println(" u" + userId + " restricted");
}
}
- } else {
- pw.println("current user: " + mCurrentUserId);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9d3385f20695..a95dc3035200 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -246,6 +246,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -2173,19 +2174,19 @@ public class NotificationManagerService extends SystemService {
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
}
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 81ee7d9eeef7..52fdc7983636 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -21,7 +21,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
import android.content.pm.DataLoaderParamsParcel;
import android.content.pm.IDataLoader;
import android.content.pm.IDataLoaderManager;
@@ -122,19 +121,7 @@ public class DataLoaderManagerService extends SystemService {
ri.serviceInfo.packageName, ri.serviceInfo.name);
// There should only be one matching provider inside the given package.
// If there's more than one, return the first one found.
- try {
- ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
- if (!ai.isPrivilegedApp()) {
- Slog.w(TAG,
- "Data loader: " + resolved + " is not a privileged app, skipping.");
- continue;
- }
- return resolved;
- } catch (PackageManager.NameNotFoundException ex) {
- Slog.w(TAG,
- "Privileged data loader: " + resolved + " not found, skipping.");
- }
-
+ return resolved;
}
Slog.e(TAG, "Didn't find any matching data loader service provider.");
return null;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 236a6816b3e3..f827721be3b7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -40,6 +40,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.VersionedPackage;
@@ -126,8 +127,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
/** Automatically destroy staged sessions that have not changed state in this time */
private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
- /** Upper bound on number of active sessions for a UID */
- private static final long MAX_ACTIVE_SESSIONS = 1024;
+ /** Upper bound on number of active sessions for a UID that has INSTALL_PACKAGES */
+ private static final long MAX_ACTIVE_SESSIONS_WITH_PERMISSION = 1024;
+ /** Upper bound on number of active sessions for a UID without INSTALL_PACKAGES */
+ private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
/** Upper bound on number of historical sessions for a UID */
private static final long MAX_HISTORICAL_SESSIONS = 1048576;
@@ -503,7 +506,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
+ "to use a data loader");
}
- String requestedInstallerPackageName = params.installerPackageName != null
+ // App package name and label length is restricted so that really long strings aren't
+ // written to disk.
+ if (params.appPackageName != null
+ && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+ params.appPackageName = null;
+ }
+
+ params.appLabel = TextUtils.trimToSize(params.appLabel,
+ PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
+
+ String requestedInstallerPackageName = (params.installerPackageName != null
+ && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
? params.installerPackageName : installerPackageName;
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
@@ -635,12 +649,23 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ if (params.whitelistedRestrictedPermissions != null) {
+ mPermissionManager.retainHardAndSoftRestrictedPermissions(
+ params.whitelistedRestrictedPermissions);
+ }
+
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
// Sanity check that installer isn't going crazy
final int activeCount = getSessionCount(mSessions, callingUid);
- if (activeCount >= MAX_ACTIVE_SESSIONS) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+ == PackageManager.PERMISSION_GRANTED) {
+ if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) {
+ throw new IllegalStateException(
+ "Too many active sessions for UID " + callingUid);
+ }
+ } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) {
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6bb10c79d382..766fae64f647 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -148,6 +148,8 @@ import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -639,6 +641,19 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
+ /**
+ * Adding an installer package name to a package that does not have one set requires the
+ * INSTALL_PACKAGES permission.
+ *
+ * If the caller targets R, this will throw a SecurityException. Otherwise the request will
+ * fail silently. In both cases, and regardless of whether this change is enabled, the
+ * installer package will remain unchanged.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE =
+ 150857253;
+
public static final String PLATFORM_PACKAGE_NAME = "android";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -5264,15 +5279,17 @@ public class PackageManagerService extends IPackageManager.Stub
* </ul>
*/
int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
- boolean matchSystemOnly) {
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, matchSystemOnly, false /*onlyExposedExplicitly*/);
+ wantInstantApps, false /*onlyExposedExplicitly*/,
+ isImplicitImageCaptureIntentAndNotSetByDpc);
}
int updateFlagsForResolve(int flags, int userId, int callingUid,
- boolean wantInstantApps, boolean onlyExposedExplicitly, boolean matchSystemOnly) {
+ boolean wantInstantApps, boolean onlyExposedExplicitly,
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
// Safe mode means we shouldn't match any third-party components
- if (mSafeMode || matchSystemOnly) {
+ if (mSafeMode || isImplicitImageCaptureIntentAndNotSetByDpc) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
}
if (getInstantAppPackageName(callingUid) != null) {
@@ -6400,7 +6417,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
@@ -6438,7 +6456,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
final int flags = updateFlagsForResolve(
0, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, 0));
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
synchronized (mLock) {
@@ -6684,6 +6702,40 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
+ /**
+ * From Android R, camera intents have to match system apps. The only exception to this is if
+ * the DPC has set the camera persistent preferred activity. This case was introduced
+ * because it is important that the DPC has the ability to set both system and non-system
+ * camera persistent preferred activities.
+ *
+ * @return {@code true} if the intent is a camera intent and the persistent preferred
+ * activity was not set by the DPC.
+ */
+ @GuardedBy("mLock")
+ private boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+ String resolvedType, int flags) {
+ return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
+ intent, userId, resolvedType, flags);
+ }
+
+ private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
+ String resolvedType, int flags) {
+ PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+ .get(userId);
+ //TODO(b/158003772): Remove double query
+ List<PersistentPreferredActivity> pprefs = ppir != null
+ ? ppir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+ userId)
+ : new ArrayList<>();
+ for (PersistentPreferredActivity ppa : pprefs) {
+ if (ppa.mIsSetByDpm) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@GuardedBy("mLock")
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
@@ -6767,7 +6819,8 @@ public class PackageManagerService extends IPackageManager.Stub
android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
flags = updateFlagsForResolve(
flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
intent = updateIntentForResolve(intent);
// writer
synchronized (mLock) {
@@ -6980,7 +7033,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
int flags = updateFlagsForResolve(0, parent.id, callingUid,
false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
+ resolvedType, 0));
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
intent, resolvedType, flags, sourceUserId, parent.id);
return xpDomainInfo != null;
@@ -7067,7 +7121,8 @@ public class PackageManagerService extends IPackageManager.Stub
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
@@ -7856,7 +7911,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent activity options");
@@ -8043,7 +8099,8 @@ public class PackageManagerService extends IPackageManager.Stub
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -8134,7 +8191,7 @@ public class PackageManagerService extends IPackageManager.Stub
int userId, int callingUid) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
List<ResolveInfo> query = queryIntentServicesInternal(
intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
if (query != null) {
@@ -8166,7 +8223,7 @@ public class PackageManagerService extends IPackageManager.Stub
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -8304,7 +8361,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -14130,19 +14187,38 @@ public class PackageManagerService extends IPackageManager.Stub
// be signed with the same cert as the caller.
String targetInstallerPackageName =
targetPackageSetting.installSource.installerPackageName;
- if (targetInstallerPackageName != null) {
- PackageSetting setting = mSettings.mPackages.get(
- targetInstallerPackageName);
- // If the currently set package isn't valid, then it's always
- // okay to change it.
- if (setting != null) {
- if (compareSignatures(callerSignature,
- setting.signatures.mSigningDetails.signatures)
- != PackageManager.SIGNATURE_MATCH) {
- throw new SecurityException(
- "Caller does not have same cert as old installer package "
- + targetInstallerPackageName);
+ PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
+ mSettings.mPackages.get(targetInstallerPackageName);
+
+ if (targetInstallerPkgSetting != null) {
+ if (compareSignatures(callerSignature,
+ targetInstallerPkgSetting.signatures.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH) {
+ throw new SecurityException(
+ "Caller does not have same cert as old installer package "
+ + targetInstallerPackageName);
+ }
+ } else if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ // This is probably an attempt to exploit vulnerability b/150857253 of taking
+ // privileged installer permissions when the installer has been uninstalled or
+ // was never set.
+ EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
+
+ long binderToken = Binder.clearCallingIdentity();
+ try {
+ if (mInjector.getCompatibility().isChangeEnabledByUid(
+ THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE,
+ callingUid)) {
+ throw new SecurityException("Neither user " + callingUid
+ + " nor current process has "
+ + Manifest.permission.INSTALL_PACKAGES);
+ } else {
+ // If change disabled, fail silently for backwards compatibility
+ return;
}
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
}
}
@@ -19840,7 +19916,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
- new PersistentPreferredActivity(filter, activity));
+ new PersistentPreferredActivity(filter, activity, true));
scheduleWritePackageRestrictionsLocked(userId);
}
updateDefaultHomeNotLocked(userId);
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
index 0d4cdf9dee53..5a6fd0923f53 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
@@ -16,31 +16,34 @@
package com.android.server.pm;
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import android.content.ComponentName;
-import android.content.IntentFilter;
-import android.util.Log;
-
import java.io.IOException;
class PersistentPreferredActivity extends IntentFilter {
private static final String ATTR_NAME = "name"; // component name
private static final String ATTR_FILTER = "filter"; // filter
+ private static final String ATTR_SET_BY_DPM = "set-by-dpm"; // set by DPM
private static final String TAG = "PersistentPreferredActivity";
private static final boolean DEBUG_FILTERS = false;
final ComponentName mComponent;
+ final boolean mIsSetByDpm;
- PersistentPreferredActivity(IntentFilter filter, ComponentName activity) {
+ PersistentPreferredActivity(IntentFilter filter, ComponentName activity, boolean isSetByDpm) {
super(filter);
mComponent = activity;
+ mIsSetByDpm = isSetByDpm;
}
PersistentPreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
@@ -52,6 +55,8 @@ class PersistentPreferredActivity extends IntentFilter {
"Bad activity name " + shortComponent +
" at " + parser.getPositionDescription());
}
+ mIsSetByDpm = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_SET_BY_DPM));
+
int outerDepth = parser.getDepth();
String tagName = parser.getName();
int type;
@@ -83,6 +88,7 @@ class PersistentPreferredActivity extends IntentFilter {
public void writeToXml(XmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());
+ serializer.attribute(null, ATTR_SET_BY_DPM, Boolean.toString(mIsSetByDpm));
serializer.startTag(null, ATTR_FILTER);
super.writeToXml(serializer);
serializer.endTag(null, ATTR_FILTER);
@@ -91,6 +97,7 @@ class PersistentPreferredActivity extends IntentFilter {
@Override
public String toString() {
return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
- + " " + mComponent.flattenToShortString() + "}";
+ + " " + mComponent.flattenToShortString()
+ + ", mIsSetByDpm=" + mIsSetByDpm + "}";
}
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 79805e3b42ae..8ccf837f64dc 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -77,7 +77,11 @@ import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.rollback.WatchdogRollbackLogger;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -102,6 +106,9 @@ public class StagingManager {
private final PreRebootVerificationHandler mPreRebootVerificationHandler;
private final Supplier<PackageParser2> mPackageParserSupplier;
+ private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
+ private String mFailureReason;
+
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
@@ -125,6 +132,12 @@ public class StagingManager {
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPreRebootVerificationHandler = new PreRebootVerificationHandler(
BackgroundThread.get().getLooper());
+
+ if (mFailureReasonFile.exists()) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(mFailureReasonFile))) {
+ mFailureReason = reader.readLine();
+ } catch (Exception ignore) { }
+ }
}
/**
@@ -383,10 +396,19 @@ public class StagingManager {
}
// Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
- private void abortCheckpoint(String errorMsg) {
- Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
+ private void abortCheckpoint(int sessionId, String errorMsg) {
+ String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
+ Slog.e(TAG, failureReason);
try {
if (supportsCheckpoint() && needsCheckpoint()) {
+ // Store failure reason for next reboot
+ try (BufferedWriter writer =
+ new BufferedWriter(new FileWriter(mFailureReasonFile))) {
+ writer.write(failureReason);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to save failure reason: ", e);
+ }
+
// Only revert apex sessions if device supports updating apex
if (mApexManager.isApexSupported()) {
mApexManager.revertActiveSessions();
@@ -592,14 +614,12 @@ public class StagingManager {
// If checkpoint is supported, then we only resume sessions if we are in checkpointing
// mode. If not, we fail all sessions.
if (supportsCheckpoint() && !needsCheckpoint()) {
- // TODO(b/146343545): Persist failure reason across checkpoint reboot
- Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
- + " as failed.");
- String errorMsg = "Reverting back to safe state";
- if (!TextUtils.isEmpty(mNativeFailureReason)) {
- errorMsg = "Entered fs-rollback mode and reverted session due to crashing "
- + "native process: " + mNativeFailureReason;
+ String errorMsg = "Reverting back to safe state. Marking " + session.sessionId
+ + " as failed";
+ if (!TextUtils.isEmpty(mFailureReason)) {
+ errorMsg = errorMsg + ": " + mFailureReason;
}
+ Slog.d(TAG, errorMsg);
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
return;
}
@@ -624,7 +644,7 @@ public class StagingManager {
+ "supposed to be activated";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (isApexSessionFailed(apexSessionInfo)) {
@@ -636,7 +656,7 @@ public class StagingManager {
}
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
@@ -647,7 +667,7 @@ public class StagingManager {
+ "didn't activate nor fail. Marking it as failed anyway.";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
}
@@ -664,7 +684,7 @@ public class StagingManager {
installApksInSession(session);
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
- abortCheckpoint(e.getMessage());
+ abortCheckpoint(session.sessionId, e.getMessage());
// If checkpoint is not supported, we have to handle failure for one staged session.
if (!hasApex) {
@@ -1189,6 +1209,8 @@ public class StagingManager {
ctx.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+
+ mFailureReasonFile.delete();
}
private static class LocalIntentReceiverAsync {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d5c9424528bd..40fa798309c1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2250,9 +2250,6 @@ public class UserManagerService extends IUserManager.Stub {
// Managed profiles have their own specific rules.
final boolean isManagedProfile = type.isManagedProfile();
if (isManagedProfile) {
- if (ActivityManager.isLowRamDeviceStatic()) {
- return false;
- }
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MANAGED_USERS)) {
return false;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index b0d4d957fc21..d3f3ba1dc6bb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -26,6 +26,7 @@ import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -1804,8 +1805,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
- // If this permission was granted by default, make sure it is.
- if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
+ // If this permission was granted by default or role, make sure it is.
+ if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
+ || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0) {
// PermissionPolicyService will handle the app op for runtime permissions later.
grantRuntimePermissionInternal(permName, packageName, false,
Process.SYSTEM_UID, userId, delayingPermCallback);
@@ -4948,6 +4950,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
}
}
+
+ @Override
+ public void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions) {
+ synchronized (mLock) {
+ Iterator<String> iterator = permissions.iterator();
+ while (iterator.hasNext()) {
+ String permission = iterator.next();
+ BasePermission basePermission = mSettings.mPermissions.get(permission);
+ if (basePermission == null || !basePermission.isHardOrSoftRestricted()) {
+ iterator.remove();
+ }
+ }
+ }
+ }
}
private static final class OnPermissionChangeListeners extends Handler {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 57a25eddf7ce..4412162a5cc8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -36,6 +36,7 @@ import java.util.function.Consumer;
* TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
*/
public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
+
/**
* Provider for package names.
*/
@@ -455,4 +456,10 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
/** Called when a new user has been created. */
public abstract void onNewUserCreated(@UserIdInt int userId);
+
+ /**
+ * Removes invalid permissions which are not {@link PermissionInfo#FLAG_HARD_RESTRICTED} or
+ * {@link PermissionInfo#FLAG_SOFT_RESTRICTED} from the input.
+ */
+ public abstract void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions);
}
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 6c1ff728e6b9..ab459fdadd21 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -3319,8 +3319,8 @@ public class StatsPullAtomService extends SystemService {
public void run() {
try {
estimateAppOpsSamplingRate();
- } catch (Exception e) {
- Slog.e(TAG, "AppOps sampling ratio estimation failed");
+ } catch (Throwable e) {
+ Slog.e(TAG, "AppOps sampling ratio estimation failed: ", e);
synchronized (mAppOpsSamplingRateLock) {
mAppOpsSamplingRate = min(mAppOpsSamplingRate, 10);
}
@@ -3361,7 +3361,7 @@ public class StatsPullAtomService extends SystemService {
Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
Long.MAX_VALUE).setFlags(
OP_FLAGS_PULLED).build();
- appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
+ appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, ops::complete);
HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS);
List<AppOpEntry> opsList =
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 5f6323369d0a..c38d649ada9b 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -115,7 +115,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
private static final String TAG = "UriGrantsManagerService";
// Maximum number of persisted Uri grants a package is allowed
private static final int MAX_PERSISTED_URI_GRANTS = 128;
- private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
+ private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
private final Object mLock = new Object();
private final H mH;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 045089082fd8..36232e13fcf1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5790,10 +5790,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// be invoked and we need to invoke it ourself.
if (mLocalSyncId >= 0) {
mBLASTSyncEngine.setReady(mLocalSyncId);
- } else {
- mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
+ return mWinAnimator.finishDrawingLocked(null);
}
+ mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
mUsingBLASTSyncTransaction = false;
mWaitingSyncId = 0;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
index 71e79b331cae..56727e81bda5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
@@ -16,34 +16,23 @@
package com.android.server.location;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.os.Handler;
-import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
import com.android.server.location.UserInfoHelper.UserListener;
import org.junit.After;
@@ -51,16 +40,18 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.quality.Strictness;
-
-import java.util.ArrayList;
-import java.util.List;
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class UserInfoHelperTest {
+ private static class TestUserInfoHelper extends UserInfoHelper {
+ TestUserInfoHelper(Context context) {
+ super(context);
+ }
+ }
+
private static final int USER1_ID = 1;
private static final int USER1_MANAGED_ID = 11;
private static final int[] USER1_PROFILES = new int[]{USER1_ID, USER1_MANAGED_ID};
@@ -70,69 +61,30 @@ public class UserInfoHelperTest {
@Mock private Context mContext;
@Mock private UserManager mUserManager;
+ @Mock private ActivityManagerInternal mActivityManagerInternal;
- private StaticMockitoSession mMockingSession;
- private List<BroadcastReceiver> mBroadcastReceivers = new ArrayList<>();
-
- private UserInfoHelper mHelper;
+ private TestUserInfoHelper mHelper;
@Before
public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .spyStatic(ActivityManager.class)
- .strictness(Strictness.WARN)
- .startMocking();
+ initMocks(this);
+ LocalServices.addService(ActivityManagerInternal.class, mActivityManagerInternal);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
- doAnswer(invocation -> {
- mBroadcastReceivers.add(invocation.getArgument(0));
- return null;
- }).when(mContext).registerReceiverAsUser(any(BroadcastReceiver.class), any(
- UserHandle.class), any(IntentFilter.class), isNull(), any(Handler.class));
- doReturn(USER1_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER1_ID);
- doReturn(USER2_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER2_ID);
- doReturn(new UserInfo(USER1_ID, "", 0)).when(mUserManager).getProfileParent(
- USER1_MANAGED_ID);
- doReturn(new UserInfo(USER2_ID, "", 0)).when(mUserManager).getProfileParent(
- USER2_MANAGED_ID);
-
- doReturn(USER1_ID).when(ActivityManager::getCurrentUser);
-
- mHelper = new UserInfoHelper(mContext);
+
+ doReturn(USER1_PROFILES).when(mUserManager).getEnabledProfileIds(USER1_ID);
+ doReturn(USER2_PROFILES).when(mUserManager).getEnabledProfileIds(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+ doReturn(USER1_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
+
+ mHelper = new TestUserInfoHelper(mContext);
mHelper.onSystemReady();
}
@After
public void tearDown() {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- private void switchUser(int userId) {
- doReturn(userId).when(ActivityManager::getCurrentUser);
- Intent intent = new Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
- }
-
- private void startUser(int userId) {
- Intent intent = new Intent(Intent.ACTION_USER_STARTED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
- }
-
- private void stopUser(int userId) {
- Intent intent = new Intent(Intent.ACTION_USER_STOPPED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
}
@Test
@@ -140,16 +92,21 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- switchUser(USER1_ID);
- verify(listener, never()).onUserChanged(anyInt(), anyInt());
-
- switchUser(USER2_ID);
- verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
- verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
-
- switchUser(USER1_ID);
- verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
- verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
+ mHelper.dispatchOnCurrentUserChanged(USER1_ID, USER2_ID);
+ verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER1_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER2_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+
+ mHelper.dispatchOnCurrentUserChanged(USER2_ID, USER1_ID);
+ verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER2_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER1_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
}
@Test
@@ -157,11 +114,11 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- startUser(USER1_ID);
+ mHelper.dispatchOnUserStarted(USER1_ID);
verify(listener).onUserChanged(USER1_ID, UserListener.USER_STARTED);
- startUser(USER2_ID);
- verify(listener).onUserChanged(USER2_ID, UserListener.USER_STARTED);
+ mHelper.dispatchOnUserStarted(USER1_MANAGED_ID);
+ verify(listener).onUserChanged(USER1_MANAGED_ID, UserListener.USER_STARTED);
}
@Test
@@ -169,24 +126,22 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- stopUser(USER1_ID);
- verify(listener).onUserChanged(USER1_ID, UserListener.USER_STOPPED);
-
- stopUser(USER2_ID);
+ mHelper.dispatchOnUserStopped(USER2_ID);
verify(listener).onUserChanged(USER2_ID, UserListener.USER_STOPPED);
+
+ mHelper.dispatchOnUserStopped(USER2_MANAGED_ID);
+ verify(listener).onUserChanged(USER2_MANAGED_ID, UserListener.USER_STOPPED);
}
@Test
public void testCurrentUserIds() {
assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
- switchUser(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+ doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER2_PROFILES);
-
- switchUser(USER1_ID);
-
- assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
}
@Test
@@ -196,7 +151,11 @@ public class UserInfoHelperTest {
assertThat(mHelper.isCurrentUserId(USER2_ID)).isFalse();
assertThat(mHelper.isCurrentUserId(USER2_MANAGED_ID)).isFalse();
- switchUser(USER2_ID);
+ doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+ doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+ doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
assertThat(mHelper.isCurrentUserId(USER1_ID)).isFalse();
assertThat(mHelper.isCurrentUserId(USER2_ID)).isTrue();
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index 752707e5a5dc..d366efe0d979 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -594,6 +594,7 @@ public final class SmsCbMessage implements Parcelable {
SmsCbEtwsInfo etwsInfo = getEtwsWarningInfo();
if (etwsInfo != null) {
cv.put(CellBroadcasts.ETWS_WARNING_TYPE, etwsInfo.getWarningType());
+ cv.put(CellBroadcasts.ETWS_IS_PRIMARY, etwsInfo.isPrimary());
}
SmsCbCmasInfo cmasInfo = getCmasWarningInfo();
@@ -667,9 +668,12 @@ public final class SmsCbMessage implements Parcelable {
SmsCbEtwsInfo etwsInfo;
int etwsWarningTypeColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_WARNING_TYPE);
- if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)) {
+ int etwsIsPrimaryColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_IS_PRIMARY);
+ if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)
+ && etwsIsPrimaryColumn != -1 && !cursor.isNull(etwsIsPrimaryColumn)) {
int warningType = cursor.getInt(etwsWarningTypeColumn);
- etwsInfo = new SmsCbEtwsInfo(warningType, false, false, false, null);
+ boolean isPrimary = cursor.getInt(etwsIsPrimaryColumn) != 0;
+ etwsInfo = new SmsCbEtwsInfo(warningType, false, false, isPrimary, null);
} else {
etwsInfo = null;
}
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 70c5e72e4e0c..b841921355e9 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -632,7 +632,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
public boolean is24GHz() {
return ScanResult.is24GHz(mFrequency);
@@ -640,7 +639,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
@UnsupportedAppUsage
public boolean is5GHz() {
@@ -648,6 +646,13 @@ public class WifiInfo implements Parcelable {
}
/**
+ * @hide
+ */
+ public boolean is6GHz() {
+ return ScanResult.is6GHz(mFrequency);
+ }
+
+ /**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
* @hide