Merge "Add benchmark for HandwritingInitiator"
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 05a06619..1f4a64f 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -81,18 +81,18 @@
static constexpr const char* OEM_USERSPACE_REBOOT_ANIMATION_FILE = "/oem/media/userspace-reboot.zip";
static constexpr const char* SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE = "/system/media/userspace-reboot.zip";
-static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
-static const char SYSTEM_TIME_DIR_NAME[] = "time";
-static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
+static const char BOOTANIM_DATA_DIR_PATH[] = "/data/bootanim";
+static const char BOOTANIM_TIME_DIR_NAME[] = "time";
+static const char BOOTANIM_TIME_DIR_PATH[] = "/data/bootanim/time";
static const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
static const char PROGRESS_FONT_ASSET[] = "images/progress_font.png";
static const char PROGRESS_FONT_ZIP_NAME[] = "progress_font.png";
static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
-static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
+static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/bootanim/time/last_time_change";
static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
-static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
-static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/system/time/time_format_12_hour";
+static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/bootanim/time/time_is_accurate";
+static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/bootanim/time/time_format_12_hour";
// Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
static const long long ACCURATE_TIME_EPOCH = 946684800000;
static constexpr char FONT_BEGIN_CHAR = ' ';
@@ -1741,7 +1741,7 @@
}
BootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
- mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
+ mInotifyFd(-1), mBootAnimWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
BootAnimation::TimeCheckThread::~TimeCheckThread() {
// mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
@@ -1784,7 +1784,7 @@
const struct inotify_event *event;
for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
event = (const struct inotify_event *) ptr;
- if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
+ if (event->wd == mBootAnimWd && strcmp(BOOTANIM_TIME_DIR_NAME, event->name) == 0) {
addTimeDirWatch();
} else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
|| strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
@@ -1796,12 +1796,12 @@
}
void BootAnimation::TimeCheckThread::addTimeDirWatch() {
- mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
+ mTimeWd = inotify_add_watch(mInotifyFd, BOOTANIM_TIME_DIR_PATH,
IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
if (mTimeWd > 0) {
// No need to watch for the time directory to be created if it already exists
- inotify_rm_watch(mInotifyFd, mSystemWd);
- mSystemWd = -1;
+ inotify_rm_watch(mInotifyFd, mBootAnimWd);
+ mBootAnimWd = -1;
}
}
@@ -1812,11 +1812,11 @@
return NO_INIT;
}
- mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
- if (mSystemWd < 0) {
+ mBootAnimWd = inotify_add_watch(mInotifyFd, BOOTANIM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
+ if (mBootAnimWd < 0) {
close(mInotifyFd);
mInotifyFd = -1;
- SLOGE("Could not add watch for %s: %s", SYSTEM_DATA_DIR_PATH, strerror(errno));
+ SLOGE("Could not add watch for %s: %s", BOOTANIM_DATA_DIR_PATH, strerror(errno));
return NO_INIT;
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 7a597da..4c378cb 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -161,7 +161,7 @@
void addTimeDirWatch();
int mInotifyFd;
- int mSystemWd;
+ int mBootAnimWd;
int mTimeWd;
BootAnimation* mBootAnimation;
};
diff --git a/core/api/current.txt b/core/api/current.txt
index c05f39b..b983617 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -4469,6 +4469,7 @@
method public android.app.ActivityOptions setLaunchDisplayId(int);
method public android.app.ActivityOptions setLockTaskEnabled(boolean);
method public void setPendingIntentBackgroundActivityLaunchAllowed(boolean);
+ method @NonNull public android.app.ActivityOptions setSplashScreenStyle(int);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
@@ -32484,6 +32485,7 @@
public final class SystemClock {
method @NonNull public static java.time.Clock currentGnssTimeClock();
+ method @NonNull public static java.time.Clock currentNetworkTimeClock();
method public static long currentThreadTimeMillis();
method public static long elapsedRealtime();
method public static long elapsedRealtimeNanos();
@@ -41481,6 +41483,7 @@
field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool";
field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int";
field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array";
+ field public static final String KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL = "enable_cross_sim_calling_on_opportunistic_data_bool";
field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int";
@@ -43947,7 +43950,7 @@
method public boolean isSimPortAvailable(int);
method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
method @Deprecated @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
- method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.euicc.EuiccManager.ResultListener);
+ method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, int, @NonNull android.app.PendingIntent);
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
@@ -43993,10 +43996,6 @@
field public static final int OPERATION_SYSTEM = 1; // 0x1
}
- public static interface EuiccManager.ResultListener {
- method public void onComplete(int, @Nullable android.content.Intent);
- }
-
}
package android.telephony.gsm {
@@ -57676,6 +57675,8 @@
method public void clearOnExitAnimationListener();
method public void setOnExitAnimationListener(@NonNull android.window.SplashScreen.OnExitAnimationListener);
method public void setSplashScreenTheme(@StyleRes int);
+ field public static final int SPLASH_SCREEN_STYLE_EMPTY = 0; // 0x0
+ field public static final int SPLASH_SCREEN_STYLE_ICON = 1; // 0x1
}
public static interface SplashScreen.OnExitAnimationListener {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 04c1e9e..53bc8a6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -258,6 +258,43 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStateSnapshot> CREATOR;
}
+ public final class NetworkTemplate implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDefaultNetworkStatus();
+ method public int getMatchRule();
+ method public int getMeteredness();
+ method public int getOemManaged();
+ method public int getRatType();
+ method public int getRoaming();
+ method @NonNull public java.util.Set<java.lang.String> getSubscriberIds();
+ method @NonNull public java.util.Set<java.lang.String> getWifiNetworkKeys();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkTemplate> CREATOR;
+ field public static final int MATCH_BLUETOOTH = 8; // 0x8
+ field public static final int MATCH_CARRIER = 10; // 0xa
+ field public static final int MATCH_ETHERNET = 5; // 0x5
+ field public static final int MATCH_MOBILE = 1; // 0x1
+ field public static final int MATCH_WIFI = 4; // 0x4
+ field public static final int NETWORK_TYPE_ALL = -1; // 0xffffffff
+ field public static final int OEM_MANAGED_ALL = -1; // 0xffffffff
+ field public static final int OEM_MANAGED_NO = 0; // 0x0
+ field public static final int OEM_MANAGED_PAID = 1; // 0x1
+ field public static final int OEM_MANAGED_PRIVATE = 2; // 0x2
+ field public static final int OEM_MANAGED_YES = -2; // 0xfffffffe
+ }
+
+ public static final class NetworkTemplate.Builder {
+ ctor public NetworkTemplate.Builder(int);
+ method @NonNull public android.net.NetworkTemplate build();
+ method @NonNull public android.net.NetworkTemplate.Builder setDefaultNetworkStatus(int);
+ method @NonNull public android.net.NetworkTemplate.Builder setMeteredness(int);
+ method @NonNull public android.net.NetworkTemplate.Builder setOemManaged(int);
+ method @NonNull public android.net.NetworkTemplate.Builder setRatType(int);
+ method @NonNull public android.net.NetworkTemplate.Builder setRoaming(int);
+ method @NonNull public android.net.NetworkTemplate.Builder setSubscriberIds(@NonNull java.util.Set<java.lang.String>);
+ method @NonNull public android.net.NetworkTemplate.Builder setWifiNetworkKeys(@NonNull java.util.Set<java.lang.String>);
+ }
+
public class NetworkWatchlistManager {
method @Nullable public byte[] getWatchlistConfigHash();
}
@@ -342,6 +379,10 @@
method @Nullable public android.os.IBinder getOrThrow() throws android.os.StatsServiceManager.ServiceNotFoundException;
}
+ public final class StrictMode {
+ method public static void noteUntaggedSocket();
+ }
+
public class SystemConfigManager {
method @NonNull public java.util.List<android.content.ComponentName> getEnabledComponentOverrides(@NonNull String);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 040eddc..30154c8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -342,6 +342,7 @@
public static final class R.array {
field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
+ field public static final int config_optionalIpSecAlgorithms;
}
public static final class R.attr {
@@ -858,7 +859,11 @@
public class StatusBarManager {
method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo();
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public int getNavBarModeOverride();
method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean);
+ method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setNavBarModeOverride(int);
+ field public static final int NAV_BAR_MODE_OVERRIDE_KIDS = 1; // 0x1
+ field public static final int NAV_BAR_MODE_OVERRIDE_NONE = 0; // 0x0
}
public static final class StatusBarManager.DisableInfo {
@@ -2917,6 +2922,7 @@
}
public static class LauncherApps.ShortcutQuery {
+ field public static final int FLAG_GET_PERSISTED_DATA = 4096; // 0x1000
field @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public static final int FLAG_GET_PERSONS_DATA = 2048; // 0x800
}
@@ -6480,7 +6486,7 @@
method public int getAvSyncHwId(@NonNull android.media.tv.tuner.filter.Filter);
method public long getAvSyncTime(int);
method @Nullable public java.util.List<android.media.tv.tuner.frontend.FrontendInfo> getAvailableFrontendInfos();
- method @Nullable public String getCurrentFrontendHardwardInfo();
+ method @Nullable public String getCurrentFrontendHardwareInfo();
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
@@ -7930,7 +7936,7 @@
method public void onScanStopped();
method public void onSignalTypeReported(int);
method public void onSymbolRatesReported(@NonNull int[]);
- method public default void onUnLocked();
+ method public default void onUnlocked();
}
}
@@ -8090,13 +8096,17 @@
method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR;
+ field public static final int DEFAULT_NETWORK_ALL = -1; // 0xffffffff
field public static final int DEFAULT_NETWORK_NO = 0; // 0x0
field public static final int DEFAULT_NETWORK_YES = 1; // 0x1
field public static final String IFACE_VT = "vt_data0";
+ field public static final int METERED_ALL = -1; // 0xffffffff
field public static final int METERED_NO = 0; // 0x0
field public static final int METERED_YES = 1; // 0x1
+ field public static final int ROAMING_ALL = -1; // 0xffffffff
field public static final int ROAMING_NO = 0; // 0x0
field public static final int ROAMING_YES = 1; // 0x1
+ field public static final int SET_ALL = -1; // 0xffffffff
field public static final int SET_DEFAULT = 0; // 0x0
field public static final int SET_FOREGROUND = 1; // 0x1
field public static final int TAG_NONE = 0; // 0x0
@@ -9540,6 +9550,7 @@
public final class PermissionControllerManager {
method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
+ method public void getUnusedAppCount(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
@@ -9564,6 +9575,7 @@
method @BinderThread public abstract void onGetPermissionUsages(boolean, long, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionUsageInfo>>);
method @BinderThread public void onGetPlatformPermissionsForGroup(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_HIBERNATION) public void onGetUnusedAppCount(@NonNull java.util.function.IntConsumer);
method @BinderThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable);
method @BinderThread public void onOneTimePermissionSessionTimeout(@NonNull String);
method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -10012,7 +10024,7 @@
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
field public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
field public static final String APP_STANDBY_ENABLED = "app_standby_enabled";
- field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
+ field @Deprecated public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
field public static final String CARRIER_APP_NAMES = "carrier_app_names";
field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
@@ -10726,6 +10738,7 @@
field public static final String EXTRA_RESOLUTION_CONFIRMATION_CODE_RETRIED = "android.service.euicc.extra.RESOLUTION_CONFIRMATION_CODE_RETRIED";
field public static final String EXTRA_RESOLUTION_CONSENT = "android.service.euicc.extra.RESOLUTION_CONSENT";
field public static final String EXTRA_RESOLUTION_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_PORT_INDEX";
+ field public static final String EXTRA_RESOLUTION_USE_PORT_INDEX = "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX";
field public static final String EXTRA_RESOLVABLE_ERRORS = "android.service.euicc.extra.RESOLVABLE_ERRORS";
field public static final int RESOLVABLE_ERROR_CONFIRMATION_CODE = 1; // 0x1
field public static final int RESOLVABLE_ERROR_POLICY_RULES = 2; // 0x2
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 8ae6e4c..8724b53 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2877,6 +2877,7 @@
}
public final class AutofillManager {
+ field public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "compat_mode_allowed_packages";
field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index f7d5e52..5e5649f 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -337,7 +337,7 @@
private static final String KEY_LAUNCHED_FROM_BUBBLE =
"android.activity.launchTypeBubble";
- /** See {@link #setSplashscreenStyle(int)}. */
+ /** See {@link #setSplashScreenStyle(int)}. */
private static final String KEY_SPLASH_SCREEN_STYLE =
"android.activity.splashScreenStyle";
@@ -1393,20 +1393,27 @@
}
/**
- * Sets the preferred splash screen style.
+ * Gets the style can be used for cold-launching an activity.
+ * @see #setSplashScreenStyle(int)
* @hide
*/
- public void setSplashscreenStyle(@SplashScreen.SplashScreenStyle int style) {
- mSplashScreenStyle = style;
+ public @SplashScreen.SplashScreenStyle int getSplashScreenStyle() {
+ return mSplashScreenStyle;
}
/**
- * Gets the preferred splash screen style from caller
- * @hide
+ * Sets the preferred splash screen style of the opening activities. This only applies if the
+ * Activity or Process is not yet created.
+ * @param style Can be either {@link SplashScreen#SPLASH_SCREEN_STYLE_ICON} or
+ * {@link SplashScreen#SPLASH_SCREEN_STYLE_EMPTY}
*/
- @SplashScreen.SplashScreenStyle
- public int getSplashScreenStyle() {
- return mSplashScreenStyle;
+ @NonNull
+ public ActivityOptions setSplashScreenStyle(@SplashScreen.SplashScreenStyle int style) {
+ if (style == SplashScreen.SPLASH_SCREEN_STYLE_ICON
+ || style == SplashScreen.SPLASH_SCREEN_STYLE_EMPTY) {
+ mSplashScreenStyle = style;
+ }
+ return this;
}
/**
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index ae578f5..64d3a9f 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -282,6 +282,33 @@
@Retention(RetentionPolicy.SOURCE)
public @interface RequestResult {}
+ /**
+ * Constant for {@link #setNavBarModeOverride(int)} indicating the default navbar mode.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int NAV_BAR_MODE_OVERRIDE_NONE = 0;
+
+ /**
+ * Constant for {@link #setNavBarModeOverride(int)} indicating kids navbar mode.
+ *
+ * <p>When used, back and home icons will change drawables and layout, recents will be hidden,
+ * and the navbar will remain visible when apps are in immersive mode.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int NAV_BAR_MODE_OVERRIDE_KIDS = 1;
+
+ /** @hide */
+ @IntDef(prefix = {"NAV_BAR_MODE_OVERRIDE_"}, value = {
+ NAV_BAR_MODE_OVERRIDE_NONE,
+ NAV_BAR_MODE_OVERRIDE_KIDS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NavBarModeOverride {}
+
@UnsupportedAppUsage
private Context mContext;
private IStatusBarService mService;
@@ -687,6 +714,52 @@
}
}
+ /**
+ * Sets or removes the navigation bar mode override.
+ *
+ * @param navBarModeOverride the mode of the navigation bar override to be set.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+ public void setNavBarModeOverride(@NavBarModeOverride int navBarModeOverride) {
+ if (navBarModeOverride != NAV_BAR_MODE_OVERRIDE_NONE
+ && navBarModeOverride != NAV_BAR_MODE_OVERRIDE_KIDS) {
+ throw new UnsupportedOperationException(
+ "Supplied navBarModeOverride not supported: " + navBarModeOverride);
+ }
+
+ try {
+ final IStatusBarService svc = getService();
+ if (svc != null) {
+ svc.setNavBarModeOverride(navBarModeOverride);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the navigation bar mode override. Returns default value if no override is set.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.STATUS_BAR)
+ public @NavBarModeOverride int getNavBarModeOverride() {
+ int navBarModeOverride = NAV_BAR_MODE_OVERRIDE_NONE;
+ try {
+ final IStatusBarService svc = getService();
+ if (svc != null) {
+ navBarModeOverride = svc.getNavBarModeOverride();
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return navBarModeOverride;
+ }
+
/** @hide */
public static String windowStateToString(int state) {
if (state == WINDOW_STATE_HIDING) return "WINDOW_STATE_HIDING";
diff --git a/core/java/android/app/communal/CommunalManager.java b/core/java/android/app/communal/CommunalManager.java
index 22f07693..22bd9d1 100644
--- a/core/java/android/app/communal/CommunalManager.java
+++ b/core/java/android/app/communal/CommunalManager.java
@@ -23,9 +23,6 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
-import android.compat.annotation.Overridable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RemoteException;
@@ -46,31 +43,10 @@
private final ICommunalManager mService;
private final ArrayMap<CommunalModeListener, ICommunalModeListener> mCommunalModeListeners;
- /**
- * This change id is used to annotate packages which can run in communal mode by default,
- * without requiring user opt-in.
- *
- * @hide
- */
- @ChangeId
- @Overridable
- @Disabled
- public static final long ALLOW_COMMUNAL_MODE_BY_DEFAULT = 203673428L;
-
- /**
- * This change id is used to annotate packages which are allowed to run in communal mode.
- *
- * @hide
- */
- @ChangeId
- @Overridable
- @Disabled
- public static final long ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT = 200324021L;
-
/** @hide */
public CommunalManager(ICommunalManager service) {
mService = service;
- mCommunalModeListeners = new ArrayMap<CommunalModeListener, ICommunalModeListener>();
+ mCommunalModeListeners = new ArrayMap<>();
}
/**
diff --git a/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java b/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
new file mode 100644
index 0000000..cb47280
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
@@ -0,0 +1,788 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * This class represents an LE Audio Broadcast Source and the associated information that is needed
+ * by Broadcast Audio Scan Service (BASS) residing on a Scan Delegator.
+ *
+ * <p>For example, the Scan Delegator on an LE Audio Broadcast Sink can use the information
+ * contained within an instance of this class to synchronize with an LE Audio Broadcast Source in
+ * order to listen to a Broadcast Audio Stream.
+ *
+ * <p>BroadcastAssistant has a BASS client which facilitates scanning and discovery of Broadcast
+ * Sources on behalf of say a Broadcast Sink. Upon successful discovery of one or more Broadcast
+ * sources, this information needs to be communicated to the BASS Server residing within the Scan
+ * Delegator on a Broadcast Sink. This is achieved using the Periodic Advertising Synchronization
+ * Transfer (PAST) procedure. This procedure uses information contained within an instance of this
+ * class.
+ *
+ * @hide
+ */
+public final class BluetoothLeBroadcastSourceInfo implements Parcelable {
+ private static final String TAG = "BluetoothLeBroadcastSourceInfo";
+ private static final boolean DBG = true;
+
+ /**
+ * Constants representing Broadcast Source address types
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = "LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_",
+ value = {
+ LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC,
+ LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM,
+ LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioBroadcastSourceAddressType {}
+
+ /**
+ * Represents a public address used by an LE Audio Broadcast Source
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC = 0;
+
+ /**
+ * Represents a random address used by an LE Audio Broadcast Source
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM = 1;
+
+ /**
+ * Represents an invalid address used by an LE Audio Broadcast Seurce
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID = 0xFFFF;
+
+ /**
+ * Periodic Advertising Synchronization state
+ *
+ * <p>Periodic Advertising (PA) enables the LE Audio Broadcast Assistant to discover broadcast
+ * audio streams as well as the audio stream configuration on behalf of an LE Audio Broadcast
+ * Sink. This information can then be transferred to the LE Audio Broadcast Sink using the
+ * Periodic Advertising Synchronizaton Transfer (PAST) procedure.
+ *
+ * @hide
+ */
+ @IntDef(
+ prefix = "LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_",
+ value = {
+ LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE,
+ LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ,
+ LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC,
+ LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL,
+ LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioBroadcastSinkPaSyncState {}
+
+ /**
+ * Indicates that the Broadcast Sink is not synchronized with the Periodic Advertisements (PA)
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE = 0;
+
+ /**
+ * Indicates that the Broadcast Sink requested the Broadcast Assistant to synchronize with the
+ * Periodic Advertisements (PA).
+ *
+ * <p>This is also known as scan delegation or scan offloading.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ = 1;
+
+ /**
+ * Indicates that the Broadcast Sink is synchronized with the Periodic Advertisements (PA).
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC = 2;
+
+ /**
+ * Indicates that the Broadcast Sink was unable to synchronize with the Periodic Advertisements
+ * (PA).
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL = 3;
+
+ /**
+ * Indicates that the Broadcast Sink should be synchronized with the Periodic Advertisements
+ * (PA) using the Periodic Advertisements Synchronization Transfert (PAST) procedure.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST = 4;
+
+ /**
+ * Indicates that the Broadcast Sink synchornization state is invalid.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID = 0xFFFF;
+
+ /** @hide */
+ @IntDef(
+ prefix = "LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_",
+ value = {
+ LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED,
+ LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioBroadcastSinkAudioSyncState {}
+
+ /**
+ * Indicates that the Broadcast Sink is not synchronized with a Broadcast Audio Stream.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED = 0;
+
+ /**
+ * Indicates that the Broadcast Sink is synchronized with a Broadcast Audio Stream.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED = 1;
+
+ /**
+ * Indicates that the Broadcast Sink audio synchronization state is invalid.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID = 0xFFFF;
+
+ /** @hide */
+ @IntDef(
+ prefix = "LE_AUDIO_BROADCAST_SINK_ENC_STATE_",
+ value = {
+ LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED,
+ LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED,
+ LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING,
+ LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LeAudioBroadcastSinkEncryptionState {}
+
+ /**
+ * Indicates that the Broadcast Sink is synchronized with an unencrypted audio stream.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED = 0;
+
+ /**
+ * Indicates that the Broadcast Sink needs a Broadcast Code to synchronize with the audio
+ * stream.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED = 1;
+
+ /**
+ * Indicates that the Broadcast Sink is synchronized with an encrypted audio stream.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING = 2;
+
+ /**
+ * Indicates that the Broadcast Sink is unable to decrypt an audio stream due to an incorrect
+ * Broadcast Code
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE = 3;
+
+ /**
+ * Indicates that the Broadcast Sink encryption state is invalid.
+ *
+ * @hide
+ */
+ public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID = 0xFF;
+
+ /**
+ * Represents an invalid LE Audio Broadcast Source ID
+ *
+ * @hide
+ */
+ public static final byte LE_AUDIO_BROADCAST_SINK_INVALID_SOURCE_ID = (byte) 0x00;
+
+ /**
+ * Represents an invalid Broadcast ID of a Broadcast Source
+ *
+ * @hide
+ */
+ public static final int INVALID_BROADCAST_ID = 0xFFFFFF;
+
+ private byte mSourceId;
+ private @LeAudioBroadcastSourceAddressType int mSourceAddressType;
+ private BluetoothDevice mSourceDevice;
+ private byte mSourceAdvSid;
+ private int mBroadcastId;
+ private @LeAudioBroadcastSinkPaSyncState int mPaSyncState;
+ private @LeAudioBroadcastSinkEncryptionState int mEncryptionStatus;
+ private @LeAudioBroadcastSinkAudioSyncState int mAudioSyncState;
+ private byte[] mBadBroadcastCode;
+ private byte mNumSubGroups;
+ private Map<Integer, Integer> mSubgroupBisSyncState = new HashMap<Integer, Integer>();
+ private Map<Integer, byte[]> mSubgroupMetadata = new HashMap<Integer, byte[]>();
+
+ private String mBroadcastCode;
+ private static final int BIS_NO_PREF = 0xFFFFFFFF;
+ private static final int BROADCAST_CODE_SIZE = 16;
+
+ /**
+ * Constructor to create an Empty object of {@link BluetoothLeBroadcastSourceInfo } with the
+ * given Source Id.
+ *
+ * <p>This is mainly used to represent the Empty Broadcast Source entries
+ *
+ * @param sourceId Source Id for this Broadcast Source info object
+ * @hide
+ */
+ public BluetoothLeBroadcastSourceInfo(byte sourceId) {
+ mSourceId = sourceId;
+ mSourceAddressType = LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID;
+ mSourceDevice = null;
+ mSourceAdvSid = (byte) 0x00;
+ mBroadcastId = INVALID_BROADCAST_ID;
+ mPaSyncState = LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID;
+ mAudioSyncState = LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID;
+ mEncryptionStatus = LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID;
+ mBadBroadcastCode = null;
+ mNumSubGroups = 0;
+ mBroadcastCode = null;
+ }
+
+ /*package*/ BluetoothLeBroadcastSourceInfo(
+ byte sourceId,
+ @LeAudioBroadcastSourceAddressType int addressType,
+ @NonNull BluetoothDevice device,
+ byte advSid,
+ int broadcastId,
+ @LeAudioBroadcastSinkPaSyncState int paSyncstate,
+ @LeAudioBroadcastSinkEncryptionState int encryptionStatus,
+ @LeAudioBroadcastSinkAudioSyncState int audioSyncstate,
+ @Nullable byte[] badCode,
+ byte numSubGroups,
+ @NonNull Map<Integer, Integer> bisSyncState,
+ @Nullable Map<Integer, byte[]> subgroupMetadata,
+ @NonNull String broadcastCode) {
+ mSourceId = sourceId;
+ mSourceAddressType = addressType;
+ mSourceDevice = device;
+ mSourceAdvSid = advSid;
+ mBroadcastId = broadcastId;
+ mPaSyncState = paSyncstate;
+ mEncryptionStatus = encryptionStatus;
+ mAudioSyncState = audioSyncstate;
+
+ if (badCode != null && badCode.length != 0) {
+ mBadBroadcastCode = new byte[badCode.length];
+ System.arraycopy(badCode, 0, mBadBroadcastCode, 0, badCode.length);
+ }
+ mNumSubGroups = numSubGroups;
+ mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
+ mSubgroupMetadata = new HashMap<Integer, byte[]>(subgroupMetadata);
+ mBroadcastCode = broadcastCode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothLeBroadcastSourceInfo) {
+ BluetoothLeBroadcastSourceInfo other = (BluetoothLeBroadcastSourceInfo) o;
+ return (other.mSourceId == mSourceId
+ && other.mSourceAddressType == mSourceAddressType
+ && other.mSourceDevice == mSourceDevice
+ && other.mSourceAdvSid == mSourceAdvSid
+ && other.mBroadcastId == mBroadcastId
+ && other.mPaSyncState == mPaSyncState
+ && other.mEncryptionStatus == mEncryptionStatus
+ && other.mAudioSyncState == mAudioSyncState
+ && Arrays.equals(other.mBadBroadcastCode, mBadBroadcastCode)
+ && other.mNumSubGroups == mNumSubGroups
+ && mSubgroupBisSyncState.equals(other.mSubgroupBisSyncState)
+ && mSubgroupMetadata.equals(other.mSubgroupMetadata)
+ && other.mBroadcastCode == mBroadcastCode);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if an instance of {@link BluetoothLeBroadcastSourceInfo} is empty.
+ *
+ * @hide
+ */
+ public boolean isEmpty() {
+ boolean ret = false;
+ if (mSourceAddressType == LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
+ && mSourceDevice == null
+ && mSourceAdvSid == (byte) 0
+ && mPaSyncState == LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID
+ && mEncryptionStatus == LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID
+ && mAudioSyncState == LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID
+ && mBadBroadcastCode == null
+ && mNumSubGroups == 0
+ && mSubgroupBisSyncState.size() == 0
+ && mSubgroupMetadata.size() == 0
+ && mBroadcastCode == null) {
+ ret = true;
+ }
+ return ret;
+ }
+
+ /**
+ * Compares an instance of {@link BluetoothLeBroadcastSourceInfo} with the provided instance.
+ *
+ * @hide
+ */
+ public boolean matches(BluetoothLeBroadcastSourceInfo srcInfo) {
+ boolean ret = false;
+ if (srcInfo == null) {
+ ret = false;
+ } else {
+ if (mSourceDevice == null) {
+ if (mSourceAdvSid == srcInfo.getAdvertisingSid()
+ && mSourceAddressType == srcInfo.getAdvAddressType()) {
+ ret = true;
+ }
+ } else {
+ if (mSourceDevice.equals(srcInfo.getSourceDevice())
+ && mSourceAdvSid == srcInfo.getAdvertisingSid()
+ && mSourceAddressType == srcInfo.getAdvAddressType()
+ && mBroadcastId == srcInfo.getBroadcastId()) {
+ ret = true;
+ }
+ }
+ }
+ return ret;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mSourceId,
+ mSourceAddressType,
+ mSourceDevice,
+ mSourceAdvSid,
+ mBroadcastId,
+ mPaSyncState,
+ mEncryptionStatus,
+ mAudioSyncState,
+ mBadBroadcastCode,
+ mNumSubGroups,
+ mSubgroupBisSyncState,
+ mSubgroupMetadata,
+ mBroadcastCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "{BluetoothLeBroadcastSourceInfo : mSourceId"
+ + mSourceId
+ + " addressType: "
+ + mSourceAddressType
+ + " sourceDevice: "
+ + mSourceDevice
+ + " mSourceAdvSid:"
+ + mSourceAdvSid
+ + " mBroadcastId:"
+ + mBroadcastId
+ + " mPaSyncState:"
+ + mPaSyncState
+ + " mEncryptionStatus:"
+ + mEncryptionStatus
+ + " mAudioSyncState:"
+ + mAudioSyncState
+ + " mBadBroadcastCode:"
+ + mBadBroadcastCode
+ + " mNumSubGroups:"
+ + mNumSubGroups
+ + " mSubgroupBisSyncState:"
+ + mSubgroupBisSyncState
+ + " mSubgroupMetadata:"
+ + mSubgroupMetadata
+ + " mBroadcastCode:"
+ + mBroadcastCode
+ + "}";
+ }
+
+ /**
+ * Get the Source Id
+ *
+ * @return byte representing the Source Id, {@link
+ * #LE_AUDIO_BROADCAST_ASSISTANT_INVALID_SOURCE_ID} if invalid
+ * @hide
+ */
+ public byte getSourceId() {
+ return mSourceId;
+ }
+
+ /**
+ * Set the Source Id
+ *
+ * @param sourceId source Id
+ * @hide
+ */
+ public void setSourceId(byte sourceId) {
+ mSourceId = sourceId;
+ }
+
+ /**
+ * Set the Broadcast Source device
+ *
+ * @param sourceDevice the Broadcast Source BluetoothDevice
+ * @hide
+ */
+ public void setSourceDevice(@NonNull BluetoothDevice sourceDevice) {
+ mSourceDevice = sourceDevice;
+ }
+
+ /**
+ * Get the Broadcast Source BluetoothDevice
+ *
+ * @return Broadcast Source BluetoothDevice
+ * @hide
+ */
+ public @NonNull BluetoothDevice getSourceDevice() {
+ return mSourceDevice;
+ }
+
+ /**
+ * Set the address type of the Broadcast Source advertisements
+ *
+ * @hide
+ */
+ public void setAdvAddressType(@LeAudioBroadcastSourceAddressType int addressType) {
+ mSourceAddressType = addressType;
+ }
+
+ /**
+ * Get the address type used by advertisements from the Broadcast Source.
+ * BluetoothLeBroadcastSourceInfo Object
+ *
+ * @hide
+ */
+ @LeAudioBroadcastSourceAddressType
+ public int getAdvAddressType() {
+ return mSourceAddressType;
+ }
+
+ /**
+ * Set the advertising SID of the Broadcast Source advertisement.
+ *
+ * @param advSid advertising SID of the Broadcast Source
+ * @hide
+ */
+ public void setAdvertisingSid(byte advSid) {
+ mSourceAdvSid = advSid;
+ }
+
+ /**
+ * Get the advertising SID of the Broadcast Source advertisement.
+ *
+ * @return advertising SID of the Broadcast Source
+ * @hide
+ */
+ public byte getAdvertisingSid() {
+ return mSourceAdvSid;
+ }
+
+ /**
+ * Get the Broadcast ID of the Broadcast Source.
+ *
+ * @return broadcast ID
+ * @hide
+ */
+ public int getBroadcastId() {
+ return mBroadcastId;
+ }
+
+ /**
+ * Set the Periodic Advertising (PA) Sync State.
+ *
+ * @hide
+ */
+ /*package*/ void setPaSyncState(@LeAudioBroadcastSinkPaSyncState int paSyncState) {
+ mPaSyncState = paSyncState;
+ }
+
+ /**
+ * Get the Periodic Advertising (PA) Sync State
+ *
+ * @hide
+ */
+ public @LeAudioBroadcastSinkPaSyncState int getMetadataSyncState() {
+ return mPaSyncState;
+ }
+
+ /**
+ * Set the audio sync state
+ *
+ * @hide
+ */
+ /*package*/ void setAudioSyncState(@LeAudioBroadcastSinkAudioSyncState int audioSyncState) {
+ mAudioSyncState = audioSyncState;
+ }
+
+ /**
+ * Get the audio sync state
+ *
+ * @hide
+ */
+ public @LeAudioBroadcastSinkAudioSyncState int getAudioSyncState() {
+ return mAudioSyncState;
+ }
+
+ /**
+ * Set the encryption status
+ *
+ * @hide
+ */
+ /*package*/ void setEncryptionStatus(
+ @LeAudioBroadcastSinkEncryptionState int encryptionStatus) {
+ mEncryptionStatus = encryptionStatus;
+ }
+
+ /**
+ * Get the encryption status
+ *
+ * @hide
+ */
+ public @LeAudioBroadcastSinkEncryptionState int getEncryptionStatus() {
+ return mEncryptionStatus;
+ }
+
+ /**
+ * Get the incorrect broadcast code that the Scan delegator used to decrypt the Broadcast Audio
+ * Stream and failed.
+ *
+ * <p>This code is valid only if {@link #getEncryptionStatus} returns {@link
+ * #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
+ *
+ * @return byte array containing bad broadcast value, null if the current encryption status is
+ * not {@link #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
+ * @hide
+ */
+ public @Nullable byte[] getBadBroadcastCode() {
+ return mBadBroadcastCode;
+ }
+
+ /**
+ * Get the number of subgroups.
+ *
+ * @return number of subgroups
+ * @hide
+ */
+ public byte getNumberOfSubGroups() {
+ return mNumSubGroups;
+ }
+
+ public @NonNull Map<Integer, Integer> getSubgroupBisSyncState() {
+ return mSubgroupBisSyncState;
+ }
+
+ public void setSubgroupBisSyncState(@NonNull Map<Integer, Integer> bisSyncState) {
+ mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
+ }
+
+ /*package*/ void setBroadcastCode(@NonNull String broadcastCode) {
+ mBroadcastCode = broadcastCode;
+ }
+
+ /**
+ * Get the broadcast code
+ *
+ * @return
+ * @hide
+ */
+ public @NonNull String getBroadcastCode() {
+ return mBroadcastCode;
+ }
+
+ /**
+ * Set the broadcast ID
+ *
+ * @param broadcastId broadcast ID of the Broadcast Source
+ * @hide
+ */
+ public void setBroadcastId(int broadcastId) {
+ mBroadcastId = broadcastId;
+ }
+
+ private void writeSubgroupBisSyncStateToParcel(
+ @NonNull Parcel dest, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
+ dest.writeInt(subgroupBisSyncState.size());
+ for (Map.Entry<Integer, Integer> entry : subgroupBisSyncState.entrySet()) {
+ dest.writeInt(entry.getKey());
+ dest.writeInt(entry.getValue());
+ }
+ }
+
+ private static void readSubgroupBisSyncStateFromParcel(
+ @NonNull Parcel in, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
+ int size = in.readInt();
+
+ for (int i = 0; i < size; i++) {
+ Integer key = in.readInt();
+ Integer value = in.readInt();
+ subgroupBisSyncState.put(key, value);
+ }
+ }
+
+ private void writeSubgroupMetadataToParcel(
+ @NonNull Parcel dest, @Nullable Map<Integer, byte[]> subgroupMetadata) {
+ if (subgroupMetadata == null) {
+ dest.writeInt(0);
+ return;
+ }
+
+ dest.writeInt(subgroupMetadata.size());
+ for (Map.Entry<Integer, byte[]> entry : subgroupMetadata.entrySet()) {
+ dest.writeInt(entry.getKey());
+ byte[] metadata = entry.getValue();
+ if (metadata != null) {
+ dest.writeInt(metadata.length);
+ dest.writeByteArray(metadata);
+ }
+ }
+ }
+
+ private static void readSubgroupMetadataFromParcel(
+ @NonNull Parcel in, @NonNull Map<Integer, byte[]> subgroupMetadata) {
+ int size = in.readInt();
+
+ for (int i = 0; i < size; i++) {
+ Integer key = in.readInt();
+ Integer metaDataLen = in.readInt();
+ byte[] metadata = null;
+ if (metaDataLen != 0) {
+ metadata = new byte[metaDataLen];
+ in.readByteArray(metadata);
+ }
+ subgroupMetadata.put(key, metadata);
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastSourceInfo> CREATOR =
+ new Parcelable.Creator<BluetoothLeBroadcastSourceInfo>() {
+ public @NonNull BluetoothLeBroadcastSourceInfo createFromParcel(
+ @NonNull Parcel in) {
+ final byte sourceId = in.readByte();
+ final int sourceAddressType = in.readInt();
+ final BluetoothDevice sourceDevice =
+ in.readTypedObject(BluetoothDevice.CREATOR);
+ final byte sourceAdvSid = in.readByte();
+ final int broadcastId = in.readInt();
+ final int paSyncState = in.readInt();
+ final int audioSyncState = in.readInt();
+ final int encryptionStatus = in.readInt();
+ final int badBroadcastLen = in.readInt();
+ byte[] badBroadcastCode = null;
+
+ if (badBroadcastLen > 0) {
+ badBroadcastCode = new byte[badBroadcastLen];
+ in.readByteArray(badBroadcastCode);
+ }
+ final byte numSubGroups = in.readByte();
+ final String broadcastCode = in.readString();
+ Map<Integer, Integer> subgroupBisSyncState = new HashMap<Integer, Integer>();
+ readSubgroupBisSyncStateFromParcel(in, subgroupBisSyncState);
+ Map<Integer, byte[]> subgroupMetadata = new HashMap<Integer, byte[]>();
+ readSubgroupMetadataFromParcel(in, subgroupMetadata);
+
+ BluetoothLeBroadcastSourceInfo srcInfo =
+ new BluetoothLeBroadcastSourceInfo(
+ sourceId,
+ sourceAddressType,
+ sourceDevice,
+ sourceAdvSid,
+ broadcastId,
+ paSyncState,
+ encryptionStatus,
+ audioSyncState,
+ badBroadcastCode,
+ numSubGroups,
+ subgroupBisSyncState,
+ subgroupMetadata,
+ broadcastCode);
+ return srcInfo;
+ }
+
+ public @NonNull BluetoothLeBroadcastSourceInfo[] newArray(int size) {
+ return new BluetoothLeBroadcastSourceInfo[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeByte(mSourceId);
+ out.writeInt(mSourceAddressType);
+ out.writeTypedObject(mSourceDevice, 0);
+ out.writeByte(mSourceAdvSid);
+ out.writeInt(mBroadcastId);
+ out.writeInt(mPaSyncState);
+ out.writeInt(mAudioSyncState);
+ out.writeInt(mEncryptionStatus);
+
+ if (mBadBroadcastCode != null) {
+ out.writeInt(mBadBroadcastCode.length);
+ out.writeByteArray(mBadBroadcastCode);
+ } else {
+ // zero indicates that there is no "bad broadcast code"
+ out.writeInt(0);
+ }
+ out.writeByte(mNumSubGroups);
+ out.writeString(mBroadcastCode);
+ writeSubgroupBisSyncStateToParcel(out, mSubgroupBisSyncState);
+ writeSubgroupMetadataToParcel(out, mSubgroupMetadata);
+ }
+
+ private static void log(@NonNull String msg) {
+ if (DBG) {
+ Log.d(TAG, msg);
+ }
+ }
+}
+;
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 37fd3ff..cb8988e 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -38,6 +38,8 @@
import android.os.UserHandle;
import android.os.ParcelFileDescriptor;
+import com.android.internal.infra.AndroidFuture;
+
import java.util.List;
/**
@@ -73,6 +75,8 @@
ParceledListSlice getShortcuts(String callingPackage, in ShortcutQueryWrapper query,
in UserHandle user);
+ void getShortcutsAsync(String callingPackage, in ShortcutQueryWrapper query,
+ in UserHandle user, in AndroidFuture<List<ShortcutInfo>> cb);
void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds,
in UserHandle user);
boolean startShortcut(String callingPackage, String packageName, String featureId, String id,
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 617d3ab..a0d348f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -69,6 +69,7 @@
import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.function.pooled.PooledLambda;
import java.io.FileNotFoundException;
@@ -84,6 +85,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
/**
@@ -440,6 +442,17 @@
public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
/**
+ * Includes shortcuts from persistence layer in the search result.
+ *
+ * <p>The caller should make the query on a worker thread since accessing persistence layer
+ * is considered asynchronous.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int FLAG_GET_PERSISTED_DATA = 1 << 12;
+
+ /**
* Populate the persons field in the result. See {@link ShortcutInfo#getPersons()}.
*
* <p>The caller must have the system {@code ACCESS_SHORTCUTS} permission.
@@ -459,6 +472,7 @@
FLAG_MATCH_PINNED_BY_ANY_LAUNCHER,
FLAG_GET_KEY_FIELDS_ONLY,
FLAG_GET_PERSONS_DATA,
+ FLAG_GET_PERSISTED_DATA
})
@Retention(RetentionPolicy.SOURCE)
public @interface QueryFlags {}
@@ -1137,6 +1151,9 @@
@NonNull UserHandle user) {
logErrorForInvalidProfileAccess(user);
try {
+ if ((query.mQueryFlags & ShortcutQuery.FLAG_GET_PERSISTED_DATA) != 0) {
+ return getShortcutsBlocked(query, user);
+ }
// Note this is the only case we need to update the disabled message for shortcuts
// that weren't restored.
// The restore problem messages are only shown by the user, and publishers will never
@@ -1144,13 +1161,29 @@
// changed callback, but that only returns shortcuts with the "key" information, so
// that won't return disabled message.
return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
- new ShortcutQueryWrapper(query), user)
- .getList());
+ new ShortcutQueryWrapper(query), user)
+ .getList());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ private List<ShortcutInfo> getShortcutsBlocked(@NonNull ShortcutQuery query,
+ @NonNull UserHandle user) {
+ logErrorForInvalidProfileAccess(user);
+ final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>();
+ future.thenApply(this::maybeUpdateDisabledMessage);
+ try {
+ mService.getShortcutsAsync(mContext.getPackageName(),
+ new ShortcutQueryWrapper(query), user, future);
+ return future.get();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9a7aeef..338dfd6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -145,6 +145,20 @@
"android.media.PROPERTY_MEDIA_CAPABILITIES";
/**
+ * Application level property that an app can specify to opt-out from having private data
+ * directories both on the internal and external storages.
+ *
+ * <p>Changing the value of this property during app update is not supported, and such updates
+ * will be rejected.
+ *
+ * <p>This should only be set by platform apps that know what they are doing.
+ *
+ * @hide
+ */
+ public static final String PROPERTY_NO_APP_DATA_STORAGE =
+ "android.internal.PROPERTY_NO_APP_DATA_STORAGE";
+
+ /**
* A property value set within the manifest.
* <p>
* The value of a property will only have a single type, as defined by
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 3ed5c64..087a795 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -29,6 +29,8 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
+import com.android.internal.infra.AndroidFuture;
+
import java.util.List;
/**
@@ -50,6 +52,19 @@
@Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
@ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid);
+ /**
+ * Retrieves shortcuts asynchronously. Query will go through persistence layer (thus making the
+ * call async) if querying by shortcutIds in a specific package; otherwise it's effectively the
+ * same as calling {@link #getShortcuts}.
+ */
+ public abstract void
+ getShortcutsAsync(int launcherUserId,
+ @NonNull String callingPackage, long changedSince,
+ @Nullable String packageName, @Nullable List<String> shortcutIds,
+ @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
+ @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid,
+ AndroidFuture<List<ShortcutInfo>> cb);
+
public abstract boolean
isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String id, int userId);
@@ -63,6 +78,14 @@
@NonNull String packageName, @NonNull String shortcutId, int userId,
int callingPid, int callingUid);
+ /**
+ * Retrieves the intents from a specified shortcut asynchronously.
+ */
+ public abstract void createShortcutIntentsAsync(
+ int launcherUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId,
+ int callingPid, int callingUid, @NonNull AndroidFuture<Intent[]> cb);
+
public abstract void addListener(@NonNull ShortcutChangeListener listener);
public abstract void addShortcutChangeCallback(
@@ -82,6 +105,13 @@
@NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
+ /**
+ * Retrieves a file descriptor from the icon in a specified shortcut asynchronously.
+ */
+ public abstract void getShortcutIconFdAsync(int launcherUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId,
+ @NonNull AndroidFuture<ParcelFileDescriptor> cb);
+
public abstract boolean hasShortcutHostPermission(int launcherUserId,
@NonNull String callingPackage, int callingPid, int callingUid);
@@ -117,6 +147,14 @@
public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
+ /**
+ * Retrieves the icon Uri of the shortcut asynchronously, and grants Uri read permission to the
+ * caller.
+ */
+ public abstract void getShortcutIconUriAsync(int launcherUserId,
+ @NonNull String launcherPackage, @NonNull String packageName,
+ @NonNull String shortcutId, int userId, @NonNull AndroidFuture<String> cb);
+
public abstract boolean isSharingShortcut(int callingUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId,
@NonNull IntentFilter filter);
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 26f0826..77b8be3 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -59,6 +59,72 @@
"include-filter": "android.content.pm.cts"
}
]
+ },
+ {
+ "name": "CtsUsesNativeLibraryTest",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "CtsAppSearchHostTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "CtsSilentUpdateHostTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "CtsSuspendAppsTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "CtsSecureFrpInstallTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
+ },
+ {
+ "name": "CtsSuspendAppsPermissionTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ }
+ ]
}
],
"postsubmit": [
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 16deaa0..f336672 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -21,6 +21,7 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
@@ -934,6 +935,13 @@
);
}
+ if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) {
+ return input.error(
+ INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Declare duplicate permissions with different protection levels."
+ );
+ }
+
convertCompatPermissions(pkg);
convertSplitPermissions(pkg);
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index 66e9d3d..86c8f02 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -27,6 +27,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.R;
@@ -34,6 +35,7 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.List;
/** @hide */
public class ParsedPermissionUtils {
@@ -271,4 +273,29 @@
}
return size;
}
+
+ /**
+ * @return {@code true} if the package declares duplicate permissions with different
+ * protection levels.
+ */
+ public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) {
+ final List<ParsedPermission> permissions = pkg.getPermissions();
+ final int size = permissions.size();
+ if (size > 0) {
+ final ArrayMap<String, ParsedPermission> checkDuplicatePerm = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ final ParsedPermission parsedPermission = permissions.get(i);
+ final String name = parsedPermission.getName();
+ final ParsedPermission perm = checkDuplicatePerm.get(name);
+ // Since a permission tree is also added as a permission with normal protection
+ // level, we need to skip if the parsedPermission is a permission tree.
+ if (perm != null && !(perm.isTree() || parsedPermission.isTree())
+ && perm.getProtectionLevel() != parsedPermission.getProtectionLevel()) {
+ return true;
+ }
+ checkDuplicatePerm.put(name, parsedPermission);
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index f4b427959f..596f431 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -339,7 +339,8 @@
out.writeInt(template.getMatchRule());
BackupUtils.writeString(out, template.getSubscriberIds().iterator().next());
- BackupUtils.writeString(out, template.getWifiNetworkKey());
+ BackupUtils.writeString(out, template.getWifiNetworkKeys().isEmpty()
+ ? null : template.getWifiNetworkKeys().iterator().next());
out.writeInt(template.getMeteredness());
return baos.toByteArray();
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fa209cc..520730f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3374,6 +3374,11 @@
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
/**
+ * Returns aggregated wake lock stats.
+ */
+ public abstract WakeLockStats getWakeLockStats();
+
+ /**
* Returns Timers tracking the total time of each Resource Power Manager state and voter.
*/
public abstract Map<String, ? extends Timer> getRpmStats();
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 7f526c1..6339435 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -157,6 +157,7 @@
@Retention(RetentionPolicy.SOURCE)
public @interface WifiSupplState {}
+
private final IBatteryStats mBatteryStats;
/** @hide */
@@ -352,6 +353,21 @@
}
/**
+ * Retrieves accumulate wake lock stats.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BATTERY_STATS)
+ @NonNull
+ public WakeLockStats getWakeLockStats() {
+ try {
+ return mBatteryStats.getWakeLockStats();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Indicates an app acquiring full wifi lock.
*
* @param ws worksource (to be used for battery blaming).
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index dbb5a2c..70aaa5e 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -15,10 +15,13 @@
*/
package android.os;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityThread;
@@ -2690,6 +2693,12 @@
((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name);
}
+ /** @hide */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static void noteUntaggedSocket() {
+ if (vmUntaggedSocketEnabled()) onUntaggedSocket();
+ }
+
/**
* For code to note that a resource was obtained using a type other than its defined type. This
* is a no-op unless the current thread's {@link android.os.StrictMode.ThreadPolicy} has {@link
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index d8f6344..b9252d6 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -311,7 +311,6 @@
* time or throw.
*
* @throws DateTimeException when no accurate network time can be provided.
- * @hide
*/
public static @NonNull Clock currentNetworkTimeClock() {
return new SimpleClock(ZoneOffset.UTC) {
diff --git a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl b/core/java/android/os/WakeLockStats.aidl
similarity index 76%
rename from telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
rename to core/java/android/os/WakeLockStats.aidl
index 69f479c..be08d78 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IResultCallback.aidl
+++ b/core/java/android/os/WakeLockStats.aidl
@@ -13,11 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.internal.telephony.euicc;
-import android.content.Intent;
+package android.os;
-/** @hide */
-oneway interface IResultCallback {
- void onComplete(int resultCode, in Intent resultIntent);
-}
+/** {@hide} */
+parcelable WakeLockStats;
diff --git a/core/java/android/os/WakeLockStats.java b/core/java/android/os/WakeLockStats.java
new file mode 100644
index 0000000..05a7313
--- /dev/null
+++ b/core/java/android/os/WakeLockStats.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Snapshot of wake lock stats.
+ * @hide
+ */
+public final class WakeLockStats implements Parcelable {
+
+ /** @hide */
+ public static class WakeLock {
+ public final int uid;
+ @NonNull
+ public final String name;
+ public final int timesAcquired;
+ public final long totalTimeHeldMs;
+
+ /**
+ * Time in milliseconds that the lock has been held or 0 if not currently holding the lock
+ */
+ public final long timeHeldMs;
+
+ public WakeLock(int uid, @NonNull String name, int timesAcquired, long totalTimeHeldMs,
+ long timeHeldMs) {
+ this.uid = uid;
+ this.name = name;
+ this.timesAcquired = timesAcquired;
+ this.totalTimeHeldMs = totalTimeHeldMs;
+ this.timeHeldMs = timeHeldMs;
+ }
+
+ private WakeLock(Parcel in) {
+ uid = in.readInt();
+ name = in.readString();
+ timesAcquired = in.readInt();
+ totalTimeHeldMs = in.readLong();
+ timeHeldMs = in.readLong();
+ }
+
+ private void writeToParcel(Parcel out) {
+ out.writeInt(uid);
+ out.writeString(name);
+ out.writeInt(timesAcquired);
+ out.writeLong(totalTimeHeldMs);
+ out.writeLong(timeHeldMs);
+ }
+
+ @Override
+ public String toString() {
+ return "WakeLock{"
+ + "uid=" + uid
+ + ", name='" + name + '\''
+ + ", timesAcquired=" + timesAcquired
+ + ", totalTimeHeldMs=" + totalTimeHeldMs
+ + ", timeHeldMs=" + timeHeldMs
+ + '}';
+ }
+ }
+
+ private final List<WakeLock> mWakeLocks;
+
+ /** @hide **/
+ public WakeLockStats(@NonNull List<WakeLock> wakeLocks) {
+ mWakeLocks = wakeLocks;
+ }
+
+ @NonNull
+ public List<WakeLock> getWakeLocks() {
+ return mWakeLocks;
+ }
+
+ private WakeLockStats(Parcel in) {
+ final int size = in.readInt();
+ mWakeLocks = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ mWakeLocks.add(new WakeLock(in));
+ }
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ final int size = mWakeLocks.size();
+ out.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ WakeLock stats = mWakeLocks.get(i);
+ stats.writeToParcel(out);
+ }
+ }
+
+ @NonNull
+ public static final Creator<WakeLockStats> CREATOR =
+ new Creator<WakeLockStats>() {
+ public WakeLockStats createFromParcel(Parcel in) {
+ return new WakeLockStats(in);
+ }
+
+ public WakeLockStats[] newArray(int size) {
+ return new WakeLockStats[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "WakeLockStats " + mWakeLocks;
+ }
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 5e4057b..29accb9 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1525,10 +1525,11 @@
result = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100;
} else {
// Else, linearly interpolate the amount of space to reserve
- result = ((CACHE_RESERVE_PERCENT_HIGH - CACHE_RESERVE_PERCENT_LOW)
- * (usableBytes - storageThresholdHighBytes) + CACHE_RESERVE_PERCENT_HIGH
- * (storageThresholdHighBytes - storageThresholdLowBytes)) * totalBytes
- / (100 * (storageThresholdHighBytes - storageThresholdLowBytes));
+ double slope = (CACHE_RESERVE_PERCENT_HIGH - CACHE_RESERVE_PERCENT_LOW) * totalBytes
+ / (100.0 * (storageThresholdHighBytes - storageThresholdLowBytes));
+ double intercept = totalBytes * CACHE_RESERVE_PERCENT_LOW / 100.0
+ - storageThresholdLowBytes * slope;
+ result = Math.round(slope * usableBytes + intercept);
}
return result;
}
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 66e1c5a..0e32a78 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -54,4 +54,6 @@
void getGroupOfPlatformPermission(
in String permissionName,
in AndroidFuture<String> callback);
+ void getUnusedAppCount(
+ in AndroidFuture callback);
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 00f9e45..a0788e7 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -69,6 +69,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
+import java.util.function.IntConsumer;
/**
* Interface for communicating with the permission controller.
@@ -786,4 +787,34 @@
}
}, executor);
}
+
+ /**
+ * Get the number of unused, hibernating apps for the user.
+ *
+ * @param executor executor to run callback on
+ * @param callback callback for when result is generated
+ */
+ public void getUnusedAppCount(@NonNull @CallbackExecutor Executor executor,
+ @NonNull IntConsumer callback) {
+ checkNotNull(executor);
+ checkNotNull(callback);
+
+ mRemoteService.postAsync(service -> {
+ AndroidFuture<Integer> unusedAppCountResult = new AndroidFuture<>();
+ service.getUnusedAppCount(unusedAppCountResult);
+ return unusedAppCountResult;
+ }).whenCompleteAsync((count, err) -> {
+ if (err != null) {
+ Log.e(TAG, "Error getting unused app count", err);
+ callback.accept(0);
+ } else {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ callback.accept((int) count);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
}
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 8854e27..c979303 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -340,6 +340,20 @@
throw new AbstractMethodError("Must be overridden in implementing class");
}
+ /**
+ * Get the count of unused, hibernating apps on the device.
+ *
+ * @param callback callback after count is retrieved
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_APP_HIBERNATION)
+ @NonNull
+ public void onGetUnusedAppCount(@NonNull IntConsumer callback) {
+ throw new AbstractMethodError("Must be overridden in implementing class");
+ }
+
@Override
public final @NonNull IBinder onBind(Intent intent) {
return new IPermissionController.Stub() {
@@ -618,6 +632,20 @@
callback.completeExceptionally(t);
}
}
+
+ @Override
+ public void getUnusedAppCount(@NonNull AndroidFuture callback) {
+ try {
+ Objects.requireNonNull(callback);
+
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.MANAGE_APP_HIBERNATION);
+
+ PermissionControllerService.this.onGetUnusedAppCount(callback::complete);
+ } catch (Throwable t) {
+ callback.completeExceptionally(t);
+ }
+ }
};
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 910fec6..55ffdab 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -391,6 +391,21 @@
"android.settings.REDUCE_BRIGHT_COLORS_SETTINGS";
/**
+ * Activity Action: Show settings to allow configuration of Color correction.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_COLOR_CORRECTION_SETTINGS =
+ "com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of Color inversion.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -10104,6 +10119,14 @@
"theme_customization_overlay_packages";
/**
+ * Indicates whether the device is in kids nav mode.
+ * <p>Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ public static final String NAV_BAR_KIDS_MODE = "nav_bar_kids_mode";
+
+ /**
* Navigation bar mode.
* 0 = 3 button
* 1 = 2 button
@@ -10467,13 +10490,6 @@
public static final String COMMUNAL_MODE_ENABLED = "communal_mode_enabled";
/**
- * An array of all the packages which have been enabled for hub mode by the user.
- *
- * @hide
- */
- public static final String COMMUNAL_MODE_PACKAGES = "communal_mode_packages";
-
- /**
* An array of SSIDs of Wi-Fi networks that, when connected, are considered safe to enable
* the communal mode.
*
@@ -15201,7 +15217,10 @@
* {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
*
* @hide
+ * @deprecated Use {@link android.view.autofill.AutofillManager
+ * #DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES} instead.
*/
+ @Deprecated
@SystemApi
@Readable
public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 8db62f6..adb8b86 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1872,7 +1872,7 @@
float x, float y, float pressure, float size, int metaState,
float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
return obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
- xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_CLASS_POINTER,
+ xPrecision, yPrecision, deviceId, edgeFlags, InputDevice.SOURCE_UNKNOWN,
DEFAULT_DISPLAY);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d0a5835..49ece5f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -972,9 +972,9 @@
mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
if (mViewVisibility) {
- mTmpTransaction.show(mSurfaceControl);
+ geometryTransaction.show(mSurfaceControl);
} else {
- mTmpTransaction.hide(mSurfaceControl);
+ geometryTransaction.hide(mSurfaceControl);
}
if (mSurfacePackage != null) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 1122056..bb13c1e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -472,6 +472,24 @@
public static final String DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT =
"augmented_service_request_timeout";
+ /**
+ * Sets allowed list for the autofill compatibility mode.
+ *
+ * The list of packages is {@code ":"} colon delimited, and each entry has the name of the
+ * package and an optional list of url bar resource ids (the list is delimited by
+ * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
+ *
+ * <p>For example, a list with 3 packages {@code p1}, {@code p2}, and {@code p3}, where
+ * package {@code p1} have one id ({@code url_bar}, {@code p2} has none, and {@code p3 }
+ * have 2 ids {@code url_foo} and {@code url_bas}) would be
+ * {@code p1[url_bar]:p2:p3[url_foo,url_bas]}
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES =
+ "compat_mode_allowed_packages";
+
/** @hide */
public static final int RESULT_OK = 0;
/** @hide */
diff --git a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
index 60688ea..ba45b85 100644
--- a/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
+++ b/core/java/android/view/selectiontoolbar/SelectionToolbarManager.java
@@ -20,6 +20,7 @@
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
+import android.provider.DeviceConfig;
import java.util.Objects;
@@ -40,6 +41,11 @@
*/
public static final String LOG_TAG = "SelectionToolbar";
+ /**
+ * Whether system selection toolbar is enabled.
+ */
+ private static final String REMOTE_SELECTION_TOOLBAR_ENABLED =
+ "remote_selection_toolbar_enabled";
@NonNull
private final Context mContext;
@@ -86,4 +92,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ private boolean isRemoteSelectionToolbarEnabled() {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SELECTION_TOOLBAR,
+ REMOTE_SELECTION_TOOLBAR_ENABLED, false);
+ }
+
+ /**
+ * Returns {@code true} if remote render selection toolbar enabled, otherwise
+ * returns {@code false}.
+ */
+ public static boolean isRemoteSelectionToolbarEnabled(Context context) {
+ SelectionToolbarManager manager = context.getSystemService(SelectionToolbarManager.class);
+ if (manager != null) {
+ return manager.isRemoteSelectionToolbarEnabled();
+ }
+ return false;
+ }
}
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 090dbff..3f65f47 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -22,6 +22,7 @@
import android.annotation.SuppressLint;
import android.annotation.UiThread;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.content.Context;
@@ -48,13 +49,13 @@
*/
int SPLASH_SCREEN_STYLE_UNDEFINED = -1;
/**
- * Force splash screen to be empty.
- * @hide
+ * Flag to be used with {@link ActivityOptions#setSplashScreenStyle}, to avoid showing the
+ * splash screen icon of the launched activity
*/
int SPLASH_SCREEN_STYLE_EMPTY = 0;
/**
- * Force splash screen to show icon.
- * @hide
+ * Flag to be used with {@link ActivityOptions#setSplashScreenStyle}, to show the splash screen
+ * icon of the launched activity.
*/
int SPLASH_SCREEN_STYLE_ICON = 1;
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 1d13b73f..587876d 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -22,6 +22,7 @@
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.ParcelFileDescriptor;
+import android.os.WakeLockStats;
import android.os.WorkSource;
import android.os.connectivity.CellularBatteryStats;
import android.os.connectivity.WifiActivityEnergyInfo;
@@ -157,6 +158,10 @@
/** {@hide} */
GpsBatteryStats getGpsBatteryStats();
+ /** {@hide} */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.BATTERY_STATS)")
+ WakeLockStats getWakeLockStats();
+
HealthStatsParceler takeUidSnapshot(int uid);
HealthStatsParceler[] takeUidSnapshots(in int[] uid);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 209c64a..21f719c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -60,6 +60,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.WakeLockStats;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
import android.os.connectivity.CellularBatteryStats;
@@ -1143,6 +1144,37 @@
return mKernelWakelockStats;
}
+ @Override
+ public WakeLockStats getWakeLockStats() {
+ final long realtimeMs = mClock.elapsedRealtime();
+ final long realtimeUs = realtimeMs * 1000;
+ List<WakeLockStats.WakeLock> uidWakeLockStats = new ArrayList<>();
+ for (int i = mUidStats.size() - 1; i >= 0; i--) {
+ final Uid uid = mUidStats.valueAt(i);
+ final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
+ uid.mWakelockStats.getMap();
+ for (int j = wakelockStats.size() - 1; j >= 0; j--) {
+ final String name = wakelockStats.keyAt(j);
+ final Uid.Wakelock wakelock = (Uid.Wakelock) wakelockStats.valueAt(j);
+ final DualTimer timer = wakelock.mTimerPartial;
+ if (timer != null) {
+ final long totalTimeLockHeldMs =
+ timer.getTotalTimeLocked(realtimeUs, STATS_SINCE_CHARGED) / 1000;
+ if (totalTimeLockHeldMs != 0) {
+ uidWakeLockStats.add(
+ new WakeLockStats.WakeLock(uid.getUid(), name,
+ timer.getCountLocked(STATS_SINCE_CHARGED),
+ totalTimeLockHeldMs,
+ timer.isRunningLocked()
+ ? timer.getCurrentDurationMsLocked(realtimeMs)
+ : 0));
+ }
+ }
+ }
+ }
+ return new WakeLockStats(uidWakeLockStats);
+ }
+
String mLastWakeupReason = null;
long mLastWakeupUptimeMs = 0;
private final HashMap<String, SamplingTimer> mWakeupReasonStats = new HashMap<>();
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 6541b14..ba7a0ef 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -121,7 +121,7 @@
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.BackgroundFallback;
import com.android.internal.widget.DecorCaptionView;
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
import java.util.List;
import java.util.function.Consumer;
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 1db7426..3c6b7ff 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -162,4 +162,20 @@
void requestAddTile(in ComponentName componentName, in CharSequence label, in Icon icon, int userId, in IAddTileResultCallback callback);
void cancelRequestAddTile(in String packageName);
+
+ /**
+ * Overrides the navigation bar mode.
+ *
+ * @param navBarModeOverride the mode of the navigation bar override to be set.
+ *
+ * @hide
+ */
+ void setNavBarModeOverride(int navBarModeOverride);
+
+ /**
+ * Gets the navigation bar mode override.
+ *
+ * @hide
+ */
+ int getNavBarModeOverride();
}
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 36913b7..06e69f2 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -33,7 +33,7 @@
import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
import java.util.Arrays;
import java.util.Objects;
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbar.java
similarity index 88%
rename from core/java/com/android/internal/widget/FloatingToolbar.java
rename to core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbar.java
index a0bf9b5..e75f372 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbar.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.widget;
+package com.android.internal.widget.floatingtoolbar;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -50,14 +50,10 @@
private final FloatingToolbarPopup mPopup;
private final Rect mContentRect = new Rect();
- private final Rect mPreviousContentRect = new Rect();
private Menu mMenu;
private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
- private int mSuggestedWidth;
- private boolean mWidthChanged = true;
-
private final OnLayoutChangeListener mOrientationChangeHandler = new OnLayoutChangeListener() {
private final Rect mNewRect = new Rect();
@@ -71,7 +67,7 @@
mNewRect.set(newLeft, newRight, newTop, newBottom);
mOldRect.set(oldLeft, oldRight, oldTop, oldBottom);
if (mPopup.isShowing() && !mNewRect.equals(mOldRect)) {
- mWidthChanged = true;
+ mPopup.setWidthChanged(true);
updateLayout();
}
}
@@ -114,7 +110,7 @@
// TODO(b/65172902): Pass context in constructor when DecorView (and other callers)
// supports multi-display.
mWindow = Objects.requireNonNull(window);
- mPopup = new FloatingToolbarPopup(window.getContext(), window.getDecorView());
+ mPopup = FloatingToolbarPopup.createInstance(window.getContext(), window.getDecorView());
}
/**
@@ -159,11 +155,7 @@
* toolbar.
*/
public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
- // Check if there's been a substantial width spec change.
- int difference = Math.abs(suggestedWidth - mSuggestedWidth);
- mWidthChanged = difference > (mSuggestedWidth * 0.2);
-
- mSuggestedWidth = suggestedWidth;
+ mPopup.setSuggestedWidth(suggestedWidth);
return this;
}
@@ -232,19 +224,7 @@
private void doShow() {
List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
menuItems.sort(mMenuItemComparator);
- if (mPopup.isLayoutRequired(menuItems) || mWidthChanged) {
- mPopup.dismiss();
- mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
- } else {
- mPopup.updateMenuItems(menuItems, mMenuItemClickListener);
- }
- if (!mPopup.isShowing()) {
- mPopup.show(mContentRect);
- } else if (!mPreviousContentRect.equals(mContentRect)) {
- mPopup.updateCoordinates(mContentRect);
- }
- mWidthChanged = false;
- mPreviousContentRect.set(mContentRect);
+ mPopup.show(menuItems, mMenuItemClickListener, mContentRect);
}
/**
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
new file mode 100644
index 0000000..f47700c
--- /dev/null
+++ b/core/java/com/android/internal/widget/floatingtoolbar/FloatingToolbarPopup.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.floatingtoolbar;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.selectiontoolbar.SelectionToolbarManager;
+import android.widget.PopupWindow;
+
+import java.util.List;
+
+/**
+ * A popup window used by the {@link FloatingToolbar} to render menu items.
+ *
+ */
+public interface FloatingToolbarPopup {
+
+ /**
+ * Sets the suggested dp width of this floating toolbar.
+ * The actual width will be about this size but there are no guarantees that it will be exactly
+ * the suggested width.
+ */
+ void setSuggestedWidth(int suggestedWidth);
+
+ /**
+ * Sets if the floating toolbar width changed.
+ */
+ void setWidthChanged(boolean widthChanged);
+
+ /**
+ * Shows this popup at the specified coordinates.
+ * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+ */
+ void show(List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener,
+ Rect contentRect);
+
+ /**
+ * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
+ */
+ void dismiss();
+
+ /**
+ * Hides this popup. This is a no-op if this popup is not showing.
+ * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
+ */
+ void hide();
+
+ /**
+ * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+ */
+ boolean isShowing();
+
+ /**
+ * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
+ */
+ boolean isHidden();
+
+ /**
+ * Makes this toolbar "outside touchable" and sets the onDismissListener.
+ *
+ * @param outsideTouchable if true, the popup will be made "outside touchable" and
+ * "non focusable". The reverse will happen if false.
+ * @param onDismiss
+ *
+ * @return true if the "outsideTouchable" setting was modified. Otherwise returns false
+ *
+ * @see PopupWindow#setOutsideTouchable(boolean)
+ * @see PopupWindow#setFocusable(boolean)
+ * @see PopupWindow.OnDismissListener
+ */
+ boolean setOutsideTouchable(boolean outsideTouchable, PopupWindow.OnDismissListener onDismiss);
+
+ /**
+ * Returns {@link RemoteFloatingToolbarPopup} implementation if the system selection toolbar
+ * enabled, otherwise returns {@link LocalFloatingToolbarPopup} implementation.
+ */
+ static FloatingToolbarPopup createInstance(Context context, View parent) {
+ boolean enabled = SelectionToolbarManager.isRemoteSelectionToolbarEnabled(context);
+ return enabled
+ ? new RemoteFloatingToolbarPopup(context, parent)
+ : new LocalFloatingToolbarPopup(context, parent);
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/FloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
similarity index 96%
rename from core/java/com/android/internal/widget/FloatingToolbarPopup.java
rename to core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
index e0388f6..80d8bd7 100644
--- a/core/java/com/android/internal/widget/FloatingToolbarPopup.java
+++ b/core/java/com/android/internal/widget/floatingtoolbar/LocalFloatingToolbarPopup.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.widget;
+package com.android.internal.widget.floatingtoolbar;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -70,13 +70,13 @@
import java.util.Objects;
/**
- * A popup window used by the floating toolbar.
+ * A popup window used by the floating toolbar to render menu items in the local app process.
*
* This class is responsible for the rendering/animation of the floating toolbar.
* It holds 2 panels (i.e. main panel and overflow panel) and an overflow button
* to transition between panels.
*/
-public final class FloatingToolbarPopup {
+public final class LocalFloatingToolbarPopup implements FloatingToolbarPopup {
/* Minimum and maximum number of items allowed in the overflow. */
private static final int MIN_OVERFLOW_SIZE = 2;
@@ -94,7 +94,7 @@
private final ViewGroup mContentContainer; // holds all contents.
private final ViewGroup mMainPanel; // holds menu items that are initially displayed.
// holds menu items hidden in the overflow.
- private final FloatingToolbarPopup.OverflowPanel mOverflowPanel;
+ private final OverflowPanel mOverflowPanel;
private final ImageButton mOverflowButton; // opens/closes the overflow.
/* overflow button drawables. */
private final Drawable mArrow;
@@ -102,8 +102,7 @@
private final AnimatedVectorDrawable mToArrow;
private final AnimatedVectorDrawable mToOverflow;
- private final FloatingToolbarPopup.OverflowPanelViewHelper
- mOverflowPanelViewHelper;
+ private final OverflowPanelViewHelper mOverflowPanelViewHelper;
/* Animation interpolators. */
private final Interpolator mLogAccelerateInterpolator;
@@ -138,7 +137,7 @@
private final int mIconTextSpacing;
/**
- * @see FloatingToolbarPopup.OverflowPanelViewHelper#preparePopupContent().
+ * @see OverflowPanelViewHelper#preparePopupContent().
*/
private final Runnable mPreparePopupContentRTLHelper = new Runnable() {
@Override
@@ -184,16 +183,20 @@
private int mTransitionDurationScale; // Used to scale the toolbar transition duration.
+ private final Rect mPreviousContentRect = new Rect();
+ private int mSuggestedWidth;
+ private boolean mWidthChanged = true;
+
/**
* Initializes a new floating toolbar popup.
*
* @param parent A parent view to get the {@link android.view.View#getWindowToken()} token
* from.
*/
- public FloatingToolbarPopup(Context context, View parent) {
+ public LocalFloatingToolbarPopup(Context context, View parent) {
mParent = Objects.requireNonNull(parent);
mContext = applyDefaultTheme(context);
- mContentContainer = createContentContainer(context);
+ mContentContainer = createContentContainer(mContext);
mPopupWindow = createPopupWindow(mContentContainer);
mMarginHorizontal = parent.getResources()
.getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
@@ -205,7 +208,7 @@
.getDimensionPixelSize(R.dimen.floating_toolbar_icon_text_spacing);
// Interpolators
- mLogAccelerateInterpolator = new FloatingToolbarPopup.LogAccelerateInterpolator();
+ mLogAccelerateInterpolator = new LogAccelerateInterpolator();
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
mContext, android.R.interpolator.fast_out_slow_in);
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
@@ -231,8 +234,7 @@
mOverflowButton = createOverflowButton();
mOverflowButtonSize = measure(mOverflowButton);
mMainPanel = createMainPanel();
- mOverflowPanelViewHelper =
- new FloatingToolbarPopup.OverflowPanelViewHelper(mContext, mIconTextSpacing);
+ mOverflowPanelViewHelper = new OverflowPanelViewHelper(mContext, mIconTextSpacing);
mOverflowPanel = createOverflowPanel();
// Animation. Need views.
@@ -263,19 +265,7 @@
});
}
- /**
- * Makes this toolbar "outside touchable" and sets the onDismissListener.
- *
- * @param outsideTouchable if true, the popup will be made "outside touchable" and
- * "non focusable". The reverse will happen if false.
- * @param onDismiss
- *
- * @return true if the "outsideTouchable" setting was modified. Otherwise returns false
- *
- * @see PopupWindow#setOutsideTouchable(boolean)
- * @see PopupWindow#setFocusable(boolean)
- * @see PopupWindow.OnDismissListener
- */
+ @Override
public boolean setOutsideTouchable(
boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) {
boolean ret = false;
@@ -293,7 +283,7 @@
* Lays out buttons for the specified menu items.
* Requires a subsequent call to {@link FloatingToolbar#show()} to show the items.
*/
- public void layoutMenuItems(
+ private void layoutMenuItems(
List<MenuItem> menuItems,
MenuItem.OnMenuItemClickListener menuItemClickListener,
int suggestedWidth) {
@@ -314,7 +304,7 @@
*
* @see #isLayoutRequired(List<MenuItem>)
*/
- public void updateMenuItems(
+ private void updateMenuItems(
List<MenuItem> menuItems, MenuItem.OnMenuItemClickListener menuItemClickListener) {
mMenuItems.clear();
for (MenuItem menuItem : menuItems) {
@@ -326,15 +316,42 @@
/**
* Returns true if this popup needs a relayout to properly render the specified menu items.
*/
- public boolean isLayoutRequired(List<MenuItem> menuItems) {
+ private boolean isLayoutRequired(List<MenuItem> menuItems) {
return !MenuItemRepr.reprEquals(menuItems, mMenuItems.values());
}
- /**
- * Shows this popup at the specified coordinates.
- * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
- */
- public void show(Rect contentRectOnScreen) {
+ @Override
+ public void setWidthChanged(boolean widthChanged) {
+ mWidthChanged = widthChanged;
+ }
+
+ @Override
+ public void setSuggestedWidth(int suggestedWidth) {
+ // Check if there's been a substantial width spec change.
+ int difference = Math.abs(suggestedWidth - mSuggestedWidth);
+ mWidthChanged = difference > (mSuggestedWidth * 0.2);
+ mSuggestedWidth = suggestedWidth;
+ }
+
+ @Override
+ public void show(List<MenuItem> menuItems,
+ MenuItem.OnMenuItemClickListener menuItemClickListener, Rect contentRect) {
+ if (isLayoutRequired(menuItems) || mWidthChanged) {
+ dismiss();
+ layoutMenuItems(menuItems, menuItemClickListener, mSuggestedWidth);
+ } else {
+ updateMenuItems(menuItems, menuItemClickListener);
+ }
+ if (!isShowing()) {
+ show(contentRect);
+ } else if (!mPreviousContentRect.equals(contentRect)) {
+ updateCoordinates(contentRect);
+ }
+ mWidthChanged = false;
+ mPreviousContentRect.set(contentRect);
+ }
+
+ private void show(Rect contentRectOnScreen) {
Objects.requireNonNull(contentRectOnScreen);
if (isShowing()) {
@@ -357,9 +374,7 @@
runShowAnimation();
}
- /**
- * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
- */
+ @Override
public void dismiss() {
if (mDismissed) {
return;
@@ -373,10 +388,7 @@
setZeroTouchableSurface();
}
- /**
- * Hides this popup. This is a no-op if this popup is not showing.
- * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
- */
+ @Override
public void hide() {
if (!isShowing()) {
return;
@@ -387,16 +399,12 @@
setZeroTouchableSurface();
}
- /**
- * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
- */
+ @Override
public boolean isShowing() {
return !mDismissed && !mHidden;
}
- /**
- * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
- */
+ @Override
public boolean isHidden() {
return mHidden;
}
@@ -406,7 +414,7 @@
* The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
* This is a no-op if this popup is not showing.
*/
- public void updateCoordinates(Rect contentRectOnScreen) {
+ private void updateCoordinates(Rect contentRectOnScreen) {
Objects.requireNonNull(contentRectOnScreen);
if (!isShowing() || !mPopupWindow.isShowing()) {
@@ -1206,9 +1214,8 @@
return overflowButton;
}
- private FloatingToolbarPopup.OverflowPanel createOverflowPanel() {
- final FloatingToolbarPopup.OverflowPanel
- overflowPanel = new FloatingToolbarPopup.OverflowPanel(this);
+ private OverflowPanel createOverflowPanel() {
+ final OverflowPanel overflowPanel = new OverflowPanel(this);
overflowPanel.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
overflowPanel.setDivider(null);
@@ -1307,9 +1314,9 @@
*/
private static final class OverflowPanel extends ListView {
- private final FloatingToolbarPopup mPopup;
+ private final LocalFloatingToolbarPopup mPopup;
- OverflowPanel(FloatingToolbarPopup popup) {
+ OverflowPanel(LocalFloatingToolbarPopup popup) {
super(Objects.requireNonNull(popup).mContext);
this.mPopup = popup;
setScrollBarDefaultDelayBeforeFade(ViewConfiguration.getScrollDefaultDelay() * 3);
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/OWNERS b/core/java/com/android/internal/widget/floatingtoolbar/OWNERS
new file mode 100644
index 0000000..ed9425c
--- /dev/null
+++ b/core/java/com/android/internal/widget/floatingtoolbar/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/selectiontoolbar/OWNERS
diff --git a/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java b/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
new file mode 100644
index 0000000..b3a8128
--- /dev/null
+++ b/core/java/com/android/internal/widget/floatingtoolbar/RemoteFloatingToolbarPopup.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget.floatingtoolbar;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.selectiontoolbar.SelectionToolbarManager;
+import android.widget.PopupWindow;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A popup window used by the floating toolbar to render menu items in the remote system process.
+ *
+ * It holds 2 panels (i.e. main panel and overflow panel) and an overflow button
+ * to transition between panels.
+ */
+public final class RemoteFloatingToolbarPopup implements FloatingToolbarPopup {
+
+ private final SelectionToolbarManager mSelectionToolbarManager;
+ // Parent for the popup window.
+ private final View mParent;
+
+ public RemoteFloatingToolbarPopup(Context context, View parent) {
+ // TODO: implement it
+ mParent = Objects.requireNonNull(parent);
+ mSelectionToolbarManager = context.getSystemService(SelectionToolbarManager.class);
+ }
+
+ @Override
+ public void show(List<MenuItem> menuItems,
+ MenuItem.OnMenuItemClickListener menuItemClickListener, Rect contentRect) {
+ // TODO: implement it
+ }
+
+ @Override
+ public void hide() {
+ // TODO: implement it
+ }
+
+ @Override
+ public void setSuggestedWidth(int suggestedWidth) {
+ // TODO: implement it
+ }
+
+ @Override
+ public void setWidthChanged(boolean widthChanged) {
+ // no-op
+ }
+
+ @Override
+ public void dismiss() {
+ // TODO: implement it
+ }
+
+ @Override
+ public boolean isHidden() {
+ return false;
+ }
+
+ @Override
+ public boolean isShowing() {
+ return false;
+ }
+
+ @Override
+ public boolean setOutsideTouchable(boolean outsideTouchable,
+ PopupWindow.OnDismissListener onDismiss) {
+ return false;
+ }
+}
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 26ff192..d89566c9 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -70,8 +70,8 @@
Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x"
+ Integer.toHexString(options.statsTag) + ", statsUid=" + options.statsUid);
}
- if (options.statsTag == -1 && StrictMode.vmUntaggedSocketEnabled()) {
- StrictMode.onUntaggedSocket();
+ if (options.statsTag == -1) {
+ StrictMode.noteUntaggedSocket();
}
// TODO: skip tagging when options would be no-op
tagSocketFd(fd, options.statsTag, options.statsUid);
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index d66f461..39f17e5 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -849,8 +849,8 @@
XmlUtils.skipCurrentTag(parser);
}
} break;
- case "updatable-library":
- // "updatable-library" is meant to behave exactly like "library"
+ case "apex-library":
+ // "apex-library" is meant to behave exactly like "library"
case "library": {
if (allowLibs) {
String lname = parser.getAttributeValue(null, "name");
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 0eb8c6a..011e051 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -83,17 +83,20 @@
constexpr int INDIC_MIN_PREFIX = 2;
constexpr int INDIC_MIN_SUFFIX = 2;
+ addHyphenator("af", 1, 1); // Afrikaans
addHyphenator("am", 1, 1); // Amharic
addHyphenator("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Assamese
addHyphenator("be", 2, 2); // Belarusian
addHyphenator("bg", 2, 2); // Bulgarian
addHyphenator("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Bengali
+ addHyphenator("cs", 2, 2); // Czech
addHyphenator("cu", 1, 2); // Church Slavonic
addHyphenator("cy", 2, 3); // Welsh
addHyphenator("da", 2, 2); // Danish
addHyphenator("de-1901", 2, 2); // German 1901 orthography
addHyphenator("de-1996", 2, 2); // German 1996 orthography
addHyphenator("de-CH-1901", 2, 2); // Swiss High German 1901 orthography
+ addHyphenator("el", 1, 1); // Greek
addHyphenator("en-GB", 2, 3); // British English
addHyphenator("en-US", 2, 3); // American English
addHyphenator("es", 2, 2); // Spanish
@@ -110,18 +113,23 @@
// Going with a more conservative value of (2, 2) for now.
addHyphenator("hy", 2, 2); // Armenian
addHyphenator("it", 2, 2); // Italian
+ addHyphenator("ka", 1, 2); // Georgian
addHyphenator("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Kannada
addHyphenator("la", 2, 2); // Latin
addHyphenator("lt", 2, 2); // Lithuanian
+ addHyphenator("lv", 2, 2); // Latvian
addHyphenator("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Malayalam
addHyphenator("mn-Cyrl", 2, 2); // Mongolian in Cyrillic script
addHyphenator("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Marathi
addHyphenator("nb", 2, 2); // Norwegian Bokmål
+ addHyphenator("nl", 2, 2); // Dutch
addHyphenator("nn", 2, 2); // Norwegian Nynorsk
addHyphenator("or", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Oriya
addHyphenator("pa", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Punjabi
addHyphenator("pt", 2, 3); // Portuguese
+ addHyphenator("sk", 2, 2); // Slovak
addHyphenator("sl", 2, 2); // Slovenian
+ addHyphenator("sq", 2, 2); // Albanian
addHyphenator("ta", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Tamil
addHyphenator("te", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Telugu
addHyphenator("tk", 2, 2); // Turkmen
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 5090d8c..00b7fd7 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -383,6 +383,7 @@
optional SettingProto multi_press_timeout = 38 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto nav_bar_kids_mode = 91 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto navigation_mode = 76 [ (android.privacy).dest = DEST_AUTOMATIC ];
message NfcPayment {
@@ -665,5 +666,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 91;
+ // Next tag = 92;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31ef2b3..a005eb0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1502,7 +1502,7 @@
<p>Protection level: dangerous
<p> This is a hard restricted permission which cannot be held by an app until
- the installer on record whitelists the permission. For more details see
+ the installer on record allowlists the permission. For more details see
{@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.BODY_SENSORS_BACKGROUND"
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 1f560f4..7d44fd99 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3281,6 +3281,8 @@
</staging-public-group>
<staging-public-group type="array" first-id="0x01d90000">
+ <!-- @hide @SystemApi -->
+ <public name="config_optionalIpSecAlgorithms" />
</staging-public-group>
<staging-public-group type="drawable" first-id="0x01d80000">
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
index 2c3c1ed..9bb064c 100644
--- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -25,6 +25,7 @@
import android.content.pm.PackageInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.platform.test.annotations.Presubmit;
import androidx.annotation.NonNull;
import androidx.test.filters.LargeTest;
@@ -39,6 +40,7 @@
import java.util.Arrays;
import java.util.List;
+@Presubmit
@LargeTest
public class ApplicationPackageManagerTest extends TestCase {
private static final String sInternalVolPath = "/data";
diff --git a/core/tests/coretests/src/android/content/ContentProviderTest.java b/core/tests/coretests/src/android/content/ContentProviderTest.java
index ceebc62..c9a6d22 100644
--- a/core/tests/coretests/src/android/content/ContentProviderTest.java
+++ b/core/tests/coretests/src/android/content/ContentProviderTest.java
@@ -24,6 +24,7 @@
import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
@@ -32,6 +33,7 @@
import org.junit.runner.RunWith;
import org.mockito.Answers;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class ContentProviderTest {
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 01e240a..7b70b41 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -35,6 +35,7 @@
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
import android.util.Size;
import androidx.test.InstrumentationRegistry;
@@ -45,6 +46,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class ContentResolverTest {
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index 3d7d807..e4a9ce5 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -34,6 +34,7 @@
import android.hardware.display.VirtualDisplay;
import android.media.ImageReader;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import android.view.Display;
import androidx.test.core.app.ApplicationProvider;
@@ -48,6 +49,7 @@
* Build/Install/Run:
* atest FrameworksCoreTests:ContextTest
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ContextTest {
diff --git a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
index 1bc46a7..68d4cd4 100644
--- a/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ManagedUserContentResolverTest.java
@@ -20,6 +20,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.annotations.Presubmit;
import androidx.test.filters.LargeTest;
@@ -36,6 +37,7 @@
* Run: adb shell am instrument -e class android.content.ManagedUserContentResolverTest -w \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
+@Presubmit
@LargeTest
public class ManagedUserContentResolverTest extends AbstractCrossUserContentResolverTest {
@Override
diff --git a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
index dbe0278..de4c572 100644
--- a/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/SecondaryUserContentResolverTest.java
@@ -18,6 +18,7 @@
import android.content.pm.UserInfo;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
import androidx.test.filters.LargeTest;
@@ -34,6 +35,7 @@
* Run: adb shell am instrument -e class android.content.SecondaryUserContentResolverTest -w \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
*/
+@Presubmit
@LargeTest
public class SecondaryUserContentResolverTest extends AbstractCrossUserContentResolverTest {
@Override
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
index 7ccbb01..e6660f3 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -170,7 +170,7 @@
when(mFile.getUsableSpace()).thenReturn(10000L);
when(mFile.getTotalSpace()).thenReturn(100000L);
long result = mSm.getStorageCacheBytes(mFile, 0);
- assertThat(result).isEqualTo(4666L);
+ assertThat(result).isEqualTo(4667L);
}
/**
diff --git a/core/tests/coretests/src/android/view/MotionEventTest.java b/core/tests/coretests/src/android/view/MotionEventTest.java
index c4c983d..78a8f7b 100644
--- a/core/tests/coretests/src/android/view/MotionEventTest.java
+++ b/core/tests/coretests/src/android/view/MotionEventTest.java
@@ -16,7 +16,6 @@
package android.view;
-import static android.view.InputDevice.SOURCE_CLASS_POINTER;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.TOOL_TYPE_FINGER;
@@ -215,27 +214,4 @@
rotInvalid.transform(mat);
assertEquals(-1, rotInvalid.getSurfaceRotation());
}
-
- @Test
- public void testUsesPointerSourceByDefault() {
- final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
- ACTION_DOWN, 0 /* x */, 0 /* y */, 0 /* metaState */);
- assertTrue(event.isFromSource(SOURCE_CLASS_POINTER));
- }
-
- @Test
- public void testLocationOffsetOnlyAppliedToNonPointerSources() {
- final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
- ACTION_DOWN, 10 /* x */, 20 /* y */, 0 /* metaState */);
- event.offsetLocation(40, 50);
-
- // The offset should be applied since a pointer source is used by default.
- assertEquals(50, (int) event.getX());
- assertEquals(70, (int) event.getY());
-
- // The offset should not be applied if the source is changed to a non-pointer source.
- event.setSource(InputDevice.SOURCE_JOYSTICK);
- assertEquals(10, (int) event.getX());
- assertEquals(20, (int) event.getY());
- }
}
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index 9696fdf..4f95cb8 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -28,7 +28,7 @@
import static androidx.test.espresso.matcher.ViewMatchers.withTagValue;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
-import static com.android.internal.widget.FloatingToolbarPopup.MenuItemRepr;
+import static com.android.internal.widget.floatingtoolbar.LocalFloatingToolbarPopup.MenuItemRepr;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
@@ -42,7 +42,7 @@
import androidx.test.espresso.ViewAction;
import androidx.test.espresso.ViewInteraction;
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
index aea453e..caec365 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
@@ -24,6 +24,7 @@
import android.os.FileUtils;
import android.os.SystemProperties;
+import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -46,6 +47,7 @@
import java.io.InputStream;
import java.util.ArrayList;
+@Presubmit
@RunWith(AndroidJUnit4.class)
public class OverlayConfigTest {
private static final String TEST_APK_PACKAGE_NAME =
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index c1a45c4..388cf6e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -22,6 +22,8 @@
import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -36,6 +38,7 @@
import android.app.ActivityManager;
import android.os.BatteryStats;
+import android.os.WakeLockStats;
import android.util.SparseArray;
import android.view.Display;
@@ -50,6 +53,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@LargeTest
@RunWith(AndroidJUnit4.class)
@SuppressWarnings("GuardedBy")
@@ -507,4 +512,51 @@
final BatteryStatsImpl.Uid u = mBatteryStatsImpl.getUidStatsLocked(parentUid);
u.addIsolatedUid(childUid);
}
+
+ @Test
+ public void testGetWakeLockStats() {
+ mBatteryStatsImpl.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+
+ // First wakelock, acquired once, not currently held
+ mMockClock.realtime = 1000;
+ mBatteryStatsImpl.noteStartWakeLocked(10100, 100, null, "wakeLock1", null,
+ BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+ mMockClock.realtime = 3000;
+ mBatteryStatsImpl.noteStopWakeLocked(10100, 100, null, "wakeLock1", null,
+ BatteryStats.WAKE_TYPE_PARTIAL);
+
+ // Second wakelock, acquired twice, still held
+ mMockClock.realtime = 4000;
+ mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
+ BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+ mMockClock.realtime = 5000;
+ mBatteryStatsImpl.noteStopWakeLocked(10200, 101, null, "wakeLock2", null,
+ BatteryStats.WAKE_TYPE_PARTIAL);
+
+ mMockClock.realtime = 6000;
+ mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
+ BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+ mMockClock.realtime = 9000;
+
+ List<WakeLockStats.WakeLock> wakeLockStats =
+ mBatteryStatsImpl.getWakeLockStats().getWakeLocks();
+ assertThat(wakeLockStats).hasSize(2);
+
+ WakeLockStats.WakeLock wakeLock1 = wakeLockStats.stream()
+ .filter(wl -> wl.uid == 10100 && wl.name.equals("wakeLock1")).findFirst().get();
+
+ assertThat(wakeLock1.timesAcquired).isEqualTo(1);
+ assertThat(wakeLock1.timeHeldMs).isEqualTo(0); // Not currently held
+ assertThat(wakeLock1.totalTimeHeldMs).isEqualTo(2000); // 3000-1000
+
+ WakeLockStats.WakeLock wakeLock2 = wakeLockStats.stream()
+ .filter(wl -> wl.uid == 10200 && wl.name.equals("wakeLock2")).findFirst().get();
+
+ assertThat(wakeLock2.timesAcquired).isEqualTo(2);
+ assertThat(wakeLock2.timeHeldMs).isEqualTo(3000); // 9000-6000
+ assertThat(wakeLock2.totalTimeHeldMs).isEqualTo(4000); // (5000-4000) + (9000-6000)
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 9575b0a..e616172 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -584,9 +584,11 @@
setCurrentValue(bounds);
if (inScaleTransition() || sourceHintRect == null) {
if (isOutPipDirection) {
- getSurfaceTransactionHelper().scale(tx, leash, end, bounds);
+ getSurfaceTransactionHelper().crop(tx, leash, end)
+ .scale(tx, leash, end, bounds);
} else {
- getSurfaceTransactionHelper().scale(tx, leash, base, bounds, angle)
+ getSurfaceTransactionHelper().crop(tx, leash, base)
+ .scale(tx, leash, base, bounds, angle)
.round(tx, leash, base, bounds);
}
} else {
@@ -622,13 +624,13 @@
if (rotationDelta == ROTATION_90) {
degree = 90 * (1 - fraction);
x = fraction * (end.left - start.left)
- + start.left + start.right * (1 - fraction);
+ + start.left + start.width() * (1 - fraction);
y = fraction * (end.top - start.top) + start.top;
} else {
degree = -90 * (1 - fraction);
x = fraction * (end.left - start.left) + start.left;
y = fraction * (end.top - start.top)
- + start.top + start.bottom * (1 - fraction);
+ + start.top + start.height() * (1 - fraction);
}
} else {
if (rotationDelta == ROTATION_90) {
@@ -646,8 +648,10 @@
getSurfaceTransactionHelper()
.rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds,
insets, degree, x, y, isOutPipDirection,
- rotationDelta == ROTATION_270 /* clockwise */)
- .round(tx, leash, sourceBounds, bounds);
+ rotationDelta == ROTATION_270 /* clockwise */);
+ if (shouldApplyCornerRadius()) {
+ getSurfaceTransactionHelper().round(tx, leash, sourceBounds, bounds);
+ }
tx.apply();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index ae7b82f..4c09a4e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -416,17 +416,32 @@
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
- final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
- mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds, mPipBoundsState.getBounds());
- tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
- // We set to fullscreen here for now, but later it will be set to UNDEFINED for
- // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
- wct.setActivityWindowingMode(mToken,
- direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN && !requestEnterSplit
- ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- : WINDOWING_MODE_FULLSCREEN);
- wct.setBounds(mToken, destinationBounds);
- wct.setBoundsChangeTransaction(mToken, tx);
+
+ if (Transitions.ENABLE_SHELL_TRANSITIONS && direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+ // When exit to fullscreen with Shell transition enabled, we update the Task windowing
+ // mode directly so that it can also trigger display rotation and visibility update in
+ // the same transition if there will be any.
+ wct.setWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
+ // We can inherit the parent bounds as it is going to be fullscreen. The
+ // destinationBounds calculated above will be incorrect if this is with rotation.
+ wct.setBounds(mToken, null);
+ } else {
+ final SurfaceControl.Transaction tx =
+ mSurfaceControlTransactionFactory.getTransaction();
+ mSurfaceTransactionHelper.scale(tx, mLeash, destinationBounds,
+ mPipBoundsState.getBounds());
+ tx.setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
+ // We set to fullscreen here for now, but later it will be set to UNDEFINED for
+ // the proper windowing mode to take place. See #applyWindowingModeChangeOnExit.
+ wct.setActivityWindowingMode(mToken,
+ direction == TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
+ && !requestEnterSplit
+ ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ : WINDOWING_MODE_FULLSCREEN);
+ wct.setBounds(mToken, destinationBounds);
+ wct.setBoundsChangeTransaction(mToken, tx);
+ }
+
// Set the exiting state first so if there is fixed rotation later, the running animation
// won't be interrupted by alpha animation for existing PiP.
mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
@@ -729,24 +744,18 @@
if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
return;
}
+ if (Transitions.ENABLE_SHELL_TRANSITIONS
+ && mPipTransitionState.getTransitionState() == PipTransitionState.EXITING_PIP) {
+ // With Shell transition, we do the cleanup in PipTransition after exiting PIP.
+ return;
+ }
final WindowContainerToken token = info.token;
Objects.requireNonNull(token, "Requires valid WindowContainerToken");
if (token.asBinder() != mToken.asBinder()) {
Log.wtf(TAG, "Unrecognized token: " + token);
return;
}
- clearWaitForFixedRotation();
- mPipTransitionState.setInSwipePipToHomeTransition(false);
- mPictureInPictureParams = null;
- mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
- // Re-set the PIP bounds to none.
- mPipBoundsState.setBounds(new Rect());
- mPipUiEventLoggerLogger.setTaskInfo(null);
- mPipMenuController.detach();
-
- if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
- mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
- }
+ onExitPipFinished(info);
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
mPipTransitionController.forceFinishTransition();
@@ -843,6 +852,22 @@
clearWaitForFixedRotation();
}
+ /** Called when exiting PIP tranisiton is finished to do the state cleanup. */
+ void onExitPipFinished(TaskInfo info) {
+ clearWaitForFixedRotation();
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
+ mPictureInPictureParams = null;
+ mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
+ // Re-set the PIP bounds to none.
+ mPipBoundsState.setBounds(new Rect());
+ mPipUiEventLoggerLogger.setTaskInfo(null);
+ mPipMenuController.detach();
+
+ if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
+ mOnDisplayIdChangeCallback.accept(Display.DEFAULT_DISPLAY);
+ }
+ }
+
private void fadeExistingPip(boolean show) {
final float alphaStart = show ? 0 : 1;
final float alphaEnd = show ? 1 : 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 2749bc8..c6794b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -19,10 +19,16 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.util.RotationUtils.deltaRotation;
+import static android.util.RotationUtils.rotateBounds;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
+import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
+import static android.window.TransitionInfo.isIndependent;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
@@ -30,6 +36,7 @@
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection;
import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
+import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
import static com.android.wm.shell.transition.Transitions.TRANSIT_REMOVE_PIP;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
@@ -38,13 +45,15 @@
import android.app.TaskInfo;
import android.content.Context;
import android.graphics.Matrix;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
-import android.util.Log;
+import android.util.ArrayMap;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -54,6 +63,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.util.CounterRotator;
import java.util.Optional;
@@ -72,8 +82,12 @@
private final Optional<SplitScreenController> mSplitScreenOptional;
private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
private Transitions.TransitionFinishCallback mFinishCallback;
- private Rect mExitDestinationBounds = new Rect();
- private IBinder mExitTransition = null;
+ private final Rect mExitDestinationBounds = new Rect();
+ @Nullable
+ private IBinder mExitTransition;
+ /** The Task window that is currently in PIP windowing mode. */
+ @Nullable
+ private WindowContainerToken mCurrentPipTaskToken;
public PipTransition(Context context,
PipBoundsState pipBoundsState,
@@ -119,112 +133,57 @@
}
@Override
- public boolean startAnimation(@android.annotation.NonNull IBinder transition,
- @android.annotation.NonNull TransitionInfo info,
- @android.annotation.NonNull SurfaceControl.Transaction startTransaction,
- @android.annotation.NonNull SurfaceControl.Transaction finishTransaction,
- @android.annotation.NonNull Transitions.TransitionFinishCallback finishCallback) {
+ public boolean startAnimation(@NonNull IBinder transition,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ // Exiting PIP.
final int type = info.getType();
- if (mExitTransition == transition) {
+ if (transition.equals(mExitTransition)) {
+ mExitDestinationBounds.setEmpty();
mExitTransition = null;
- if (type == TRANSIT_EXIT_PIP_TO_SPLIT) {
- return startExitToSplitAnimation(
- info, startTransaction, finishTransaction, finishCallback);
- }
-
- if (info.getChanges().size() == 1) {
- if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null, null);
- mFinishCallback = null;
- throw new RuntimeException("Previous callback not called, aborting exit PIP.");
- }
-
- final TransitionInfo.Change change = info.getChanges().get(0);
- mFinishCallback = finishCallback;
- startTransaction.apply();
- boolean success = startExpandAnimation(change.getTaskInfo(), change.getLeash(),
- new Rect(mExitDestinationBounds));
- mExitDestinationBounds.setEmpty();
- return success;
- } else {
- Log.e(TAG, "Got an exit-pip transition with unexpected change-list");
- }
- }
-
- if (type == TRANSIT_REMOVE_PIP) {
if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+ mFinishCallback.onTransitionFinished(null, null);
mFinishCallback = null;
- throw new RuntimeException("Previous callback not called, aborting remove PIP.");
+ throw new RuntimeException("Previous callback not called, aborting exit PIP.");
}
- startTransaction.apply();
- finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
- mPipBoundsState.getDisplayBounds());
- finishCallback.onTransitionFinished(null, null);
+ final TransitionInfo.Change exitPipChange = findCurrentPipChange(info);
+ if (exitPipChange == null) {
+ throw new RuntimeException("Cannot find the pip window for exit-pip transition.");
+ }
+
+ switch (type) {
+ case TRANSIT_EXIT_PIP:
+ startExitAnimation(info, startTransaction, finishCallback, exitPipChange);
+ break;
+ case TRANSIT_EXIT_PIP_TO_SPLIT:
+ startExitToSplitAnimation(info, startTransaction, finishTransaction,
+ finishCallback, exitPipChange);
+ break;
+ case TRANSIT_REMOVE_PIP:
+ removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
+ exitPipChange);
+ break;
+ default:
+ throw new IllegalStateException("mExitTransition with unexpected transit type="
+ + transitTypeToString(type));
+ }
+ mCurrentPipTaskToken = null;
return true;
}
- // We only support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
- // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
- if (type != TRANSIT_PIP && type != TRANSIT_OPEN) {
- // In case the PIP window is part of rotation transition, reset the bounds and rounded
- // corner.
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getMode() == TRANSIT_CHANGE && change.getTaskInfo() != null
- && change.getTaskInfo().configuration.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_PINNED) {
- final SurfaceControl leash = change.getLeash();
- final Rect destBounds = mPipBoundsState.getBounds();
- final boolean isInPip = mPipTransitionState.isInPip();
- mSurfaceTransactionHelper
- .crop(startTransaction, leash, destBounds)
- .round(startTransaction, leash, isInPip);
- mSurfaceTransactionHelper
- .crop(finishTransaction, leash, destBounds)
- .round(finishTransaction, leash, isInPip);
- break;
- }
- }
- return false;
+ // Entering PIP.
+ if (isEnteringPip(info, mCurrentPipTaskToken)) {
+ return startEnterAnimation(info, startTransaction, finishTransaction, finishCallback);
}
- // Search for an Enter PiP transition (along with a show wallpaper one)
- TransitionInfo.Change enterPip = null;
- TransitionInfo.Change wallpaper = null;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getTaskInfo() != null
- && change.getTaskInfo().configuration.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_PINNED) {
- enterPip = change;
- } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
- wallpaper = change;
- }
- }
- if (enterPip == null) {
- return false;
- }
-
- if (mFinishCallback != null) {
- mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
- mFinishCallback = null;
- throw new RuntimeException("Previous callback not called, aborting entering PIP.");
- }
-
- // Show the wallpaper if there is a wallpaper change.
- if (wallpaper != null) {
- startTransaction.show(wallpaper.getLeash());
- startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
- }
-
- mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
- mFinishCallback = finishCallback;
- return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
- startTransaction, finishTransaction, enterPip.getStartRotation(),
- enterPip.getEndRotation());
+ // For transition that we don't animate, we may need to update the PIP surface, otherwise it
+ // will be reset after the transition.
+ updatePipForUnhandledTransition(info, startTransaction, finishTransaction);
+ return false;
}
@Nullable
@@ -266,6 +225,7 @@
new Rect(mExitDestinationBounds));
}
mExitDestinationBounds.setEmpty();
+ mCurrentPipTaskToken = null;
}
@Override
@@ -298,7 +258,142 @@
mFinishCallback = null;
}
- private boolean startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
+ @Nullable
+ private TransitionInfo.Change findCurrentPipChange(@NonNull TransitionInfo info) {
+ if (mCurrentPipTaskToken == null) {
+ return null;
+ }
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (mCurrentPipTaskToken.equals(change.getContainer())) {
+ return change;
+ }
+ }
+ return null;
+ }
+
+ private void startExitAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull TransitionInfo.Change pipChange) {
+ TransitionInfo.Change displayRotationChange = null;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getMode() == TRANSIT_CHANGE
+ && (change.getFlags() & FLAG_IS_DISPLAY) != 0
+ && change.getStartRotation() != change.getEndRotation()) {
+ displayRotationChange = change;
+ break;
+ }
+ }
+
+ if (displayRotationChange != null) {
+ // Exiting PIP to fullscreen with orientation change.
+ startExpandAndRotationAnimation(info, startTransaction, finishCallback,
+ displayRotationChange, pipChange);
+ return;
+ }
+
+ // When there is no rotation, we can simply expand the PIP window.
+ mFinishCallback = (wct, wctCB) -> {
+ mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+ finishCallback.onTransitionFinished(wct, wctCB);
+ };
+
+ // Set the initial frame as scaling the end to the start.
+ final Rect destinationBounds = new Rect(pipChange.getEndAbsBounds());
+ final Point offset = pipChange.getEndRelOffset();
+ destinationBounds.offset(-offset.x, -offset.y);
+ startTransaction.setWindowCrop(pipChange.getLeash(), destinationBounds);
+ mSurfaceTransactionHelper.scale(startTransaction, pipChange.getLeash(),
+ destinationBounds, mPipBoundsState.getBounds());
+ startTransaction.apply();
+ startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds);
+ }
+
+ private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull TransitionInfo.Change displayRotationChange,
+ @NonNull TransitionInfo.Change pipChange) {
+ final int rotateDelta = deltaRotation(displayRotationChange.getStartRotation(),
+ displayRotationChange.getEndRotation());
+ final int displayW = displayRotationChange.getEndAbsBounds().width();
+ final int displayH = displayRotationChange.getEndAbsBounds().height();
+
+ // Counter-rotate all "going-away" things since they are still in the old orientation.
+ final ArrayMap<WindowContainerToken, CounterRotator> counterRotators = new ArrayMap<>();
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (!Transitions.isClosingType(change.getMode())
+ || !isIndependent(change, info)
+ || change.getParent() == null) {
+ continue;
+ }
+ CounterRotator crot = counterRotators.get(change.getParent());
+ if (crot == null) {
+ crot = new CounterRotator();
+ crot.setup(startTransaction,
+ info.getChange(change.getParent()).getLeash(),
+ rotateDelta, displayW, displayH);
+ if (crot.getSurface() != null) {
+ // Wallpaper should be placed at the bottom.
+ final int layer = (change.getFlags() & FLAG_IS_WALLPAPER) == 0
+ ? info.getChanges().size() - i
+ : -1;
+ startTransaction.setLayer(crot.getSurface(), layer);
+ }
+ counterRotators.put(change.getParent(), crot);
+ }
+ crot.addChild(startTransaction, change.getLeash());
+ }
+ mFinishCallback = (wct, wctCB) -> {
+ for (int i = 0; i < counterRotators.size(); ++i) {
+ counterRotators.valueAt(i).cleanUp(info.getRootLeash());
+ }
+ mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+ finishCallback.onTransitionFinished(wct, wctCB);
+ };
+
+ // Get the start bounds in new orientation.
+ final Rect startBounds = new Rect(pipChange.getStartAbsBounds());
+ rotateBounds(startBounds, displayRotationChange.getStartAbsBounds(), rotateDelta);
+ final Rect endBounds = new Rect(pipChange.getEndAbsBounds());
+ final Point offset = pipChange.getEndRelOffset();
+ startBounds.offset(-offset.x, -offset.y);
+ endBounds.offset(-offset.x, -offset.y);
+
+ // Reverse the rotation direction for expansion.
+ final int pipRotateDelta = deltaRotation(rotateDelta, 0);
+
+ // Set the start frame.
+ final int degree, x, y;
+ if (pipRotateDelta == ROTATION_90) {
+ degree = 90;
+ x = startBounds.right;
+ y = startBounds.top;
+ } else {
+ degree = -90;
+ x = startBounds.left;
+ y = startBounds.bottom;
+ }
+ mSurfaceTransactionHelper.rotateAndScaleWithCrop(startTransaction, pipChange.getLeash(),
+ endBounds, startBounds, new Rect(), degree, x, y, true /* isExpanding */,
+ pipRotateDelta == ROTATION_270 /* clockwise */);
+ startTransaction.apply();
+
+ // Expand and rotate the pip window to fullscreen.
+ final PipAnimationController.PipTransitionAnimator animator =
+ mPipAnimationController.getAnimator(pipChange.getTaskInfo(), pipChange.getLeash(),
+ startBounds, startBounds, endBounds, null, TRANSITION_DIRECTION_LEAVE_PIP,
+ 0 /* startingAngle */, pipRotateDelta);
+ animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
+ .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(mEnterExitAnimationDuration)
+ .start();
+ }
+
+ private void startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
final Rect destinationBounds) {
PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(),
@@ -309,8 +404,87 @@
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
.start();
+ }
- return true;
+ /** For {@link Transitions#TRANSIT_REMOVE_PIP}, we just immediately remove the PIP Task. */
+ private void removePipImmediately(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull TransitionInfo.Change pipChange) {
+ startTransaction.apply();
+ finishTransaction.setWindowCrop(info.getChanges().get(0).getLeash(),
+ mPipBoundsState.getDisplayBounds());
+ mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
+ finishCallback.onTransitionFinished(null, null);
+ }
+
+ /** Whether we should handle the given {@link TransitionInfo} animation as entering PIP. */
+ private static boolean isEnteringPip(@NonNull TransitionInfo info,
+ @Nullable WindowContainerToken currentPipTaskToken) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getTaskInfo() != null
+ && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED
+ && !change.getContainer().equals(currentPipTaskToken)) {
+ // We support TRANSIT_PIP type (from RootWindowContainer) or TRANSIT_OPEN (from apps
+ // that enter PiP instantly on opening, mostly from CTS/Flicker tests)
+ if (info.getType() == TRANSIT_PIP || info.getType() == TRANSIT_OPEN) {
+ return true;
+ }
+ // This can happen if the request to enter PIP happens when we are collecting for
+ // another transition, such as TRANSIT_CHANGE (display rotation).
+ if (info.getType() == TRANSIT_CHANGE) {
+ return true;
+ }
+
+ // Please file a bug to handle the unexpected transition type.
+ throw new IllegalStateException("Entering PIP with unexpected transition type="
+ + transitTypeToString(info.getType()));
+ }
+ }
+ return false;
+ }
+
+ private boolean startEnterAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ // Search for an Enter PiP transition (along with a show wallpaper one)
+ TransitionInfo.Change enterPip = null;
+ TransitionInfo.Change wallpaper = null;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getTaskInfo() != null
+ && change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_PINNED) {
+ enterPip = change;
+ } else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+ wallpaper = change;
+ }
+ }
+ if (enterPip == null) {
+ return false;
+ }
+ // Keep track of the PIP task.
+ mCurrentPipTaskToken = enterPip.getContainer();
+
+ if (mFinishCallback != null) {
+ mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
+ mFinishCallback = null;
+ throw new RuntimeException("Previous callback not called, aborting entering PIP.");
+ }
+
+ // Show the wallpaper if there is a wallpaper change.
+ if (wallpaper != null) {
+ startTransaction.show(wallpaper.getLeash());
+ startTransaction.setAlpha(wallpaper.getLeash(), 1.f);
+ }
+
+ mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
+ mFinishCallback = finishCallback;
+ return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
+ startTransaction, finishTransaction, enterPip.getStartRotation(),
+ enterPip.getEndRotation());
}
private boolean startEnterAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
@@ -387,10 +561,11 @@
return true;
}
- private boolean startExitToSplitAnimation(TransitionInfo info,
+ private void startExitToSplitAnimation(TransitionInfo info,
SurfaceControl.Transaction startTransaction,
SurfaceControl.Transaction finishTransaction,
- Transitions.TransitionFinishCallback finishCallback) {
+ Transitions.TransitionFinishCallback finishCallback,
+ TransitionInfo.Change pipChange) {
final int changeSize = info.getChanges().size();
if (changeSize < 4) {
throw new RuntimeException(
@@ -417,8 +592,35 @@
}
mSplitScreenOptional.get().finishEnterSplitScreen(startTransaction);
startTransaction.apply();
+
+ mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
finishCallback.onTransitionFinished(null, null);
- return true;
+ }
+
+ private void updatePipForUnhandledTransition(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction) {
+ if (mCurrentPipTaskToken == null) {
+ return;
+ }
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (!mCurrentPipTaskToken.equals(change.getContainer())) {
+ continue;
+ }
+ // When the PIP window is visible and being a part of the transition, such as display
+ // rotation, we need to update its bounds and rounded corner.
+ final SurfaceControl leash = change.getLeash();
+ final Rect destBounds = mPipBoundsState.getBounds();
+ final boolean isInPip = mPipTransitionState.isInPip();
+ mSurfaceTransactionHelper
+ .crop(startTransaction, leash, destBounds)
+ .round(startTransaction, leash, isInPip);
+ mSurfaceTransactionHelper
+ .crop(finishTransaction, leash, destBounds)
+ .round(finishTransaction, leash, isInPip);
+ break;
+ }
}
private void finishResizeForMenu(Rect destinationBounds) {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 300aa15..4128abf 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -1294,7 +1294,7 @@
* @throws IllegalStateException if there is no active frontend currently.
*/
@Nullable
- public String getCurrentFrontendHardwardInfo() {
+ public String getCurrentFrontendHardwareInfo() {
mFrontendLock.lock();
try {
if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
@@ -1434,7 +1434,7 @@
}
}
- private void onUnLocked() {
+ private void onUnlocked() {
Log.d(TAG, "Wrote Stats Log for unlocked event from scanning.");
FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
@@ -1444,7 +1444,7 @@
mScanCallbackExecutor.execute(() -> {
synchronized (mScanCallbackLock) {
if (mScanCallback != null) {
- mScanCallback.onUnLocked();
+ mScanCallback.onUnlocked();
}
}
});
diff --git a/media/java/android/media/tv/tuner/frontend/ScanCallback.java b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
index 6bbc13fe..68f3c1b 100644
--- a/media/java/android/media/tv/tuner/frontend/ScanCallback.java
+++ b/media/java/android/media/tv/tuner/frontend/ScanCallback.java
@@ -37,7 +37,7 @@
void onLocked();
/** Scan unlocked the signal. */
- default void onUnLocked() {}
+ default void onUnlocked() {}
/** Scan stopped. */
void onScanStopped();
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 8ccc4fb..c601649 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1044,7 +1044,7 @@
} else {
env->CallVoidMethod(
frontend,
- env->GetMethodID(clazz, "onUnLocked", "()V"));
+ env->GetMethodID(clazz, "onUnlocked", "()V"));
}
break;
}
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index 03606ba..9039011 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -20,7 +20,7 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.bluetoothmidiservice"
>
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
<uses-feature android:name="android.hardware.bluetooth_le"
android:required="true"/>
diff --git a/media/packages/BluetoothMidiService/AndroidManifestBase.xml b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
index bfb0546..5a900c7 100644
--- a/media/packages/BluetoothMidiService/AndroidManifestBase.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
@@ -19,7 +19,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.bluetoothmidiservice"
>
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
<application
android:label="BluetoothMidi"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index 181a594..b00fea4 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -83,10 +83,7 @@
*/
// TODO: Rename TAG_ALL to TAG_ANY.
public static final int TAG_ALL = -1;
- /**
- * {@link #set} value for all sets combined, not including debug sets.
- * @hide
- */
+ /** {@link #set} value for all sets combined, not including debug sets. */
public static final int SET_ALL = -1;
/** {@link #set} value where background data is accounted. */
public static final int SET_DEFAULT = 0;
@@ -114,9 +111,6 @@
SET_ALL,
SET_DEFAULT,
SET_FOREGROUND,
- SET_DEBUG_START,
- SET_DBG_VPN_IN,
- SET_DBG_VPN_OUT
})
public @interface State {
}
@@ -131,10 +125,7 @@
// TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
- /**
- * {@link #metered} value to account for all metered states.
- * @hide
- */
+ /** {@link #metered} value to account for all metered states. */
public static final int METERED_ALL = -1;
/** {@link #metered} value where native, unmetered data is accounted. */
public static final int METERED_NO = 0;
@@ -152,10 +143,7 @@
}
- /**
- * {@link #roaming} value to account for all roaming states.
- * @hide
- */
+ /** {@link #roaming} value to account for all roaming states. */
public static final int ROAMING_ALL = -1;
/** {@link #roaming} value where native, non-roaming data is accounted. */
public static final int ROAMING_NO = 0;
@@ -172,10 +160,7 @@
public @interface Roaming {
}
- /**
- * {@link #onDefaultNetwork} value to account for all default network states.
- * @hide
- */
+ /** {@link #onDefaultNetwork} value to account for all default network states. */
public static final int DEFAULT_NETWORK_ALL = -1;
/** {@link #onDefaultNetwork} value to account for usage while not the default network. */
public static final int DEFAULT_NETWORK_NO = 0;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
index 659ad06..e9084b0 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkTemplate.java
@@ -16,6 +16,7 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
@@ -39,7 +40,9 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.wifi.WifiInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -70,7 +73,7 @@
*
* @hide
*/
-// @SystemApi(client = MODULE_LIBRARIES)
+@SystemApi(client = MODULE_LIBRARIES)
public final class NetworkTemplate implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -572,6 +575,7 @@
/**
* Get subscriber Id of the template.
+ * @hide
*/
@Nullable
@UnsupportedAppUsage
@@ -588,26 +592,19 @@
}
/**
- * Get Wifi Network Key of the template. See {@link WifiInfo#getCurrentNetworkKey()}.
+ * Get the set of Wifi Network Keys of the template.
+ * See {@link WifiInfo#getCurrentNetworkKey()}.
*/
- @Nullable
- public String getWifiNetworkKey() {
- return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) ? null : mMatchWifiNetworkKeys[0];
- }
-
- /**
- * Get set of Wifi Network Keys of the template.
- */
- @Nullable
+ @NonNull
public Set<String> getWifiNetworkKeys() {
return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys));
}
/** @hide */
- // TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}.
+ // TODO: Remove this and replace all callers with {@link #getWifiNetworkKeys()}.
@Nullable
public String getNetworkId() {
- return getWifiNetworkKey();
+ return getWifiNetworkKeys().isEmpty() ? null : getWifiNetworkKeys().iterator().next();
}
/**
diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
index d1e432e..179d945 100644
--- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
@@ -1236,37 +1236,53 @@
int callingUid = Binder.getCallingUid();
UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
final int resourceId = mNextResourceId++;
- FileDescriptor sockFd = null;
+
+ ParcelFileDescriptor pFd = null;
try {
if (!userRecord.mSocketQuotaTracker.isAvailable()) {
return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
}
- sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- mUidFdTagger.tag(sockFd, callingUid);
+ FileDescriptor sockFd = null;
+ try {
+ sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ pFd = ParcelFileDescriptor.dup(sockFd);
+ } finally {
+ IoUtils.closeQuietly(sockFd);
+ }
+ mUidFdTagger.tag(pFd.getFileDescriptor(), callingUid);
// This code is common to both the unspecified and specified port cases
Os.setsockoptInt(
- sockFd,
+ pFd.getFileDescriptor(),
OsConstants.IPPROTO_UDP,
OsConstants.UDP_ENCAP,
OsConstants.UDP_ENCAP_ESPINUDP);
- mNetd.ipSecSetEncapSocketOwner(new ParcelFileDescriptor(sockFd), callingUid);
+ mNetd.ipSecSetEncapSocketOwner(pFd, callingUid);
if (port != 0) {
Log.v(TAG, "Binding to port " + port);
- Os.bind(sockFd, INADDR_ANY, port);
+ Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port);
} else {
- port = bindToRandomPort(sockFd);
+ port = bindToRandomPort(pFd.getFileDescriptor());
}
userRecord.mEncapSocketRecords.put(
resourceId,
new RefcountedResource<EncapSocketRecord>(
- new EncapSocketRecord(resourceId, sockFd, port), binder));
- return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd);
+ new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port),
+ binder));
+ return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port,
+ pFd.getFileDescriptor());
} catch (IOException | ErrnoException e) {
- IoUtils.closeQuietly(sockFd);
+ try {
+ if (pFd != null) {
+ pFd.close();
+ }
+ } catch (IOException ex) {
+ // Nothing can be done at this point
+ Log.e(TAG, "Failed to close pFd.");
+ }
}
// If we make it to here, then something has gone wrong and we couldn't open a socket.
// The only reasonable condition that would cause that is resource unavailable.
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index ef84ce0..ced2e22 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -42,7 +42,6 @@
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
-import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UNSUPPORTED;
@@ -107,13 +106,13 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
+import android.net.TetheringManager;
import android.net.TrafficStats;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.netstats.provider.INetworkStatsProvider;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.net.netstats.provider.NetworkStatsProvider;
-import android.os.BestClock;
import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
@@ -149,6 +148,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FileRotator;
+import com.android.net.module.util.BestClock;
import com.android.net.module.util.BinderUtils;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkStatsUtils;
@@ -531,8 +531,9 @@
}
// watch for tethering changes
- final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED);
- mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler);
+ final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
+ tetheringManager.registerTetheringEventCallback(
+ new HandlerExecutor(mHandler), mTetherListener);
// listen for periodic polling events
final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL);
@@ -588,7 +589,8 @@
@GuardedBy("mStatsLock")
private void shutdownLocked() {
- mContext.unregisterReceiver(mTetherReceiver);
+ final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
+ tetheringManager.unregisterTetheringEventCallback(mTetherListener);
mContext.unregisterReceiver(mPollReceiver);
mContext.unregisterReceiver(mRemovedReceiver);
mContext.unregisterReceiver(mUserReceiver);
@@ -1152,14 +1154,15 @@
}
/**
- * Receiver that watches for {@link Tethering} to claim interface pairs.
+ * Listener that watches for {@link TetheringManager} to claim interface pairs.
*/
- private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- performPoll(FLAG_PERSIST_NETWORK);
- }
- };
+ private final TetheringManager.TetheringEventCallback mTetherListener =
+ new TetheringManager.TetheringEventCallback() {
+ @Override
+ public void onUpstreamChanged(@Nullable Network network) {
+ performPoll(FLAG_PERSIST_NETWORK);
+ }
+ };
private BroadcastReceiver mPollReceiver = new BroadcastReceiver() {
@Override
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 93d0ae7..9bb7bb8 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -101,7 +101,8 @@
// with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration.
final List<Pair<Integer, String>> filteredNewSubs = new ArrayList<>();
for (final int subId : newSubs) {
- final String subscriberId = mTeleManager.getSubscriberId(subId);
+ final String subscriberId =
+ mTeleManager.createForSubscriptionId(subId).getSubscriberId();
if (!TextUtils.isEmpty(subscriberId)) {
filteredNewSubs.add(new Pair(subId, subscriberId));
}
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
index e586dbb..b127630 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
@@ -24,7 +24,6 @@
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical"
- android:importantForAccessibility = "no"
android:clipToPadding="false">
<LinearLayout
diff --git a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
index 990860a..23192b6 100644
--- a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
@@ -23,7 +23,6 @@
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/selectableItemBackground"
- android:importantForAccessibility = "no"
android:clipToPadding="false">
<LinearLayout
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index fe7988f..e51bb45 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -61,6 +61,7 @@
title.setMovementMethod(new LinkMovementMethod());
title.setClickable(false);
title.setLongClickable(false);
+ title.setFocusable(false);
if (!TextUtils.isEmpty(mContentDescription)) {
title.setContentDescription(mContentDescription);
}
@@ -79,6 +80,7 @@
if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
learnMore.setContentDescription(mLearnMoreContentDescription);
}
+ learnMore.setFocusable(false);
} else {
learnMore.setVisibility(View.GONE);
}
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index c439cf0..9bccc3f 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -22,7 +22,7 @@
<!-- The translation for disappearing security views after having solved them. -->
<dimen name="disappear_y_translation">-32dp</dimen>
- <dimen name="circle_avatar_size">40dp</dimen>
+ <dimen name="circle_avatar_size">190dp</dimen>
<!-- Height of a user icon view -->
<dimen name="user_icon_view_height">24dp</dimen>
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 688c48d..13c1e51 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -229,6 +229,7 @@
VALIDATORS.put(Secure.SKIP_DIRECTION, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SILENCE_GESTURE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, JSON_OBJECT_VALIDATOR);
+ VALIDATORS.put(Secure.NAV_BAR_KIDS_MODE, BOOLEAN_VALIDATOR);
VALIDATORS.put(
Secure.NAVIGATION_MODE, new DiscreteValueValidator(new String[] {"0", "1", "2"}));
VALIDATORS.put(Secure.BACK_GESTURE_INSET_SCALE_LEFT,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 103e141..cd6447f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -244,9 +244,6 @@
final long autofillToken = p.start(GlobalSettingsProto.AUTOFILL);
dumpSetting(s, p,
- Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
- GlobalSettingsProto.Autofill.COMPAT_MODE_ALLOWED_PACKAGES);
- dumpSetting(s, p,
Settings.Global.AUTOFILL_LOGGING_LEVEL,
GlobalSettingsProto.Autofill.LOGGING_LEVEL);
dumpSetting(s, p,
@@ -2247,6 +2244,10 @@
SecureSettingsProto.MULTI_PRESS_TIMEOUT);
dumpSetting(s, p,
+ Settings.Secure.NAV_BAR_KIDS_MODE,
+ SecureSettingsProto.NAV_BAR_KIDS_MODE);
+
+ dumpSetting(s, p,
Settings.Secure.NAVIGATION_MODE,
SecureSettingsProto.NAVIGATION_MODE);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 368dda1..a3f3995 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -134,7 +134,6 @@
Settings.Global.ART_VERIFIER_VERIFY_DEBUGGABLE,
Settings.Global.ASSISTED_GPS_ENABLED,
Settings.Global.AUDIO_SAFE_VOLUME_STATE,
- Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_correction.xml b/packages/SystemUI/res/drawable/ic_qs_color_correction.xml
new file mode 100644
index 0000000..f83cabd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_color_correction.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M3,21v-4.75l8.95,-8.95 -1.45,-1.4 1.45,-1.4 1.9,1.9 3.1,-3.1q0.275,-0.275 0.7,-0.275 0.425,0 0.7,0.275l2.35,2.35q0.275,0.275 0.275,0.7 0,0.425 -0.275,0.7l-3.075,3.075 1.9,1.95L18.1,13.5l-1.4,-1.45L7.75,21zM5,19h1.95l8.3,-8.35 -1.9,-1.9L5,17.05z"/>
+</vector>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 9f017b2..7b8f349 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -82,7 +82,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,fgsmanager
+ internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,qr_code_scanner,onehanded,fgsmanager,color_correction
</string>
<!-- The tiles to display in QuickSettings -->
@@ -97,6 +97,7 @@
The syntax is setting-name:spec. If the tile is a TileService, the spec should be specified
as custom(package/class). Relative class name is supported. -->
<string-array name="config_quickSettingsAutoAdd" translatable="false">
+ <item>accessibility_display_daltonizer_enabled:color_correction</item>
<item>accessibility_display_inversion_enabled:inversion</item>
<item>one_handed_mode_enabled:onehanded</item>
</string-array>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 95d140f..2bf121d2e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -596,6 +596,7 @@
<!-- QuickSettings: Label for the toggle that controls whether display inversion is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_inversion_label">Color inversion</string>
<!-- QuickSettings: Label for the toggle that controls whether display color correction is enabled. [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_color_correction_label">Color correction</string>
<!-- QuickSettings: Control panel: Label for button that navigates to settings. [CHAR LIMIT=NONE] -->
<string name="quick_settings_more_settings">More settings</string>
<!-- QuickSettings: Control panel: Label for button that navigates to user settings. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/tiles_states_strings.xml b/packages/SystemUI/res/values/tiles_states_strings.xml
index 5fdb497..a610caa 100644
--- a/packages/SystemUI/res/values/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values/tiles_states_strings.xml
@@ -142,6 +142,16 @@
<item>On</item>
</string-array>
+ <!-- State names for color correction tile: unavailable, off, on.
+ This subtitle is shown when the tile is in that particular state but does not set its own
+ subtitle, so some of these may never appear on screen. They should still be translated as
+ if they could appear. [CHAR LIMIT=32] -->
+ <string-array name="tile_states_color_correction">
+ <item>Unavailable</item>
+ <item>Off</item>
+ <item>On</item>
+ </string-array>
+
<!-- State names for (color) inversion tile: unavailable, off, on.
This subtitle is shown when the tile is in that particular state but does not set its own
subtitle, so some of these may never appear on screen. They should still be translated as
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index c1d9d0d..4ec65d8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -282,7 +282,9 @@
* @see SurfaceControl#release()
*/
public void release() {
- leash.mSurfaceControl.release();
+ if (leash.mSurfaceControl != null) {
+ leash.mSurfaceControl.release();
+ }
if (mStartLeash != null) {
mStartLeash.release();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index dc64f14..a701b44 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -23,7 +23,7 @@
import androidx.dynamicanimation.animation.SpringForce
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
-import com.android.systemui.unfold.updates.FOLD_UPDATE_ABORTED
+import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
@@ -84,7 +84,7 @@
cancelTransition(endValue = 1f, animate = true)
}
}
- FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_ABORTED -> {
+ FOLD_UPDATE_FINISH_FULL_OPEN, FOLD_UPDATE_FINISH_HALF_OPEN -> {
// Do not cancel if we haven't started the transition yet.
// This could happen when we fully unfolded the device before the screen
// became available. In this case we start and immediately cancel the animation
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 6d9631c..cd1ea21 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -138,7 +138,7 @@
if (isTransitionInProgess) {
cancelTimeout()
}
- handler.postDelayed(timeoutRunnable, ABORT_CLOSING_MILLIS)
+ handler.postDelayed(timeoutRunnable, HALF_OPENED_TIMEOUT_MILLIS)
}
private fun cancelTimeout() {
@@ -163,16 +163,14 @@
}
private inner class HingeAngleListener : Consumer<Float> {
-
override fun accept(angle: Float) {
onHingeAngle(angle)
}
}
private inner class TimeoutRunnable : Runnable {
-
override fun run() {
- notifyFoldUpdate(FOLD_UPDATE_ABORTED)
+ notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN)
}
}
}
@@ -180,9 +178,7 @@
private fun stateToString(@FoldUpdate update: Int): String {
return when (update) {
FOLD_UPDATE_START_OPENING -> "START_OPENING"
- FOLD_UPDATE_HALF_OPEN -> "HALF_OPEN"
FOLD_UPDATE_START_CLOSING -> "START_CLOSING"
- FOLD_UPDATE_ABORTED -> "ABORTED"
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> "UNFOLDED_SCREEN_AVAILABLE"
FOLD_UPDATE_FINISH_HALF_OPEN -> "FINISH_HALF_OPEN"
FOLD_UPDATE_FINISH_FULL_OPEN -> "FINISH_FULL_OPEN"
@@ -195,11 +191,11 @@
private const val DEBUG = false
/**
- * Time after which [FOLD_UPDATE_ABORTED] is emitted following a [FOLD_UPDATE_START_CLOSING] or
- * [FOLD_UPDATE_START_OPENING] event, if an end state is not reached.
+ * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a
+ * [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not reached.
*/
@VisibleForTesting
-const val ABORT_CLOSING_MILLIS = 1000L
+const val HALF_OPENED_TIMEOUT_MILLIS = 1000L
/** Threshold after which we consider the device fully unfolded. */
@VisibleForTesting
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index bffebcd..df3563d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -37,9 +37,7 @@
@IntDef(prefix = ["FOLD_UPDATE_"], value = [
FOLD_UPDATE_START_OPENING,
- FOLD_UPDATE_HALF_OPEN,
FOLD_UPDATE_START_CLOSING,
- FOLD_UPDATE_ABORTED,
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
FOLD_UPDATE_FINISH_HALF_OPEN,
FOLD_UPDATE_FINISH_FULL_OPEN,
@@ -50,10 +48,8 @@
}
const val FOLD_UPDATE_START_OPENING = 0
-const val FOLD_UPDATE_HALF_OPEN = 1
-const val FOLD_UPDATE_START_CLOSING = 2
-const val FOLD_UPDATE_ABORTED = 3
-const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 4
-const val FOLD_UPDATE_FINISH_HALF_OPEN = 5
-const val FOLD_UPDATE_FINISH_FULL_OPEN = 6
-const val FOLD_UPDATE_FINISH_CLOSED = 7
+const val FOLD_UPDATE_START_CLOSING = 1
+const val FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE = 2
+const val FOLD_UPDATE_FINISH_HALF_OPEN = 3
+const val FOLD_UPDATE_FINISH_FULL_OPEN = 4
+const val FOLD_UPDATE_FINISH_CLOSED = 5
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
index 492fdc6..b15807c 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
@@ -66,11 +66,12 @@
* @param poolSize The maximum amount that the size of the buffer is allowed to flex in response to
* sequential calls to [document] that aren't immediately followed by a matching call to [push].
*/
-class LogBuffer(
+class LogBuffer @JvmOverloads constructor(
private val name: String,
private val maxLogs: Int,
private val poolSize: Int,
- private val logcatEchoTracker: LogcatEchoTracker
+ private val logcatEchoTracker: LogcatEchoTracker,
+ private val systrace: Boolean = true
) {
init {
if (maxLogs < poolSize) {
@@ -175,6 +176,10 @@
buffer.removeFirst()
}
buffer.add(message as LogMessageImpl)
+ if (systrace) {
+ val messageStr = message.printer(message)
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", "$name - $messageStr")
+ }
if (logcatEchoTracker.isBufferLoggable(name, message.level) ||
logcatEchoTracker.isTagLoggable(message.tag, message.level)) {
echo(message)
@@ -237,7 +242,6 @@
LogLevel.ERROR -> Log.e(message.tag, strMessage)
LogLevel.WTF -> Log.wtf(message.tag, strMessage)
}
- Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", strMessage)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index 5296ee6..cbfca25 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -36,8 +36,13 @@
}
@JvmOverloads
- fun create(name: String, maxPoolSize: Int, flexSize: Int = 10): LogBuffer {
- val buffer = LogBuffer(name, poolLimit(maxPoolSize), flexSize, logcatEchoTracker)
+ fun create(
+ name: String,
+ maxPoolSize: Int,
+ flexSize: Int = 10,
+ systrace: Boolean = true
+ ): LogBuffer {
+ val buffer = LogBuffer(name, poolLimit(maxPoolSize), flexSize, logcatEchoTracker, systrace)
dumpManager.registerBuffer(name, buffer)
return buffer
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index d3bd0a5..1f953d7 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -49,7 +49,8 @@
@SysUISingleton
@NotificationLog
public static LogBuffer provideNotificationsLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifLog", 1000);
+ return factory.create("NotifLog", 1000 /* maxPoolSize */,
+ 10 /* flexSize */, false /* systrace */);
}
/** Provides a logging buffer for all logs related to the data layer of notifications. */
@@ -65,7 +66,8 @@
@SysUISingleton
@NotificationSectionLog
public static LogBuffer provideNotificationSectionLogBuffer(LogBufferFactory factory) {
- return factory.create("NotifSectionLog", 1000);
+ return factory.create("NotifSectionLog", 1000 /* maxPoolSize */,
+ 10 /* flexSize */, false /* systrace */);
}
/** Provides a logging buffer for all logs related to the data layer of notifications. */
@@ -81,7 +83,8 @@
@SysUISingleton
@QSLog
public static LogBuffer provideQuickSettingsLogBuffer(LogBufferFactory factory) {
- return factory.create("QSLog", 500);
+ return factory.create("QSLog", 500 /* maxPoolSize */,
+ 10 /* flexSize */, false /* systrace */);
}
/** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
@@ -89,7 +92,8 @@
@SysUISingleton
@BroadcastDispatcherLog
public static LogBuffer provideBroadcastDispatcherLogBuffer(LogBufferFactory factory) {
- return factory.create("BroadcastDispatcherLog", 500);
+ return factory.create("BroadcastDispatcherLog", 500 /* maxPoolSize */,
+ 10 /* flexSize */, false /* systrace */);
}
/** Provides a logging buffer for all logs related to Toasts shown by SystemUI. */
@@ -127,7 +131,8 @@
@SysUISingleton
@QSFragmentDisableLog
public static LogBuffer provideQSFragmentDisableLogBuffer(LogBufferFactory factory) {
- return factory.create("QSFragmentDisableFlagsLog", 10);
+ return factory.create("QSFragmentDisableFlagsLog", 10 /* maxPoolSize */,
+ 10 /* flexSize */, false /* systrace */);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index c2a9e3a..76950d1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -32,6 +32,7 @@
import com.android.systemui.qs.tiles.CameraToggleTile;
import com.android.systemui.qs.tiles.CastTile;
import com.android.systemui.qs.tiles.CellularTile;
+import com.android.systemui.qs.tiles.ColorCorrectionTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
import com.android.systemui.qs.tiles.DataSaverTile;
import com.android.systemui.qs.tiles.DeviceControlsTile;
@@ -71,6 +72,7 @@
private final Provider<BluetoothTile> mBluetoothTileProvider;
private final Provider<CellularTile> mCellularTileProvider;
private final Provider<DndTile> mDndTileProvider;
+ private final Provider<ColorCorrectionTile> mColorCorrectionTileProvider;
private final Provider<ColorInversionTile> mColorInversionTileProvider;
private final Provider<AirplaneModeTile> mAirplaneModeTileProvider;
private final Provider<WorkModeTile> mWorkModeTileProvider;
@@ -133,7 +135,8 @@
Provider<QuickAccessWalletTile> quickAccessWalletTileProvider,
Provider<QRCodeScannerTile> qrCodeScannerTileProvider,
Provider<OneHandedModeTile> oneHandedModeTileProvider,
- Provider<FgsManagerTile> fgsManagerTileProvider) {
+ Provider<FgsManagerTile> fgsManagerTileProvider,
+ Provider<ColorCorrectionTile> colorCorrectionTileProvider) {
mQsHostLazy = qsHostLazy;
mCustomTileBuilderProvider = customTileBuilderProvider;
@@ -167,6 +170,7 @@
mQRCodeScannerTileProvider = qrCodeScannerTileProvider;
mOneHandedModeTileProvider = oneHandedModeTileProvider;
mFgsManagerTileProvider = fgsManagerTileProvider;
+ mColorCorrectionTileProvider = colorCorrectionTileProvider;
}
public final QSTile createTile(String tileSpec) {
@@ -239,6 +243,8 @@
return mOneHandedModeTileProvider.get();
case "fgsmanager":
return mFgsManagerTileProvider.get();
+ case "color_correction":
+ return mColorCorrectionTileProvider.get();
}
// Custom tiles
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 6bb79867..7efb983 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -653,7 +653,8 @@
"qr_code_scanner" to R.array.tile_states_qr_code_scanner,
"alarm" to R.array.tile_states_alarm,
"onehanded" to R.array.tile_states_onehanded,
- "fgsmanager" to R.array.tile_states_fgsmanager
+ "fgsmanager" to R.array.tile_states_fgsmanager,
+ "color_correction" to R.array.tile_states_color_correction
)
fun getSubtitleId(spec: String?): Int {
@@ -665,4 +666,4 @@
return PropertyValuesHolder.ofInt(name, *values).apply {
setEvaluator(ArgbEvaluator.getInstance())
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
new file mode 100644
index 0000000..6dfcf5c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.service.quicksettings.Tile;
+import android.view.View;
+import android.widget.Switch;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.R.drawable;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.SecureSettings;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: Color correction **/
+public class ColorCorrectionTile extends QSTileImpl<BooleanState> {
+
+ private final Icon mIcon = ResourceIcon.get(drawable.ic_qs_color_correction);
+ private final SettingObserver mSetting;
+
+ @Inject
+ public ColorCorrectionTile(
+ QSHost host,
+ @Background Looper backgroundLooper,
+ @Main Handler mainHandler,
+ FalsingManager falsingManager,
+ MetricsLogger metricsLogger,
+ StatusBarStateController statusBarStateController,
+ ActivityStarter activityStarter,
+ QSLogger qsLogger,
+ UserTracker userTracker,
+ SecureSettings secureSettings
+ ) {
+ super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+ statusBarStateController, activityStarter, qsLogger);
+
+ mSetting = new SettingObserver(secureSettings, mHandler,
+ Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, userTracker.getUserId()) {
+ @Override
+ protected void handleValueChanged(int value, boolean observedChange) {
+ // mHandler is the background handler so calling this is OK
+ handleRefreshState(value);
+ }
+ };
+ }
+
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ mSetting.setListening(false);
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void handleSetListening(boolean listening) {
+ super.handleSetListening(listening);
+ mSetting.setListening(listening);
+ }
+
+ @Override
+ protected void handleUserSwitch(int newUserId) {
+ mSetting.setUserId(newUserId);
+ handleRefreshState(mSetting.getValue());
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return new Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS);
+ }
+
+ @Override
+ protected void handleClick(@Nullable View view) {
+ mSetting.setValue(mState.value ? 0 : 1);
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_color_correction_label);
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
+ final boolean enabled = value != 0;
+ state.value = enabled;
+ state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.label = mContext.getString(R.string.quick_settings_color_correction_label);
+ state.icon = mIcon;
+ state.expandedAccessibilityClassName = Switch.class.getName();
+ state.contentDescription = state.label;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ // MetricsProto/MetricsEvent is deprecated, so just simply return 0 here.
+ return 0;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index c9c1a9b..a22fda7 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -93,6 +93,12 @@
}
@Override
+ protected void onPause() {
+ super.onPause();
+ overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
+ }
+
+ @Override
protected void onStop() {
super.onStop();
MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
index 43b3fb1..7cf0583 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlertingNotificationManager.java
@@ -257,6 +257,30 @@
return !canRemoveImmediately(entry.getKey());
}
+ /**
+ * @param key
+ * @return true if the entry is pinned
+ */
+ public boolean isSticky(String key) {
+ AlertEntry alerting = mAlertEntries.get(key);
+ if (alerting != null) {
+ return alerting.isSticky();
+ }
+ return false;
+ }
+
+ /**
+ * @param key
+ * @return When a HUN entry should be removed in milliseconds from now
+ */
+ public long getEarliestRemovalTime(String key) {
+ AlertEntry alerting = mAlertEntries.get(key);
+ if (alerting != null) {
+ return Math.max(0, alerting.mEarliestRemovaltime - mClock.currentTimeMillis());
+ }
+ return 0;
+ }
+
@Override
public void setShouldManageLifetime(NotificationEntry entry, boolean shouldExtend) {
if (shouldExtend) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 2dbe59e..bd948ece 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -28,6 +28,7 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.SystemProperties;
+import android.os.Trace;
import android.text.format.DateFormat;
import android.util.FloatProperty;
import android.util.Log;
@@ -193,6 +194,7 @@
mState = state;
mUpcomingState = state;
mUiEventLogger.log(StatusBarStateEvent.fromState(mState));
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events", "StatusBarState " + tag);
for (RankedListener rl : new ArrayList<>(mListeners)) {
rl.mListener.onStateChanged(mState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index f8b4274..ed9663e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -19,9 +19,12 @@
import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain;
+import android.util.ArraySet;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -38,8 +41,7 @@
import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
-
-import java.util.Objects;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import javax.inject.Inject;
@@ -66,12 +68,11 @@
private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final NotificationRemoteInputManager mRemoteInputManager;
private final NodeController mIncomingHeaderController;
-
- // tracks the current HeadUpNotification reported by HeadsUpManager
- private @Nullable NotificationEntry mCurrentHun;
+ private final DelayableExecutor mExecutor;
private NotifLifetimeExtender.OnEndLifetimeExtensionCallback mEndLifetimeExtension;
- private NotificationEntry mNotifExtendingLifetime; // notif we've extended the lifetime for
+ // notifs we've extended the lifetime for
+ private final ArraySet<NotificationEntry> mNotifsExtendingLifetime = new ArraySet<>();
@Inject
public HeadsUpCoordinator(
@@ -79,12 +80,14 @@
HeadsUpViewBinder headsUpViewBinder,
NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationRemoteInputManager remoteInputManager,
- @IncomingHeader NodeController incomingHeaderController) {
+ @IncomingHeader NodeController incomingHeaderController,
+ @Main DelayableExecutor executor) {
mHeadsUpManager = headsUpManager;
mHeadsUpViewBinder = headsUpViewBinder;
mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mRemoteInputManager = remoteInputManager;
mIncomingHeaderController = incomingHeaderController;
+ mExecutor = executor;
}
@Override
@@ -178,16 +181,26 @@
public boolean shouldExtendLifetime(@NonNull NotificationEntry entry, int reason) {
boolean isShowingHun = isCurrentlyShowingHun(entry);
if (isShowingHun) {
- mNotifExtendingLifetime = entry;
+ if (isSticky(entry)) {
+ long removeAfterMillis = mHeadsUpManager.getEarliestRemovalTime(entry.getKey());
+ if (removeAfterMillis <= 0) return false;
+ mExecutor.executeDelayed(() -> {
+ // make sure that the entry was not updated
+ long removeAfterMillis2 =
+ mHeadsUpManager.getEarliestRemovalTime(entry.getKey());
+ if (mNotifsExtendingLifetime.contains(entry) && removeAfterMillis2 <= 0) {
+ mHeadsUpManager.removeNotification(entry.getKey(), true);
+ }
+ }, removeAfterMillis);
+ }
+ mNotifsExtendingLifetime.add(entry);
}
return isShowingHun;
}
@Override
public void cancelLifetimeExtension(@NonNull NotificationEntry entry) {
- if (Objects.equals(mNotifExtendingLifetime, entry)) {
- mNotifExtendingLifetime = null;
- }
+ mNotifsExtendingLifetime.remove(entry);
}
};
@@ -220,27 +233,24 @@
new OnHeadsUpChangedListener() {
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- NotificationEntry newHUN = mHeadsUpManager.getTopEntry();
- if (!Objects.equals(mCurrentHun, newHUN)) {
- mCurrentHun = newHUN;
- endNotifLifetimeExtension();
- }
if (!isHeadsUp) {
mHeadsUpViewBinder.unbindHeadsUpView(entry);
+ endNotifLifetimeExtensionIfExtended(entry);
}
}
};
- private boolean isCurrentlyShowingHun(ListEntry entry) {
- return mCurrentHun == entry.getRepresentativeEntry();
+ private boolean isSticky(NotificationEntry entry) {
+ return mHeadsUpManager.isSticky(entry.getKey());
}
- private void endNotifLifetimeExtension() {
- if (mNotifExtendingLifetime != null) {
- mEndLifetimeExtension.onEndLifetimeExtension(
- mLifetimeExtender,
- mNotifExtendingLifetime);
- mNotifExtendingLifetime = null;
+ private boolean isCurrentlyShowingHun(ListEntry entry) {
+ return mHeadsUpManager.isAlerting(entry.getKey());
+ }
+
+ private void endNotifLifetimeExtensionIfExtended(NotificationEntry entry) {
+ if (mNotifsExtendingLifetime.remove(entry)) {
+ mEndLifetimeExtension.onEndLifetimeExtension(mLifetimeExtender, entry);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index ab36da5..6218c77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -520,26 +520,66 @@
}
/**
+ * Called when removing a view from its transient container, such as at the end of an animation.
+ * Generally, when operating on ExpandableView instances, this should be used rather than
+ * {@link ExpandableView#removeTransientView(View)} to ensure that the
+ * {@link #getTransientContainer() transient container} is correctly reset.
+ */
+ public void removeFromTransientContainer() {
+ final ViewGroup transientContainer = getTransientContainer();
+ if (transientContainer == null) {
+ return;
+ }
+ final ViewParent parent = getParent();
+ if (parent != transientContainer) {
+ Log.w(TAG, "Expandable view " + this
+ + " has transient container " + transientContainer
+ + " but different parent " + parent);
+ setTransientContainer(null);
+ return;
+ }
+ transientContainer.removeTransientView(this);
+ setTransientContainer(null);
+ }
+
+ /**
* Called before adding this view to a group, which would always throw an exception if this view
- * has a parent, so clean up the transient container and throw an exception if the parent isn't
- * a transient container. Provide as much detail in the event of a crash as possible.
+ * has a different parent, so clean up the transient container and throw an exception if the
+ * parent isn't a transient container. Provide as much detail as possible in the crash.
*/
public void removeFromTransientContainerForAdditionTo(ViewGroup newParent) {
final ViewParent parent = getParent();
+ final ViewGroup transientContainer = getTransientContainer();
if (parent == null) {
- // If this view has no parent, the add will succeed, so do nothing.
+ // If this view has no parent, the add will succeed, so just make sure the tracked
+ // transient container is in sync with the lack of a parent.
+ if (transientContainer != null) {
+ Log.w(TAG, "Expandable view " + this
+ + " has transient container " + transientContainer
+ + " but no parent");
+ setTransientContainer(null);
+ }
return;
}
- ViewGroup transientContainer = getTransientContainer();
if (transientContainer == null) {
throw new IllegalStateException(
"Can't add view " + this + " to container " + newParent + "; current parent "
+ parent + " is not a transient container");
}
if (transientContainer != parent) {
- throw new IllegalStateException(
- "Expandable view " + this + " has transient container " + transientContainer
- + " which is not the same as its parent " + parent);
+ String transientContainerOutOfSyncError = "Expandable view " + this
+ + " has transient container " + transientContainer
+ + " but different parent " + parent;
+ if (parent != newParent) {
+ // Crash with details before addView() crashes without any; the view is being added
+ // to a different parent, and the transient container isn't the parent, so we can't
+ // even (safely) clean that up.
+ throw new IllegalStateException(transientContainerOutOfSyncError);
+ } else {
+ Log.w(TAG, transientContainerOutOfSyncError);
+ setTransientContainer(null);
+ return;
+ }
}
if (parent != newParent) {
Log.w(TAG, "Moving view " + this + " from transient container "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 88198f3..1d90780 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -215,8 +215,7 @@
// TODO: We should really cancel the active animations here. This will
// happen automatically when the view's intro animation starts, but
// it's a fragile link.
- header.transientContainer?.removeTransientView(header)
- header.transientContainer = null
+ header.removeFromTransientContainer()
parent.addView(header, target)
} else {
parent.changeViewPosition(header, target)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 3e9ce25..943f05f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -3213,10 +3213,7 @@
// Clean up any potential transient views if the child has already been swiped
// out, as we won't be animating it further (due to its height already being
// clipped to 0.
- ViewGroup transientContainer = child.getTransientContainer();
- if (transientContainer != null) {
- transientContainer.removeTransientView(child);
- }
+ child.removeFromTransientContainer();
}
}
int animationType = childWasSwipedOut
@@ -3933,7 +3930,11 @@
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
- viewGroup.removeTransientView(viewGroup.getTransientView(0));
+ final View transientView = viewGroup.getTransientView(0);
+ viewGroup.removeTransientView(transientView);
+ if (transientView instanceof ExpandableView) {
+ ((ExpandableView) transientView).setTransientContainer(null);
+ }
}
}
@@ -4102,7 +4103,7 @@
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void clearTransient() {
for (ExpandableView view : mClearTransientViewsWhenFinished) {
- StackStateAnimator.removeTransientView(view);
+ view.removeFromTransientContainer();
}
mClearTransientViewsWhenFinished.clear();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 71dcc5d..fc612a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -455,10 +455,7 @@
if (!row.isDismissed()) {
handleChildViewDismissed(view);
}
- ViewGroup transientContainer = row.getTransientContainer();
- if (transientContainer != null) {
- transientContainer.removeTransientView(view);
- }
+ row.removeFromTransientContainer();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 2dc9276..1d0d374 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -322,9 +322,8 @@
private void onAnimationFinished() {
mHostLayout.onChildAnimationFinished();
- for (ExpandableView transientViewsToRemove : mTransientViewsToRemove) {
- transientViewsToRemove.getTransientContainer()
- .removeTransientView(transientViewsToRemove);
+ for (ExpandableView transientViewToRemove : mTransientViewsToRemove) {
+ transientViewToRemove.removeFromTransientContainer();
}
mTransientViewsToRemove.clear();
}
@@ -353,7 +352,7 @@
} else if (event.animationType ==
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) {
if (changingView.getVisibility() != View.VISIBLE) {
- removeTransientView(changingView);
+ changingView.removeFromTransientContainer();
continue;
}
@@ -390,12 +389,11 @@
}
changingView.performRemoveAnimation(ANIMATION_DURATION_APPEAR_DISAPPEAR,
0 /* delay */, translationDirection, false /* isHeadsUpAppear */,
- 0, () -> removeTransientView(changingView), null);
+ 0, changingView::removeFromTransientContainer, null);
} else if (event.animationType ==
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) {
- if (mHostLayout.isFullySwipedOut(changingView)
- && changingView.getTransientContainer() != null) {
- changingView.getTransientContainer().removeTransientView(changingView);
+ if (mHostLayout.isFullySwipedOut(changingView)) {
+ changingView.removeFromTransientContainer();
}
} else if (event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_GROUP_EXPANSION_CHANGED) {
@@ -425,7 +423,7 @@
mHostLayout.addTransientView(changingView, 0);
changingView.setTransientContainer(mHostLayout);
mTmpState.initFrom(changingView);
- endRunnable = () -> removeTransientView(changingView);
+ endRunnable = changingView::removeFromTransientContainer;
}
float targetLocation = 0;
boolean needsAnimation = true;
@@ -468,12 +466,6 @@
}
}
- public static void removeTransientView(ExpandableView viewToRemove) {
- if (viewToRemove.getTransientContainer() != null) {
- viewToRemove.getTransientContainer().removeTransientView(viewToRemove);
- }
- }
-
public void animateOverScrollToAmount(float targetAmount, final boolean onTop,
final boolean isRubberbanded) {
final float startOverScrollAmount = mHostLayout.getCurrentOverScrollAmount(onTop);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt
new file mode 100644
index 0000000..56b0d598
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FoldStateListener.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback
+import com.android.internal.R
+
+/**
+ * Listens for fold state changes and reports the new folded state together with other properties
+ * associated with that state.
+ */
+internal class FoldStateListener(
+ context: Context,
+ private val listener: OnFoldStateChangeListener
+) : DeviceStateCallback {
+
+ internal interface OnFoldStateChangeListener {
+ /**
+ * Reports that the device either became folded or unfolded.
+ *
+ * @param folded whether the device is folded.
+ * @param willGoToSleep whether the device will go to sleep and keep the screen off.
+ */
+ fun onFoldStateChanged(folded: Boolean, willGoToSleep: Boolean)
+ }
+
+ private val foldedDeviceStates: IntArray =
+ context.resources.getIntArray(R.array.config_foldedDeviceStates)
+ private val goToSleepDeviceStates: IntArray =
+ context.resources.getIntArray(R.array.config_deviceStatesOnWhichToSleep)
+
+ private var wasFolded: Boolean? = null
+
+ override fun onStateChanged(state: Int) {
+ val isFolded = foldedDeviceStates.contains(state)
+ if (wasFolded == isFolded) {
+ return
+ }
+ wasFolded = isFolded
+ val willGoToSleep = goToSleepDeviceStates.contains(state)
+ listener.onFoldStateChanged(isFolded, willGoToSleep)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
index 72f1695..fb0e306 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowView.java
@@ -50,7 +50,7 @@
import android.widget.FrameLayout;
import com.android.internal.view.FloatingActionMode;
-import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.floatingtoolbar.FloatingToolbar;
import com.android.systemui.R;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index 2d41e5e..24bb7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -55,6 +55,9 @@
*/
boolean closeShadeIfOpen();
+ /** Returns whether the shade is currently open or opening. */
+ boolean isShadeOpen();
+
/**
* Add a runnable for NotificationPanelView to post when the panel is expanded.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
index b4fed2b..f8b0535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java
@@ -148,6 +148,13 @@
}
@Override
+ public boolean isShadeOpen() {
+ NotificationPanelViewController controller =
+ getNotificationPanelViewController();
+ return controller.isExpanding() || controller.isFullyExpanded();
+ }
+
+ @Override
public void postOnShadeExpanded(Runnable executable) {
getNotificationPanelViewController().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 3671bb9..1cc5e12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -70,6 +70,7 @@
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.PointF;
+import android.hardware.devicestate.DeviceStateManager;
import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Bundle;
@@ -779,7 +780,8 @@
Optional<StartingSurface> startingSurfaceOptional,
ActivityLaunchAnimator activityLaunchAnimator,
NotifPipelineFlags notifPipelineFlags,
- InteractionJankMonitor jankMonitor) {
+ InteractionJankMonitor jankMonitor,
+ DeviceStateManager deviceStateManager) {
super(context);
mNotificationsController = notificationsController;
mFragmentService = fragmentService;
@@ -902,6 +904,9 @@
data -> mCommandQueueCallbacks.animateExpandSettingsPanel(data.mSubpanel));
mMessageRouter.subscribeTo(MSG_LAUNCH_TRANSITION_TIMEOUT,
id -> onLaunchTransitionTimeout());
+
+ deviceStateManager.registerCallback(mMainExecutor,
+ new FoldStateListener(mContext, this::onFoldedStateChanged));
}
@Override
@@ -1100,6 +1105,27 @@
requestTopUi, componentTag))));
}
+ private void onFoldedStateChanged(boolean isFolded, boolean willGoToSleep) {
+ // Folded state changes are followed by a screen off event.
+ // By default turning off the screen also closes the shade.
+ // We want to make sure that the shade status is kept after
+ // folding/unfolding.
+ boolean isShadeOpen = mShadeController.isShadeOpen();
+ boolean leaveOpen = isShadeOpen && !willGoToSleep;
+ if (DEBUG) {
+ Log.d(TAG, String.format(
+ "#onFoldedStateChanged(): "
+ + "isFolded=%s, "
+ + "willGoToSleep=%s, "
+ + "isShadeOpen=%s, "
+ + "leaveOpen=%s",
+ isFolded, willGoToSleep, isShadeOpen, leaveOpen));
+ }
+ if (leaveOpen) {
+ mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+ }
+ }
+
// ================================================================================
// Constructing the view
// ================================================================================
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 50176fe..977fe9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -20,6 +20,7 @@
import android.app.WallpaperManager;
import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
import android.os.Handler;
import android.os.PowerManager;
import android.util.DisplayMetrics;
@@ -231,7 +232,8 @@
Optional<StartingSurface> startingSurfaceOptional,
ActivityLaunchAnimator activityLaunchAnimator,
NotifPipelineFlags notifPipelineFlags,
- InteractionJankMonitor jankMonitor) {
+ InteractionJankMonitor jankMonitor,
+ DeviceStateManager deviceStateManager) {
return new StatusBar(
context,
notificationsController,
@@ -327,7 +329,8 @@
startingSurfaceOptional,
activityLaunchAnimator,
notifPipelineFlags,
- jankMonitor
+ jankMonitor,
+ deviceStateManager
);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 2dfcc98..c1f63b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -171,6 +171,8 @@
if (mShowing == showing && mOccluded == occluded) return;
mShowing = showing;
mOccluded = occluded;
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, "UI Events",
+ "Keyguard showing: " + showing + " occluded: " + occluded);
notifyKeyguardChanged();
// Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
index af33daf..968b12a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
@@ -29,6 +29,7 @@
import com.android.systemui.qs.tiles.CameraToggleTile
import com.android.systemui.qs.tiles.CastTile
import com.android.systemui.qs.tiles.CellularTile
+import com.android.systemui.qs.tiles.ColorCorrectionTile
import com.android.systemui.qs.tiles.ColorInversionTile
import com.android.systemui.qs.tiles.DataSaverTile
import com.android.systemui.qs.tiles.DeviceControlsTile
@@ -91,7 +92,8 @@
"wallet" to QuickAccessWalletTile::class.java,
"qr_code_scanner" to QRCodeScannerTile::class.java,
"onehanded" to OneHandedModeTile::class.java,
- "fgsmanager" to FgsManagerTile::class.java
+ "fgsmanager" to FgsManagerTile::class.java,
+ "color_correction" to ColorCorrectionTile::class.java
)
@RunWith(AndroidTestingRunner::class)
@@ -132,6 +134,7 @@
@Mock private lateinit var qrCodeScannerTile: QRCodeScannerTile
@Mock private lateinit var oneHandedModeTile: OneHandedModeTile
@Mock private lateinit var fgsManagerTile: FgsManagerTile
+ @Mock private lateinit var colorCorrectionTile: ColorCorrectionTile
private lateinit var factory: QSFactoryImpl
@@ -175,7 +178,8 @@
{ quickAccessWalletTile },
{ qrCodeScannerTile },
{ oneHandedModeTile },
- { fgsManagerTile }
+ { fgsManagerTile },
+ { colorCorrectionTile }
)
// When adding/removing tiles, fix also [specMap]
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
new file mode 100644
index 0000000..debe41c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.settings.FakeSettings;
+import com.android.systemui.util.settings.SecureSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class ColorCorrectionTileTest extends SysuiTestCase {
+
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ private MetricsLogger mMetricsLogger;
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private QSLogger mQSLogger;
+ @Mock
+ private UiEventLogger mUiEventLogger;
+ @Mock
+ private UserTracker mUserTracker;
+
+ private TestableLooper mTestableLooper;
+ private SecureSettings mSecureSettings;
+ private ColorCorrectionTile mTile;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mSecureSettings = new FakeSettings();
+ mTestableLooper = TestableLooper.get(this);
+
+ when(mHost.getContext()).thenReturn(mContext);
+ when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger);
+
+ mTile = new ColorCorrectionTile(
+ mHost,
+ mTestableLooper.getLooper(),
+ new Handler(mTestableLooper.getLooper()),
+ new FalsingManagerFake(),
+ mMetricsLogger,
+ mStatusBarStateController,
+ mActivityStarter,
+ mQSLogger,
+ mUserTracker,
+ mSecureSettings
+ );
+
+ mTile.initialize();
+ mTestableLooper.processAllMessages();
+ }
+
+ @Test
+ public void longClick_expectedAction() {
+ final ArgumentCaptor<Intent> IntentCaptor = ArgumentCaptor.forClass(Intent.class);
+
+ mTile.longClick(/* view= */ null);
+ mTestableLooper.processAllMessages();
+
+ verify(mActivityStarter).postStartActivityDismissingKeyguard(IntentCaptor.capture(),
+ anyInt(), any());
+ assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
+ Settings.ACTION_COLOR_CORRECTION_SETTINGS);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index a3569e4..a11b46d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -19,8 +19,11 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -44,6 +47,8 @@
import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +57,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -75,6 +82,9 @@
@Mock private NodeController mHeaderController;
private NotificationEntry mEntry;
+ private final FakeSystemClock mClock = new FakeSystemClock();
+ private final FakeExecutor mExecutor = new FakeExecutor(mClock);
+ private final ArrayList<NotificationEntry> mHuns = new ArrayList();
@Before
public void setUp() {
@@ -85,7 +95,8 @@
mHeadsUpViewBinder,
mNotificationInterruptStateProvider,
mRemoteInputManager,
- mHeaderController);
+ mHeaderController,
+ mExecutor);
mCoordinator.attach(mNotifPipeline);
@@ -105,6 +116,16 @@
notifLifetimeExtenderCaptor.capture());
verify(mHeadsUpManager).addListener(headsUpChangedListenerCaptor.capture());
+ given(mHeadsUpManager.getAllEntries()).willAnswer(i -> mHuns.stream());
+ given(mHeadsUpManager.isAlerting(anyString())).willAnswer(i -> {
+ String key = i.getArgument(0);
+ for (NotificationEntry entry : mHuns) {
+ if (entry.getKey().equals(key)) return true;
+ }
+ return false;
+ });
+ when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L);
+
mCollectionListener = notifCollectionCaptor.getValue();
mNotifPromoter = notifPromoterCaptor.getValue();
mNotifLifetimeExtender = notifLifetimeExtenderCaptor.getValue();
@@ -116,63 +137,64 @@
}
@Test
+ public void testCancelStickyNotification() {
+ when(mHeadsUpManager.isSticky(anyString())).thenReturn(true);
+ addHUN(mEntry);
+ when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 0L);
+ assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
+ mClock.advanceTime(1000L);
+ mExecutor.runAllReady();
+ verify(mHeadsUpManager, times(1))
+ .removeNotification(anyString(), eq(true));
+ }
+
+ @Test
+ public void testCancelUpdatedStickyNotification() {
+ when(mHeadsUpManager.isSticky(anyString())).thenReturn(true);
+ addHUN(mEntry);
+ when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L);
+ assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
+ mClock.advanceTime(1000L);
+ mExecutor.runAllReady();
+ verify(mHeadsUpManager, times(0))
+ .removeNotification(anyString(), eq(true));
+ }
+
+ @Test
public void testPromotesCurrentHUN() {
// GIVEN the current HUN is set to mEntry
- setCurrentHUN(mEntry);
+ addHUN(mEntry);
// THEN only promote the current HUN, mEntry
assertTrue(mNotifPromoter.shouldPromoteToTopLevel(mEntry));
- assertFalse(mNotifPromoter.shouldPromoteToTopLevel(new NotificationEntryBuilder().build()));
+ assertFalse(mNotifPromoter.shouldPromoteToTopLevel(new NotificationEntryBuilder()
+ .setPkg("test-package2")
+ .build()));
}
@Test
public void testIncludeInSectionCurrentHUN() {
// GIVEN the current HUN is set to mEntry
- setCurrentHUN(mEntry);
+ addHUN(mEntry);
// THEN only section the current HUN, mEntry
assertTrue(mNotifSectioner.isInSection(mEntry));
- assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder().build()));
+ assertFalse(mNotifSectioner.isInSection(new NotificationEntryBuilder()
+ .setPkg("test-package")
+ .build()));
}
@Test
public void testLifetimeExtendsCurrentHUN() {
// GIVEN there is a HUN, mEntry
- setCurrentHUN(mEntry);
+ addHUN(mEntry);
// THEN only the current HUN, mEntry, should be lifetimeExtended
assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, /* cancellationReason */ 0));
assertFalse(mNotifLifetimeExtender.shouldExtendLifetime(
- new NotificationEntryBuilder().build(), /* cancellationReason */ 0));
- }
-
- @Test
- public void testLifetimeExtensionEndsOnNewHUN() {
- // GIVEN there was a HUN that was lifetime extended
- setCurrentHUN(mEntry);
- assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(
- mEntry, /* cancellation reason */ 0));
-
- // WHEN there's a new HUN
- NotificationEntry newHUN = new NotificationEntryBuilder().build();
- setCurrentHUN(newHUN);
-
- // THEN the old entry's lifetime extension should be cancelled
- verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry);
- }
-
- @Test
- public void testLifetimeExtensionEndsOnNoHUNs() {
- // GIVEN there was a HUN that was lifetime extended
- setCurrentHUN(mEntry);
- assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(
- mEntry, /* cancellation reason */ 0));
-
- // WHEN there's no longer a HUN
- setCurrentHUN(null);
-
- // THEN the old entry's lifetime extension should be cancelled
- verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry);
+ new NotificationEntryBuilder()
+ .setPkg("test-package")
+ .build(), /* cancellationReason */ 0));
}
@Test
@@ -208,7 +230,7 @@
@Test
public void testOnEntryRemovedRemovesHeadsUpNotification() {
// GIVEN the current HUN is mEntry
- setCurrentHUN(mEntry);
+ addHUN(mEntry);
// WHEN mEntry is removed from the notification collection
mCollectionListener.onEntryRemoved(mEntry, /* cancellation reason */ 0);
@@ -218,12 +240,9 @@
verify(mHeadsUpManager).removeNotification(mEntry.getKey(), false);
}
- private void setCurrentHUN(NotificationEntry entry) {
+ private void addHUN(NotificationEntry entry) {
+ mHuns.add(entry);
when(mHeadsUpManager.getTopEntry()).thenReturn(entry);
- when(mHeadsUpManager.isAlerting(any())).thenReturn(false);
- if (entry != null) {
- when(mHeadsUpManager.isAlerting(entry.getKey())).thenReturn(true);
- }
mOnHeadsUpChangedListener.onHeadsUpStateChanged(entry, entry != null);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 276f246..4d2c0c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -46,9 +47,7 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.ActivityStarterDelegate;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
@@ -56,7 +55,6 @@
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
-import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
@@ -66,6 +64,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -266,8 +265,9 @@
// THEN the header is first removed from the transient parent before being added to the
// NSSL.
- verify(transientParent).removeTransientView(silentHeaderView);
- verify(mNssl).addView(silentHeaderView, 1);
+ final InOrder inOrder = inOrder(silentHeaderView, mNssl);
+ inOrder.verify(silentHeaderView).removeFromTransientContainer();
+ inOrder.verify(mNssl).addView(eq(silentHeaderView), eq(1));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
new file mode 100644
index 0000000..649dc23
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.phone.FoldStateListener.OnFoldStateChangeListener
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations.initMocks
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class FoldStateListenerTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var listener: OnFoldStateChangeListener
+ private lateinit var sut: FoldStateListener
+
+ @Before
+ fun setUp() {
+ initMocks(this)
+ setFoldedStates(DEVICE_STATE_FOLDED)
+ setGoToSleepStates(DEVICE_STATE_FOLDED)
+ sut = FoldStateListener(mContext, listener)
+ }
+
+ @Test
+ fun onStateChanged_stateFolded_notifiesWithFoldedAndGoingToSleep() {
+ sut.onStateChanged(DEVICE_STATE_FOLDED)
+
+ verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
+ }
+
+ @Test
+ fun onStateChanged_stateHalfFolded_notifiesWithNotFoldedAndNotGoingToSleep() {
+ sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+
+ verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+ }
+
+ @Test
+ fun onStateChanged_stateUnfolded_notifiesWithNotFoldedAndNotGoingToSleep() {
+ sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+
+ verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+ }
+
+ @Test
+ fun onStateChanged_stateUnfoldedThenHalfFolded_notifiesOnce() {
+ sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+ sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+
+ verify(listener, times(1)).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+ }
+
+ @Test
+ fun onStateChanged_stateHalfFoldedThenUnfolded_notifiesOnce() {
+ sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+ sut.onStateChanged(DEVICE_STATE_UNFOLDED)
+
+ verify(listener, times(1)).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+ }
+
+ @Test
+ fun onStateChanged_stateHalfFoldedThenFolded_notifiesTwice() {
+ sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+ sut.onStateChanged(DEVICE_STATE_FOLDED)
+
+ val inOrder = Mockito.inOrder(listener)
+ inOrder.verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+ inOrder.verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
+ }
+
+ @Test
+ fun onStateChanged_stateFoldedThenHalfFolded_notifiesTwice() {
+ sut.onStateChanged(DEVICE_STATE_FOLDED)
+ sut.onStateChanged(DEVICE_STATE_HALF_FOLDED)
+
+ val inOrder = Mockito.inOrder(listener)
+ inOrder.verify(listener).onFoldStateChanged(FOLDED, WILL_GO_TO_SLEEP)
+ inOrder.verify(listener).onFoldStateChanged(NOT_FOLDED, WILL_NOT_SLEEP)
+ }
+
+ private fun setGoToSleepStates(vararg states: Int) {
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_deviceStatesOnWhichToSleep,
+ states
+ )
+ }
+
+ private fun setFoldedStates(vararg states: Int) {
+ mContext.orCreateTestableResources.addOverride(
+ R.array.config_foldedDeviceStates,
+ states
+ )
+ }
+
+ companion object {
+ private const val DEVICE_STATE_FOLDED = 123
+ private const val DEVICE_STATE_HALF_FOLDED = 456
+ private const val DEVICE_STATE_UNFOLDED = 789
+
+ private const val FOLDED = true
+ private const val NOT_FOLDED = false
+
+ private const val WILL_GO_TO_SLEEP = true
+ private const val WILL_NOT_SLEEP = false
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 69f2bd7..bb8bad3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -44,6 +44,7 @@
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.IntentFilter;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
import android.metrics.LogMaker;
@@ -162,6 +163,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -176,6 +178,9 @@
@RunWithLooper(setAsMainLooper = true)
public class StatusBarTest extends SysuiTestCase {
+ private static final int FOLD_STATE_FOLDED = 0;
+ private static final int FOLD_STATE_UNFOLDED = 1;
+
private StatusBar mStatusBar;
private FakeMetricsLogger mMetricsLogger;
private PowerManager mPowerManager;
@@ -281,6 +286,7 @@
@Mock private NotifPipelineFlags mNotifPipelineFlags;
@Mock private NotifLiveDataStore mNotifLiveDataStore;
@Mock private InteractionJankMonitor mJankMonitor;
+ @Mock private DeviceStateManager mDeviceStateManager;
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -466,7 +472,8 @@
Optional.of(mStartingSurface),
mActivityLaunchAnimator,
mNotifPipelineFlags,
- mJankMonitor);
+ mJankMonitor,
+ mDeviceStateManager);
when(mKeyguardViewMediator.registerStatusBar(
any(StatusBar.class),
any(NotificationPanelViewController.class),
@@ -949,6 +956,47 @@
verify(mStatusBarKeyguardViewManager).updateResources();
}
+ @Test
+ public void deviceStateChange_unfolded_shadeOpen_setsLeaveOpenOnKeyguardHide() {
+ setFoldedStates(FOLD_STATE_FOLDED);
+ setGoToSleepStates(FOLD_STATE_FOLDED);
+ when(mNotificationPanelViewController.isFullyExpanded()).thenReturn(true);
+
+ setDeviceState(FOLD_STATE_UNFOLDED);
+
+ verify(mStatusBarStateController).setLeaveOpenOnKeyguardHide(true);
+ }
+
+ @Test
+ public void deviceStateChange_unfolded_shadeClose_doesNotSetLeaveOpenOnKeyguardHide() {
+ setFoldedStates(FOLD_STATE_FOLDED);
+ setGoToSleepStates(FOLD_STATE_FOLDED);
+ when(mNotificationPanelViewController.isFullyExpanded()).thenReturn(false);
+
+ setDeviceState(FOLD_STATE_UNFOLDED);
+
+ verify(mStatusBarStateController, never()).setLeaveOpenOnKeyguardHide(true);
+ }
+
+ private void setDeviceState(int state) {
+ ArgumentCaptor<DeviceStateManager.DeviceStateCallback> callbackCaptor =
+ ArgumentCaptor.forClass(DeviceStateManager.DeviceStateCallback.class);
+ verify(mDeviceStateManager).registerCallback(any(), callbackCaptor.capture());
+ callbackCaptor.getValue().onStateChanged(state);
+ }
+
+ private void setGoToSleepStates(int... states) {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_deviceStatesOnWhichToSleep,
+ states);
+ }
+
+ private void setFoldedStates(int... states) {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_foldedDeviceStates,
+ states);
+ }
+
public static class TestableNotificationInterruptStateProviderImpl extends
NotificationInterruptStateProviderImpl {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 46e0b12..f43dc6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -30,6 +30,7 @@
import com.android.systemui.unfold.util.FoldableTestUtils
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
+import java.lang.Exception
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -39,32 +40,24 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
-import java.lang.Exception
@RunWith(AndroidTestingRunner::class)
@SmallTest
class DeviceFoldStateProviderTest : SysuiTestCase() {
- @Mock
- private lateinit var hingeAngleProvider: HingeAngleProvider
+ @Mock private lateinit var hingeAngleProvider: HingeAngleProvider
- @Mock
- private lateinit var screenStatusProvider: ScreenStatusProvider
+ @Mock private lateinit var screenStatusProvider: ScreenStatusProvider
- @Mock
- private lateinit var deviceStateManager: DeviceStateManager
+ @Mock private lateinit var deviceStateManager: DeviceStateManager
- @Mock
- private lateinit var handler: Handler
+ @Mock private lateinit var handler: Handler
- @Captor
- private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
+ @Captor private lateinit var foldStateListenerCaptor: ArgumentCaptor<FoldStateListener>
- @Captor
- private lateinit var screenOnListenerCaptor: ArgumentCaptor<ScreenListener>
+ @Captor private lateinit var screenOnListenerCaptor: ArgumentCaptor<ScreenListener>
- @Captor
- private lateinit var hingeAngleCaptor: ArgumentCaptor<Consumer<Float>>
+ @Captor private lateinit var hingeAngleCaptor: ArgumentCaptor<Consumer<Float>>
private lateinit var foldStateProvider: DeviceFoldStateProvider
@@ -81,24 +74,25 @@
MockitoAnnotations.initMocks(this)
deviceStates = FoldableTestUtils.findDeviceStates(context)
- foldStateProvider = DeviceFoldStateProvider(
- context,
- hingeAngleProvider,
- screenStatusProvider,
- deviceStateManager,
- context.mainExecutor,
- handler
- )
+ foldStateProvider =
+ DeviceFoldStateProvider(
+ context,
+ hingeAngleProvider,
+ screenStatusProvider,
+ deviceStateManager,
+ context.mainExecutor,
+ handler)
- foldStateProvider.addCallback(object : FoldStateProvider.FoldUpdatesListener {
- override fun onHingeAngleUpdate(angle: Float) {
- hingeAngleUpdates.add(angle)
- }
+ foldStateProvider.addCallback(
+ object : FoldStateProvider.FoldUpdatesListener {
+ override fun onHingeAngleUpdate(angle: Float) {
+ hingeAngleUpdates.add(angle)
+ }
- override fun onFoldUpdate(update: Int) {
- foldUpdates.add(update)
- }
- })
+ override fun onFoldUpdate(update: Int) {
+ foldUpdates.add(update)
+ }
+ })
foldStateProvider.start()
verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
@@ -200,9 +194,10 @@
sendHingeAngleEvent(90)
sendHingeAngleEvent(80)
- simulateTimeout(ABORT_CLOSING_MILLIS)
+ simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS)
- assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_ABORTED)
+ assertThat(foldUpdates)
+ .containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_FINISH_HALF_OPEN)
}
@Test
@@ -210,7 +205,7 @@
sendHingeAngleEvent(90)
sendHingeAngleEvent(80)
- simulateTimeout(ABORT_CLOSING_MILLIS - 1)
+ simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
}
@@ -220,7 +215,7 @@
sendHingeAngleEvent(180)
sendHingeAngleEvent(90)
- simulateTimeout(ABORT_CLOSING_MILLIS - 1)
+ simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
sendHingeAngleEvent(80)
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
@@ -231,11 +226,13 @@
sendHingeAngleEvent(180)
sendHingeAngleEvent(90)
- simulateTimeout(ABORT_CLOSING_MILLIS - 1) // The timeout should not trigger here.
+ // The timeout should not trigger here.
+ simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS - 1)
sendHingeAngleEvent(80)
- simulateTimeout(ABORT_CLOSING_MILLIS) // The timeout should trigger here.
+ simulateTimeout(HALF_OPENED_TIMEOUT_MILLIS) // The timeout should trigger here.
- assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_ABORTED)
+ assertThat(foldUpdates)
+ .containsExactly(FOLD_UPDATE_START_CLOSING, FOLD_UPDATE_FINISH_HALF_OPEN)
}
@Test
@@ -261,7 +258,7 @@
}
}
- private fun simulateTimeout(waitTime: Long = ABORT_CLOSING_MILLIS) {
+ private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) {
val runnableDelay = scheduledRunnableDelay ?: throw Exception("No runnable scheduled.")
if (waitTime >= runnableDelay) {
scheduledRunnable?.run()
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 422749e..051281c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -241,9 +241,6 @@
protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver,
@NonNull ContentObserver observer) {
resolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.AUTOFILL_LOGGING_LEVEL), false, observer,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
@@ -274,8 +271,6 @@
break;
default:
Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
- // fall through
- case Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
synchronized (mLock) {
updateCachedServiceLocked(userId);
}
@@ -307,6 +302,9 @@
case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_REQUEST_TIMEOUT:
setDeviceConfigProperties();
break;
+ case AutofillManager.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES:
+ updateCachedServices();
+ break;
default:
Slog.i(mTag, "Ignoring change on " + key);
}
@@ -588,6 +586,15 @@
}
}
+ private void updateCachedServices() {
+ List<UserInfo> supportedUsers = getSupportedUsers();
+ for (UserInfo userInfo : supportedUsers) {
+ synchronized (mLock) {
+ updateCachedServiceLocked(userInfo.id);
+ }
+ }
+ }
+
// Called by Shell command.
void calculateScore(@Nullable String algorithmName, @NonNull String value1,
@NonNull String value2, @NonNull RemoteCallback callback) {
@@ -702,31 +709,44 @@
return;
}
- final Map<String, String[]> whiteListedPackages = getWhitelistedCompatModePackages();
+ final Map<String, String[]> allowedPackages = getAllowedCompatModePackages();
final int compatPackageCount = compatPackages.size();
for (int i = 0; i < compatPackageCount; i++) {
final String packageName = compatPackages.keyAt(i);
- if (whiteListedPackages == null || !whiteListedPackages.containsKey(packageName)) {
- Slog.w(TAG, "Ignoring not whitelisted compat package " + packageName);
+ if (allowedPackages == null || !allowedPackages.containsKey(packageName)) {
+ Slog.w(TAG, "Ignoring not allowed compat package " + packageName);
continue;
}
final Long maxVersionCode = compatPackages.valueAt(i);
if (maxVersionCode != null) {
mAutofillCompatState.addCompatibilityModeRequest(packageName,
- maxVersionCode, whiteListedPackages.get(packageName), userId);
+ maxVersionCode, allowedPackages.get(packageName), userId);
}
}
}
- private String getWhitelistedCompatModePackagesFromSettings() {
+ private String getAllowedCompatModePackagesFromDeviceConfig() {
+ String config = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ AutofillManager.DEVICE_CONFIG_AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES,
+ /* defaultValue */ null);
+ if (!TextUtils.isEmpty(config)) {
+ return config;
+ }
+ // Fallback to Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES if
+ // the device config is null.
+ return getAllowedCompatModePackagesFromSettings();
+ }
+
+ private String getAllowedCompatModePackagesFromSettings() {
return Settings.Global.getString(
getContext().getContentResolver(),
Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES);
}
@Nullable
- private Map<String, String[]> getWhitelistedCompatModePackages() {
- return getWhitelistedCompatModePackages(getWhitelistedCompatModePackagesFromSettings());
+ private Map<String, String[]> getAllowedCompatModePackages() {
+ return getAllowedCompatModePackages(getAllowedCompatModePackagesFromDeviceConfig());
}
private void send(@NonNull IResultReceiver receiver, int value) {
@@ -771,7 +791,7 @@
@Nullable
@VisibleForTesting
- static Map<String, String[]> getWhitelistedCompatModePackages(String setting) {
+ static Map<String, String[]> getAllowedCompatModePackages(String setting) {
if (TextUtils.isEmpty(setting)) {
return null;
}
@@ -1756,8 +1776,8 @@
mUi.dump(pw);
pw.print("Autofill Compat State: ");
mAutofillCompatState.dump(prefix, pw);
- pw.print("from settings: ");
- pw.println(getWhitelistedCompatModePackagesFromSettings());
+ pw.print("from device config: ");
+ pw.println(getAllowedCompatModePackagesFromDeviceConfig());
if (mSupportedSmartSuggestionModes != 0) {
pw.print("Smart Suggestion modes: ");
pw.println(getSmartSuggestionModeToString(mSupportedSmartSuggestionModes));
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ebce30a..9d2b4e7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5823,7 +5823,7 @@
return Arrays.binarySearch(allowlist, appId) >= 0
|| Arrays.binarySearch(mDeviceIdleTempAllowlist, appId) >= 0
- || mPendingTempAllowlist.indexOfKey(uid) >= 0;
+ || mPendingTempAllowlist.get(uid) != null;
}
/**
@@ -15122,11 +15122,13 @@
// First copy out the pending changes... we need to leave them in the map for now,
// in case someone needs to check what is coming up while we don't have the lock held.
- synchronized (mProcLock) {
- N = mPendingTempAllowlist.size();
- list = new PendingTempAllowlist[N];
- for (int i = 0; i < N; i++) {
- list[i] = mPendingTempAllowlist.valueAt(i);
+ synchronized (this) {
+ synchronized (mProcLock) {
+ N = mPendingTempAllowlist.size();
+ list = new PendingTempAllowlist[N];
+ for (int i = 0; i < N; i++) {
+ list[i] = mPendingTempAllowlist.valueAt(i);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5fc11e8..8cb2040 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -56,6 +56,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.WakeLockStats;
import android.os.WorkSource;
import android.os.connectivity.CellularBatteryStats;
import android.os.connectivity.GpsBatteryStats;
@@ -2596,6 +2597,20 @@
}
/**
+ * Gets a snapshot of wake lock stats
+ * @hide
+ */
+ public WakeLockStats getWakeLockStats() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BATTERY_STATS, null);
+
+ // Wait for the completion of pending works if there is any
+ awaitCompletion();
+ synchronized (mStats) {
+ return mStats.getWakeLockStats();
+ }
+ }
+
+ /**
* Gets a snapshot of the system health for a particular uid.
*/
@Override
diff --git a/services/core/java/com/android/server/am/PendingTempAllowlists.java b/services/core/java/com/android/server/am/PendingTempAllowlists.java
index 75935c4..0263de7 100644
--- a/services/core/java/com/android/server/am/PendingTempAllowlists.java
+++ b/services/core/java/com/android/server/am/PendingTempAllowlists.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.os.Process.INVALID_UID;
+
import android.util.SparseArray;
/** Allowlists of uids to temporarily bypass Power Save mode. */
@@ -31,29 +33,42 @@
}
void put(int uid, ActivityManagerService.PendingTempAllowlist value) {
- mPendingTempAllowlist.put(uid, value);
+ synchronized (mPendingTempAllowlist) {
+ mPendingTempAllowlist.put(uid, value);
+ }
mService.mAtmInternal.onUidAddedToPendingTempAllowlist(uid, value.tag);
}
void removeAt(int index) {
- final int uid = mPendingTempAllowlist.keyAt(index);
- mPendingTempAllowlist.removeAt(index);
+ int uid = INVALID_UID;
+ synchronized (mPendingTempAllowlist) {
+ uid = mPendingTempAllowlist.keyAt(index);
+ mPendingTempAllowlist.removeAt(index);
+ }
mService.mAtmInternal.onUidRemovedFromPendingTempAllowlist(uid);
}
ActivityManagerService.PendingTempAllowlist get(int uid) {
- return mPendingTempAllowlist.get(uid);
+ synchronized (mPendingTempAllowlist) {
+ return mPendingTempAllowlist.get(uid);
+ }
}
int size() {
- return mPendingTempAllowlist.size();
+ synchronized (mPendingTempAllowlist) {
+ return mPendingTempAllowlist.size();
+ }
}
ActivityManagerService.PendingTempAllowlist valueAt(int index) {
- return mPendingTempAllowlist.valueAt(index);
+ synchronized (mPendingTempAllowlist) {
+ return mPendingTempAllowlist.valueAt(index);
+ }
}
int indexOfKey(int key) {
- return mPendingTempAllowlist.indexOfKey(key);
+ synchronized (mPendingTempAllowlist) {
+ return mPendingTempAllowlist.indexOfKey(key);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2def50e..1ad0bce 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -135,6 +135,7 @@
import com.android.server.am.ActivityManagerService.ProcessChangeItem;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.WindowManagerService;
@@ -2379,6 +2380,8 @@
final String[] targetPackagesList = sharedPackages.length == 0
? new String[]{app.info.packageName} : sharedPackages;
+ final boolean hasAppStorage = hasAppStorage(pmInt, app.info.packageName);
+
pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
if (pkgDataInfoMap == null) {
// TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
@@ -2401,6 +2404,12 @@
bindMountAppsData = false;
}
+ if (!hasAppStorage) {
+ bindMountAppsData = false;
+ pkgDataInfoMap = null;
+ allowlistedAppDataInfoMap = null;
+ }
+
int userId = UserHandle.getUserId(uid);
StorageManagerInternal storageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
@@ -2488,6 +2497,17 @@
}
}
+ private boolean hasAppStorage(PackageManagerInternal pmInt, String packageName) {
+ final AndroidPackage pkg = pmInt.getPackage(packageName);
+ if (pkg == null) {
+ Slog.w(TAG, "Unknown package " + packageName);
+ return false;
+ }
+ final PackageManager.Property noAppStorageProp =
+ pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+ return noAppStorageProp == null || !noAppStorageProp.getBoolean();
+ }
+
@GuardedBy("mService")
void startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags) {
startProcessLocked(app, hostingRecord, zygotePolicyFlags, null /* abiOverride */);
diff --git a/services/core/java/com/android/server/communal/CommunalManagerService.java b/services/core/java/com/android/server/communal/CommunalManagerService.java
index 1220391..2a6456d 100644
--- a/services/core/java/com/android/server/communal/CommunalManagerService.java
+++ b/services/core/java/com/android/server/communal/CommunalManagerService.java
@@ -16,117 +16,34 @@
package com.android.server.communal;
-import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
-import static android.app.communal.CommunalManager.ALLOW_COMMUNAL_MODE_BY_DEFAULT;
-import static android.app.communal.CommunalManager.ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT;
-import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-
-import static com.android.server.wm.ActivityInterceptorCallback.COMMUNAL_MODE_ORDERED_ID;
-
import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
import android.app.communal.ICommunalManager;
import android.app.communal.ICommunalModeListener;
-import android.app.compat.CompatChanges;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.net.Uri;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.dreams.DreamManagerInternal;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.LaunchAfterAuthenticationActivity;
-import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.wm.ActivityInterceptorCallback;
-import com.android.server.wm.ActivityTaskManagerInternal;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* System service for handling Communal Mode state.
*/
public final class CommunalManagerService extends SystemService {
- private static final String TAG = CommunalManagerService.class.getSimpleName();
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final String DELIMITER = ",";
private final Context mContext;
- private final ActivityTaskManagerInternal mAtmInternal;
- private final KeyguardManager mKeyguardManager;
private final AtomicBoolean mCommunalViewIsShowing = new AtomicBoolean(false);
private final BinderService mBinderService;
- private final PackageReceiver mPackageReceiver;
- private final PackageManager mPackageManager;
- private final DreamManagerInternal mDreamManagerInternal;
private final RemoteCallbackList<ICommunalModeListener> mListeners =
new RemoteCallbackList<>();
- private final ActivityInterceptorCallback mActivityInterceptorCallback =
- new ActivityInterceptorCallback() {
- @Nullable
- @Override
- public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
- if (!shouldIntercept(info.aInfo)) {
- if (DEBUG) {
- Slog.d(TAG, "Activity allowed, not intercepting: "
- + info.aInfo.getComponentName());
- }
- return null;
- }
-
- final IIntentSender target = mAtmInternal.getIntentSender(
- INTENT_SENDER_ACTIVITY,
- info.callingPackage,
- info.callingFeatureId,
- info.callingUid,
- info.userId,
- /* token= */null,
- /* resultWho= */ null,
- /* requestCode= */ 0,
- new Intent[]{info.intent},
- new String[]{info.resolvedType},
- PendingIntent.FLAG_IMMUTABLE,
- /* bOptions= */ null);
-
- return new ActivityInterceptResult(
- LaunchAfterAuthenticationActivity.createLaunchAfterAuthenticationIntent(
- new IntentSender(target)),
- info.checkedOptions);
-
- }
- };
public CommunalManagerService(Context context) {
super(context);
mContext = context;
- mPackageManager = mContext.getPackageManager();
- mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
- mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
- mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
mBinderService = new BinderService();
- mPackageReceiver = new PackageReceiver(mContext);
}
@VisibleForTesting
@@ -139,116 +56,6 @@
publishBinderService(Context.COMMUNAL_SERVICE, mBinderService);
}
- @Override
- public void onBootPhase(int phase) {
- if (phase != SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) return;
- mAtmInternal.registerActivityStartInterceptor(
- COMMUNAL_MODE_ORDERED_ID,
- mActivityInterceptorCallback);
- mPackageReceiver.register();
- removeUninstalledPackagesFromSettings();
- }
-
- @Override
- public void finalize() {
- mPackageReceiver.unregister();
- }
-
- private Set<String> getUserEnabledApps() {
- final String encodedApps = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.COMMUNAL_MODE_PACKAGES,
- UserHandle.USER_SYSTEM);
-
- return TextUtils.isEmpty(encodedApps)
- ? Collections.emptySet()
- : new HashSet<>(Arrays.asList(encodedApps.split(DELIMITER)));
- }
-
- private void removeUninstalledPackagesFromSettings() {
- for (String packageName : getUserEnabledApps()) {
- if (!isPackageInstalled(packageName, mPackageManager)) {
- removePackageFromSettings(packageName);
- }
- }
- }
-
- private void removePackageFromSettings(String packageName) {
- Set<String> enabledPackages = getUserEnabledApps();
- if (enabledPackages.remove(packageName)) {
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.COMMUNAL_MODE_PACKAGES,
- String.join(DELIMITER, enabledPackages),
- UserHandle.USER_SYSTEM);
- }
- }
-
- @VisibleForTesting
- static boolean isPackageInstalled(String packageName, PackageManager packageManager) {
- if (packageManager == null) return false;
- try {
- return packageManager.getPackageInfo(packageName, 0) != null;
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
- }
-
- private boolean isAppAllowed(ApplicationInfo appInfo) {
- if (isActiveDream(appInfo) || isChangeEnabled(ALLOW_COMMUNAL_MODE_BY_DEFAULT, appInfo)) {
- return true;
- }
-
- if (!isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, appInfo)) {
- if (DEBUG) Slog.d(TAG, "App is not allowlisted: " + appInfo.packageName);
- return false;
- }
-
- if (!getUserEnabledApps().contains(appInfo.packageName)) {
- if (DEBUG) Slog.d(TAG, "App does not have user consent: " + appInfo.packageName);
- return false;
- }
-
- return true;
- }
-
- private boolean isActiveDream(ApplicationInfo appInfo) {
- final ComponentName activeDream = mDreamManagerInternal.getActiveDreamComponent(
- /* doze= */ false);
- final ComponentName activeDoze = mDreamManagerInternal.getActiveDreamComponent(
- /* doze= */ true);
- return isFromPackage(activeDream, appInfo) || isFromPackage(activeDoze, appInfo);
- }
-
- private static boolean isFromPackage(ComponentName componentName, ApplicationInfo appInfo) {
- if (componentName == null) return false;
- return TextUtils.equals(appInfo.packageName, componentName.getPackageName());
- }
-
- private static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
- return CompatChanges.isChangeEnabled(changeId, appInfo.packageName, UserHandle.SYSTEM);
- }
-
- private boolean shouldIntercept(ActivityInfo activityInfo) {
- if (!mCommunalViewIsShowing.get() || !mKeyguardManager.isKeyguardLocked()) return false;
- ApplicationInfo appInfo = activityInfo.applicationInfo;
- // Dreams are allowed to show, and don't require the showWhenLocked attribute.
- if (isActiveDream(appInfo)) return false;
-
- // If the activity doesn't have showWhenLocked enabled, disallow the activity.
- final boolean showWhenLocked =
- (activityInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0;
- if (!showWhenLocked) {
- if (DEBUG) {
- Slog.d(TAG, "Activity does not contain showWhenLocked attribute: "
- + activityInfo.getComponentName());
- }
- return true;
- }
-
- return !isAppAllowed(appInfo);
- }
-
private void dispatchCommunalMode(boolean isShowing) {
synchronized (mListeners) {
int i = mListeners.beginBroadcast();
@@ -319,50 +126,4 @@
}
}
}
-
- /**
- * A {@link BroadcastReceiver} that listens on package removed events and updates any stored
- * package state in Settings.
- */
- private final class PackageReceiver extends BroadcastReceiver {
- private final Context mContext;
- private final IntentFilter mIntentFilter;
-
- private PackageReceiver(Context context) {
- mContext = context;
- mIntentFilter = new IntentFilter();
- mIntentFilter.addAction(ACTION_PACKAGE_REMOVED);
- mIntentFilter.addDataScheme("package");
- }
-
- private void register() {
- mContext.registerReceiverAsUser(
- this,
- UserHandle.SYSTEM,
- mIntentFilter,
- /* broadcastPermission= */null,
- /* scheduler= */ null,
- Context.RECEIVER_EXPORTED_UNAUDITED);
- }
-
- private void unregister() {
- mContext.unregisterReceiver(this);
- }
-
- @Override
- public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
- final Uri data = intent.getData();
- if (data == null) {
- Slog.w(TAG, "Failed to get package name in package receiver");
- return;
- }
- final String packageName = data.getSchemeSpecificPart();
- final String action = intent.getAction();
- if (ACTION_PACKAGE_REMOVED.equals(action)) {
- removePackageFromSettings(packageName);
- } else {
- Slog.w(TAG, "Unsupported action in package receiver: " + action);
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index d2baaf22..d632ee3 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -147,7 +147,8 @@
getContext(), getHandler(), mWifiDisplayListener);
getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
- new IntentFilter(ACTION_DISCONNECT), null, mHandler);
+ new IntentFilter(ACTION_DISCONNECT), null, mHandler,
+ Context.RECEIVER_NOT_EXPORTED);
}
});
}
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 1461675..9e00f95 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -509,7 +509,7 @@
*
* <pre><code>
* resolver.registerContentObserver(Settings.Global.getUriFor(
- * Settings.Global.AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES), false, observer,
+ * Settings.Global.AUTOFILL_LOGGING_LEVEL), false, observer,
* UserHandle.USER_ALL);
* </code></pre>
*
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index 19f7c4d..c199bb3 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -152,6 +152,14 @@
@Override
/* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ ContextHubStatsLog.write(
+ ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED,
+ nanoAppBinary.getNanoAppId(),
+ nanoAppBinary.getNanoAppVersion(),
+ ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_LOAD,
+ toStatsTransactionResult(result));
+
if (result == ContextHubTransaction.RESULT_SUCCESS) {
// NOTE: The legacy JNI code used to do a query right after a load success
// to synchronize the service cache. Instead store the binary that was
@@ -200,6 +208,13 @@
@Override
/* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ ContextHubStatsLog.write(
+ ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED, nanoAppId,
+ 0 /* nanoappVersion */,
+ ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_UNLOAD,
+ toStatsTransactionResult(result));
+
if (result == ContextHubTransaction.RESULT_SUCCESS) {
mNanoAppStateManager.removeNanoAppInstance(contextHubId, nanoAppId);
}
@@ -477,6 +492,30 @@
}
}
+ private int toStatsTransactionResult(@ContextHubTransaction.Result int result) {
+ switch (result) {
+ case ContextHubTransaction.RESULT_SUCCESS:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_SUCCESS;
+ case ContextHubTransaction.RESULT_FAILED_BAD_PARAMS:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BAD_PARAMS;
+ case ContextHubTransaction.RESULT_FAILED_UNINITIALIZED:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNINITIALIZED;
+ case ContextHubTransaction.RESULT_FAILED_BUSY:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BUSY;
+ case ContextHubTransaction.RESULT_FAILED_AT_HUB:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_AT_HUB;
+ case ContextHubTransaction.RESULT_FAILED_TIMEOUT:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_TIMEOUT;
+ case ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_SERVICE_INTERNAL_FAILURE;
+ case ContextHubTransaction.RESULT_FAILED_HAL_UNAVAILABLE:
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_HAL_UNAVAILABLE;
+ case ContextHubTransaction.RESULT_FAILED_UNKNOWN:
+ default: /* fall through */
+ return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNKNOWN;
+ }
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(100);
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index cc5dcf30..a513e08 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -623,8 +623,38 @@
public void injectLocation(Location location) {
Preconditions.checkState(mRegistered);
if (location.hasAccuracy()) {
- mGnssHal.injectLocation(location.getLatitude(), location.getLongitude(),
- location.getAccuracy());
+
+ int gnssLocationFlags = GNSS_LOCATION_HAS_LAT_LONG
+ | (location.hasAltitude() ? GNSS_LOCATION_HAS_ALTITUDE : 0)
+ | (location.hasSpeed() ? GNSS_LOCATION_HAS_SPEED : 0)
+ | (location.hasBearing() ? GNSS_LOCATION_HAS_BEARING : 0)
+ | (location.hasAccuracy() ? GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY : 0)
+ | (location.hasVerticalAccuracy() ? GNSS_LOCATION_HAS_VERTICAL_ACCURACY : 0)
+ | (location.hasSpeedAccuracy() ? GNSS_LOCATION_HAS_SPEED_ACCURACY : 0)
+ | (location.hasBearingAccuracy() ? GNSS_LOCATION_HAS_BEARING_ACCURACY : 0);
+
+ double latitudeDegrees = location.getLatitude();
+ double longitudeDegrees = location.getLongitude();
+ double altitudeMeters = location.getAltitude();
+ float speedMetersPerSec = location.getSpeed();
+ float bearingDegrees = location.getBearing();
+ float horizontalAccuracyMeters = location.getAccuracy();
+ float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
+ float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
+ float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
+ long timestamp = location.getTime();
+
+ int elapsedRealtimeFlags = GNSS_REALTIME_HAS_TIMESTAMP_NS
+ | (location.hasElapsedRealtimeUncertaintyNanos()
+ ? GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
+ long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
+ double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
+
+ mGnssHal.injectLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
+ verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
}
}
@@ -1263,8 +1293,15 @@
return native_read_nmea(buffer, bufferSize);
}
- protected void injectLocation(double latitude, double longitude, float accuracy) {
- native_inject_location(latitude, longitude, accuracy);
+ protected void injectLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
+ double longitude, double altitude, float speed, float bearing,
+ float horizontalAccuracy, float verticalAccuracy, float speedAccuracy,
+ float bearingAccuracy, long timestamp, @GnssRealtimeFlags int elapsedRealtimeFlags,
+ long elapsedRealtimeNanos, double elapsedRealtimeUncertaintyNanos) {
+ native_inject_location(gnssLocationFlags, latitude, longitude, altitude, speed,
+ bearing, horizontalAccuracy, verticalAccuracy, speedAccuracy, bearingAccuracy,
+ timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
}
protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
@@ -1438,8 +1475,13 @@
// location injection APIs
- private static native void native_inject_location(double latitude, double longitude,
- float accuracy);
+ private static native void native_inject_location(
+ int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees,
+ double altitudeMeters, float speedMetersPerSec, float bearingDegrees,
+ float horizontalAccuracyMeters, float verticalAccuracyMeters,
+ float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees,
+ long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos,
+ double elapsedRealtimeUncertaintyNanos);
private static native void native_inject_best_location(
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index bedb8b9..22cd06d 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -101,6 +101,12 @@
mPm.mSettings.writeKernelMappingLPr(ps);
}
+ // TODO(b/211761016): should we still create the profile dirs?
+ if (!shouldHaveAppStorage(pkg)) {
+ Slog.w(TAG, "Skipping preparing app data for " + pkg.getPackageName());
+ return;
+ }
+
Installer.Batch batch = new Installer.Batch();
UserManagerInternal umInternal = mInjector.getUserManagerInternal();
StorageManagerInternal smInternal = mInjector.getLocalService(
@@ -161,6 +167,10 @@
Slog.wtf(TAG, "Package was null!", new Throwable());
return CompletableFuture.completedFuture(null);
}
+ if (!shouldHaveAppStorage(pkg)) {
+ Slog.w(TAG, "Skipping preparing app data for " + pkg.getPackageName());
+ return CompletableFuture.completedFuture(null);
+ }
return prepareAppDataLeaf(batch, pkg, previousAppId, userId, flags);
}
@@ -381,7 +391,7 @@
for (File file : files) {
final String packageName = file.getName();
try {
- assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+ assertPackageStorageValid(volumeUuid, packageName, userId);
} catch (PackageManagerException e) {
logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
try {
@@ -398,7 +408,7 @@
for (File file : files) {
final String packageName = file.getName();
try {
- assertPackageKnownAndInstalled(volumeUuid, packageName, userId);
+ assertPackageStorageValid(volumeUuid, packageName, userId);
} catch (PackageManagerException e) {
logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
try {
@@ -446,7 +456,11 @@
return result;
}
- private void assertPackageKnownAndInstalled(String volumeUuid, String packageName, int userId)
+ /**
+ * Asserts that storage path is valid by checking that {@code packageName} is present,
+ * installed for the given {@code userId} and can have app data.
+ */
+ private void assertPackageStorageValid(String volumeUuid, String packageName, int userId)
throws PackageManagerException {
synchronized (mPm.mLock) {
// Normalize package name to handle renamed packages
@@ -462,6 +476,13 @@
} else if (!ps.getInstalled(userId)) {
throw new PackageManagerException(
"Package " + packageName + " not installed for user " + userId);
+ } else if (ps.getPkg() == null) {
+ throw new PackageManagerException("Package " + packageName + " is not parsed yet");
+ } else {
+ if (!shouldHaveAppStorage(ps.getPkg())) {
+ throw new PackageManagerException(
+ "Package " + packageName + " shouldn't have storage");
+ }
}
}
}
@@ -603,4 +624,13 @@
Slog.w(TAG, String.valueOf(e));
}
}
+
+ /**
+ * Returns {@code true} if app's internal storage should be created for this {@code pkg}.
+ */
+ private boolean shouldHaveAppStorage(AndroidPackage pkg) {
+ PackageManager.Property noAppDataProp =
+ pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+ return noAppDataProp == null || !noAppDataProp.getBoolean();
+ }
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 0f96e83..27b6282 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -942,17 +942,26 @@
if (result.needsNewAppId()) {
request.mInstallResult.mRemovedInfo.mAppIdChanging = true;
}
+ if (!checkNoAppStorageIsConsistent(
+ result.mRequest.mOldPkg, result.mPkgSetting.getPkg())) {
+ // TODO: INSTALL_FAILED_UPDATE_INCOMPATIBLE is about incomptabible
+ // signatures. Is there a better error code?
+ request.mInstallResult.setError(
+ INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "Update attempted to change value of "
+ + PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+ return;
+ }
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
versionInfos.put(result.mPkgSetting.getPkg().getPackageName(),
mPm.getSettingsVersionForPackage(result.mPkgSetting.getPkg()));
- if (result.mStaticSharedLibraryInfo != null
- || result.mSdkSharedLibraryInfo != null) {
- final PackageSetting sharedLibLatestVersionSetting =
- mSharedLibraries.getSharedLibLatestVersionSetting(result);
- if (sharedLibLatestVersionSetting != null) {
+ if (result.mStaticSharedLibraryInfo != null) {
+ final PackageSetting staticSharedLibLatestVersionSetting =
+ mSharedLibraries.getStaticSharedLibLatestVersionSetting(result);
+ if (staticSharedLibLatestVersionSetting != null) {
lastStaticSharedLibSettings.put(
result.mPkgSetting.getPkg().getPackageName(),
- sharedLibLatestVersionSetting);
+ staticSharedLibLatestVersionSetting);
}
}
} catch (PackageManagerException e) {
@@ -1040,6 +1049,22 @@
}
@GuardedBy("mPm.mInstallLock")
+ private boolean checkNoAppStorageIsConsistent(AndroidPackage oldPkg, AndroidPackage newPkg) {
+ if (oldPkg == null) {
+ // New install, nothing to check against.
+ return true;
+ }
+ final PackageManager.Property curProp =
+ oldPkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+ final PackageManager.Property newProp =
+ newPkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
+ if (curProp == null || !curProp.getBoolean()) {
+ return newProp == null || !newProp.getBoolean();
+ }
+ return newProp != null && newProp.getBoolean();
+ }
+
+ @GuardedBy("mPm.mInstallLock")
private PrepareResult preparePackageLI(InstallArgs args, PackageInstalledInfo res)
throws PrepareFailure {
final int installFlags = args.mInstallFlags;
@@ -3559,22 +3584,20 @@
boolean appIdCreated = false;
try {
final String pkgName = scanResult.mPkgSetting.getPackageName();
+ final ReconcileRequest reconcileRequest = new ReconcileRequest(
+ Collections.singletonMap(pkgName, scanResult),
+ mSharedLibraries.getAll(), mPm.mPackages,
+ Collections.singletonMap(pkgName,
+ mPm.getSettingsVersionForPackage(parsedPackage)),
+ Collections.singletonMap(pkgName,
+ mSharedLibraries.getStaticSharedLibLatestVersionSetting(
+ scanResult)));
final Map<String, ReconciledPackage> reconcileResult =
- ReconcilePackageUtils.reconcilePackages(
- new ReconcileRequest(
- Collections.singletonMap(pkgName, scanResult),
- mSharedLibraries.getAll(),
- mPm.mPackages,
- Collections.singletonMap(
- pkgName,
- mPm.getSettingsVersionForPackage(
- parsedPackage)),
- Collections.singletonMap(pkgName, mSharedLibraries
- .getSharedLibLatestVersionSetting(scanResult))),
+ ReconcilePackageUtils.reconcilePackages(reconcileRequest,
mPm.mSettings.getKeySetManagerService(), mPm.mInjector);
appIdCreated = optimisticallyRegisterAppId(scanResult);
- commitReconciledScanResultLocked(
- reconcileResult.get(pkgName), mPm.mUserManager.getUserIds());
+ commitReconciledScanResultLocked(reconcileResult.get(pkgName),
+ mPm.mUserManager.getUserIds());
} catch (PackageManagerException e) {
if (appIdCreated) {
cleanUpAppIdCreation(scanResult);
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 0777cde..ca87685 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -88,6 +88,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -103,6 +104,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.ExecutionException;
/**
* Service that manages requests and callbacks for launchers that support
@@ -728,9 +730,16 @@
return null;
}
- final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
- getCallingUserId(), callingPackage, packageName, shortcutId,
- user.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid());
+ final AndroidFuture<Intent[]> ret = new AndroidFuture<>();
+ Intent[] intents;
+ mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(),
+ callingPackage, packageName, shortcutId, user.getIdentifier(),
+ injectBinderCallingPid(), injectBinderCallingUid(), ret);
+ try {
+ intents = ret.get();
+ } catch (InterruptedException | ExecutionException e) {
+ return null;
+ }
if (intents == null || intents.length == 0) {
return null;
}
@@ -901,6 +910,40 @@
}
@Override
+ public void getShortcutsAsync(@NonNull final String callingPackage,
+ @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser,
+ @NonNull final AndroidFuture<List<ShortcutInfo>> cb) {
+ ensureShortcutPermission(callingPackage);
+ if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) {
+ cb.complete(Collections.EMPTY_LIST);
+ return;
+ }
+
+ final long changedSince = query.getChangedSince();
+ final String packageName = query.getPackage();
+ final List<String> shortcutIds = query.getShortcutIds();
+ final List<LocusId> locusIds = query.getLocusIds();
+ final ComponentName componentName = query.getActivity();
+ final int flags = query.getQueryFlags();
+ if (shortcutIds != null && packageName == null) {
+ throw new IllegalArgumentException(
+ "To query by shortcut ID, package name must also be set");
+ }
+ if (locusIds != null && packageName == null) {
+ throw new IllegalArgumentException(
+ "To query by locus ID, package name must also be set");
+ }
+ if ((query.getQueryFlags() & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) {
+ ensureStrictAccessShortcutsPermission(callingPackage);
+ }
+
+ mShortcutServiceInternal.getShortcutsAsync(getCallingUserId(),
+ callingPackage, changedSince, packageName, shortcutIds, locusIds,
+ componentName, flags, targetUser.getIdentifier(),
+ injectBinderCallingPid(), injectBinderCallingUid(), cb);
+ }
+
+ @Override
public void registerShortcutChangeCallback(@NonNull final String callingPackage,
@NonNull final ShortcutQueryWrapper query,
@NonNull final IShortcutChangeCallback callback) {
@@ -991,8 +1034,14 @@
return null;
}
- return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(),
- callingPackage, packageName, id, targetUserId);
+ final AndroidFuture<ParcelFileDescriptor> ret = new AndroidFuture<>();
+ mShortcutServiceInternal.getShortcutIconFdAsync(getCallingUserId(),
+ callingPackage, packageName, id, targetUserId, ret);
+ try {
+ return ret.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
@@ -1003,8 +1052,14 @@
return null;
}
- return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage,
- packageName, shortcutId, userId);
+ final AndroidFuture<String> ret = new AndroidFuture<>();
+ mShortcutServiceInternal.getShortcutIconUriAsync(getCallingUserId(), callingPackage,
+ packageName, shortcutId, userId, ret);
+ try {
+ return ret.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
}
@Override
@@ -1037,9 +1092,16 @@
ensureShortcutPermission(callerUid, callerPid, callingPackage);
}
- final Intent[] intents = mShortcutServiceInternal.createShortcutIntents(
- callingUserId, callingPackage, packageName, shortcutId, targetUserId,
- callerPid, callerUid);
+ final AndroidFuture<Intent[]> ret = new AndroidFuture<>();
+ Intent[] intents;
+ mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage,
+ packageName, shortcutId, targetUserId,
+ injectBinderCallingPid(), injectBinderCallingUid(), ret);
+ try {
+ intents = ret.get();
+ } catch (InterruptedException | ExecutionException e) {
+ return false;
+ }
if (intents == null || intents.length == 0) {
return false;
}
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index f38ae77..0055f4e 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -381,7 +381,7 @@
* @return The package setting that represents the latest version of shared library info.
*/
@Nullable
- PackageSetting getSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
+ PackageSetting getStaticSharedLibLatestVersionSetting(@NonNull ScanResult scanResult) {
PackageSetting sharedLibPackage = null;
synchronized (mPm.mLock) {
final SharedLibraryInfo latestSharedLibraVersionLPr =
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 3d10b6f..bf7ef1b 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -22,6 +22,7 @@
import android.app.appsearch.AppSearchManager;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSession;
+import android.app.appsearch.GetByDocumentIdRequest;
import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.PutDocumentsRequest;
import android.app.appsearch.RemoveByDocumentIdRequest;
@@ -820,42 +821,6 @@
getPinnedByAnyLauncher, si));
}
- /**
- * Find all shortcuts that has id matching {@code ids}.
- */
- public void findAllByIds(@NonNull final List<ShortcutInfo> result,
- @NonNull final Collection<String> ids, @Nullable final Predicate<ShortcutInfo> filter,
- final int cloneFlag) {
- findAllByIds(result, ids, filter, cloneFlag, null, 0, /*getPinnedByAnyLauncher=*/ false);
- }
-
- /**
- * Find all shortcuts that has id matching {@code ids}.
- *
- * This will also provide a "view" for each launcher -- a non-dynamic shortcut that's not pinned
- * by the calling launcher will not be included in the result, and also "isPinned" will be
- * adjusted for the caller too.
- */
- public void findAllByIds(@NonNull List<ShortcutInfo> result,
- @NonNull final Collection<String> ids, @Nullable final Predicate<ShortcutInfo> query,
- int cloneFlag, @Nullable String callingLauncher, int launcherUserId,
- boolean getPinnedByAnyLauncher) {
- if (getPackageInfo().isShadow()) {
- // Restored and the app not installed yet, so don't return any.
- return;
- }
- final ShortcutService s = mShortcutUser.mService;
-
- // Set of pinned shortcuts by the calling launcher.
- final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
- : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
- .getPinnedShortcutIds(getPackageName(), getPackageUserId());
- for (ShortcutInfo si : mShortcuts.values()) {
- filter(result, query, cloneFlag, callingLauncher, pinnedByCallerSet,
- getPinnedByAnyLauncher, si);
- }
- }
-
private void filter(@NonNull final List<ShortcutInfo> result,
@Nullable final Predicate<ShortcutInfo> query, final int cloneFlag,
@Nullable final String callingLauncher,
@@ -2411,6 +2376,25 @@
})));
}
+ void getShortcutByIdsAsync(@NonNull final Set<String> ids,
+ @NonNull final Consumer<List<ShortcutInfo>> cb) {
+ if (!isAppSearchEnabled()) {
+ cb.accept(Collections.emptyList());
+ return;
+ }
+ runAsSystem(() -> fromAppSearch().thenAccept(session -> {
+ session.getByDocumentId(new GetByDocumentIdRequest.Builder(getPackageName())
+ .addIds(ids).build(), mShortcutUser.mExecutor, result -> {
+ final List<ShortcutInfo> ret = result.getSuccesses().values()
+ .stream().map(doc ->
+ new AppSearchShortcutInfo(doc)
+ .toShortcutInfo(mShortcutUser.getUserId()))
+ .collect(Collectors.toList());
+ cb.accept(ret);
+ });
+ }));
+ }
+
private void removeShortcutAsync(@NonNull final String... id) {
Objects.requireNonNull(id);
removeShortcutAsync(Arrays.asList(id));
@@ -2444,9 +2428,8 @@
}
if (ShortcutService.DEBUG_REBOOT) {
Slog.d(TAG, "Saving shortcuts async for user=" + mShortcutUser.getUserId()
- + " pkg=" + getPackageName() + " ids=["
- + shortcuts.stream().map(ShortcutInfo::getId)
- .collect(Collectors.joining(",")) + "]");
+ + " pkg=" + getPackageName() + " ids=" + shortcuts.stream()
+ .map(ShortcutInfo::getId).collect(Collectors.joining(",", "[", "]")));
}
runAsSystem(() -> fromAppSearch().thenAccept(session -> {
if (shortcuts.isEmpty()) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a482f9a..0a2735cd 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -153,6 +153,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* TODO:
@@ -2957,13 +2958,8 @@
final Predicate<ShortcutInfo> filter = getFilterFromQuery(ids, locusIds, changedSince,
componentName, queryFlags, getPinnedByAnyLauncher);
- if (ids != null && !ids.isEmpty()) {
- p.findAllByIds(ret, ids, filter, cloneFlag, callingPackage, launcherUserId,
+ p.findAll(ret, filter, cloneFlag, callingPackage, launcherUserId,
getPinnedByAnyLauncher);
- } else {
- p.findAll(ret, filter, cloneFlag, callingPackage, launcherUserId,
- getPinnedByAnyLauncher);
- }
}
private Predicate<ShortcutInfo> getFilterFromQuery(@Nullable ArraySet<String> ids,
@@ -3010,6 +3006,51 @@
}
@Override
+ public void getShortcutsAsync(int launcherUserId,
+ @NonNull String callingPackage, long changedSince,
+ @Nullable String packageName, @Nullable List<String> shortcutIds,
+ @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName,
+ int queryFlags, int userId, int callingPid, int callingUid,
+ @NonNull AndroidFuture<List<ShortcutInfo>> cb) {
+ final List<ShortcutInfo> ret = getShortcuts(launcherUserId, callingPackage,
+ changedSince, packageName, shortcutIds, locusIds, componentName, queryFlags,
+ userId, callingPid, callingUid);
+ if (shortcutIds == null || packageName == null || ret.size() >= shortcutIds.size()) {
+ // skip persistence layer if not querying by id in a specific package or all
+ // shortcuts have already been found.
+ cb.complete(ret);
+ return;
+ }
+ final ShortcutPackage p;
+ synchronized (mLock) {
+ p = getUserShortcutsLocked(userId).getPackageShortcutsIfExists(packageName);
+ }
+ if (p == null) {
+ cb.complete(ret);
+ return; // Bail-out directly if package doesn't exist.
+ }
+ // fetch remaining shortcuts from persistence layer
+ final ArraySet<String> ids = new ArraySet<>(shortcutIds);
+ // remove the ids that are already fetched
+ ret.stream().map(ShortcutInfo::getId).collect(Collectors.toList()).forEach(ids::remove);
+
+ int flags = ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER;
+ if ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0) {
+ flags = ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
+ } else if ((queryFlags & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) {
+ flags &= ~ShortcutInfo.CLONE_REMOVE_PERSON;
+ }
+ final int cloneFlag = flags;
+
+ p.getShortcutByIdsAsync(ids, shortcuts -> {
+ if (shortcuts != null) {
+ shortcuts.stream().map(si -> si.clone(cloneFlag)).forEach(ret::add);
+ }
+ cb.complete(ret);
+ });
+ }
+
+ @Override
public boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId) {
Preconditions.checkStringNotEmpty(packageName, "packageName");
@@ -3047,12 +3088,32 @@
}
final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
- p.findAllByIds(list, Collections.singletonList(shortcutId),
- (ShortcutInfo si) -> shortcutId.equals(si.getId()),
+ p.findAll(list, (ShortcutInfo si) -> shortcutId.equals(si.getId()),
/* clone flags=*/ 0, callingPackage, launcherUserId, getPinnedByAnyLauncher);
return list.size() == 0 ? null : list.get(0);
}
+ private void getShortcutInfoAsync(
+ int launcherUserId, @NonNull String packageName, @NonNull String shortcutId,
+ int userId, @NonNull Consumer<ShortcutInfo> cb) {
+ Preconditions.checkStringNotEmpty(packageName, "packageName");
+ Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
+
+ throwIfUserLockedL(userId);
+ throwIfUserLockedL(launcherUserId);
+
+ final ShortcutPackage p;
+ synchronized (mLock) {
+ p = getUserShortcutsLocked(userId).getPackageShortcutsIfExists(packageName);
+ }
+ if (p == null) {
+ cb.accept(null);
+ return;
+ }
+ p.getShortcutByIdsAsync(Collections.singleton(shortcutId), shortcuts ->
+ cb.accept(shortcuts == null || shortcuts.isEmpty() ? null : shortcuts.get(0)));
+ }
+
@Override
public void pinShortcuts(int launcherUserId,
@NonNull String callingPackage, @NonNull String packageName,
@@ -3237,6 +3298,48 @@
}
@Override
+ public void createShortcutIntentsAsync(int launcherUserId,
+ @NonNull String callingPackage, @NonNull String packageName,
+ @NonNull String shortcutId, int userId, int callingPid,
+ int callingUid, @NonNull AndroidFuture<Intent[]> cb) {
+ // Calling permission must be checked by LauncherAppsImpl.
+ Preconditions.checkStringNotEmpty(packageName, "packageName can't be empty");
+ Preconditions.checkStringNotEmpty(shortcutId, "shortcutId can't be empty");
+
+ // Check in memory shortcut first
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+ throwIfUserLockedL(launcherUserId);
+
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave();
+
+ final boolean getPinnedByAnyLauncher =
+ canSeeAnyPinnedShortcut(callingPackage, launcherUserId,
+ callingPid, callingUid);
+
+ // Make sure the shortcut is actually visible to the launcher.
+ final ShortcutInfo si = getShortcutInfoLocked(
+ launcherUserId, callingPackage, packageName, shortcutId, userId,
+ getPinnedByAnyLauncher);
+ if (si != null) {
+ if (!si.isEnabled() || !(si.isAlive() || getPinnedByAnyLauncher)) {
+ Log.e(TAG, "Shortcut " + shortcutId + " does not exist or disabled");
+ cb.complete(null);
+ return;
+ }
+ cb.complete(si.getIntents());
+ return;
+ }
+ }
+
+ // Otherwise check persisted shortcuts
+ getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
+ cb.complete(si == null ? null : si.getIntents());
+ });
+ }
+
+ @Override
public void addListener(@NonNull ShortcutChangeListener listener) {
synchronized (mLock) {
mListeners.add(Objects.requireNonNull(listener));
@@ -3326,23 +3429,68 @@
}
final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
- if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
+ if (shortcutInfo == null) {
return null;
}
- final String path = mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcutInfo);
- if (path == null) {
- Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
- return null;
+ return getShortcutIconParcelFileDescriptor(shortcutInfo);
+ }
+ }
+
+ @Override
+ public void getShortcutIconFdAsync(int launcherUserId, @NonNull String callingPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId,
+ @NonNull AndroidFuture<ParcelFileDescriptor> cb) {
+ Objects.requireNonNull(callingPackage, "callingPackage");
+ Objects.requireNonNull(packageName, "packageName");
+ Objects.requireNonNull(shortcutId, "shortcutId");
+
+ // Checks shortcuts in memory first
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+ throwIfUserLockedL(launcherUserId);
+
+ getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave();
+
+ final ShortcutPackage p = getUserShortcutsLocked(userId)
+ .getPackageShortcutsIfExists(packageName);
+ if (p == null) {
+ cb.complete(null);
+ return;
}
- try {
- return ParcelFileDescriptor.open(
- new File(path),
- ParcelFileDescriptor.MODE_READ_ONLY);
- } catch (FileNotFoundException e) {
- Slog.e(TAG, "Icon file not found: " + path);
- return null;
+
+ final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
+ if (shortcutInfo != null) {
+ cb.complete(getShortcutIconParcelFileDescriptor(shortcutInfo));
+ return;
}
}
+
+ // Otherwise check persisted shortcuts
+ getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
+ cb.complete(getShortcutIconParcelFileDescriptor(si));
+ });
+ }
+
+ @Nullable
+ private ParcelFileDescriptor getShortcutIconParcelFileDescriptor(
+ @NonNull final ShortcutInfo shortcutInfo) {
+ if (!shortcutInfo.hasIconFile()) {
+ return null;
+ }
+ final String path = mShortcutBitmapSaver.getBitmapPathMayWaitLocked(shortcutInfo);
+ if (path == null) {
+ Slog.w(TAG, "null bitmap detected in getShortcutIconFd()");
+ return null;
+ }
+ try {
+ return ParcelFileDescriptor.open(
+ new File(path),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ Slog.e(TAG, "Icon file not found: " + path);
+ return null;
+ }
}
@Override
@@ -3366,34 +3514,82 @@
}
final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
- if (shortcutInfo == null || !shortcutInfo.hasIconUri()) {
+ if (shortcutInfo == null) {
return null;
}
- String uri = shortcutInfo.getIconUri();
- if (uri == null) {
- Slog.w(TAG, "null uri detected in getShortcutIconUri()");
- return null;
+ return getShortcutIconUriInternal(launcherUserId, launcherPackage,
+ packageName, shortcutInfo, userId);
+ }
+ }
+
+ @Override
+ public void getShortcutIconUriAsync(int launcherUserId, @NonNull String launcherPackage,
+ @NonNull String packageName, @NonNull String shortcutId, int userId,
+ @NonNull AndroidFuture<String> cb) {
+ Objects.requireNonNull(launcherPackage, "launcherPackage");
+ Objects.requireNonNull(packageName, "packageName");
+ Objects.requireNonNull(shortcutId, "shortcutId");
+
+ // Checks shortcuts in memory first
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+ throwIfUserLockedL(launcherUserId);
+
+ getLauncherShortcutsLocked(launcherPackage, userId, launcherUserId)
+ .attemptToRestoreIfNeededAndSave();
+
+ final ShortcutPackage p = getUserShortcutsLocked(userId)
+ .getPackageShortcutsIfExists(packageName);
+ if (p == null) {
+ cb.complete(null);
+ return;
}
- final long token = Binder.clearCallingIdentity();
- try {
- int packageUid = mPackageManagerInternal.getPackageUid(packageName,
- PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
- // Grant read uri permission to the caller on behalf of the shortcut owner. All
- // granted permissions are revoked when the default launcher changes, or when
- // device is rebooted.
- mUriGrantsManager.grantUriPermissionFromOwner(mUriPermissionOwner, packageUid,
- launcherPackage, Uri.parse(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION,
- userId, launcherUserId);
- } catch (Exception e) {
- Slog.e(TAG, "Failed to grant uri access to " + launcherPackage + " for " + uri,
- e);
- uri = null;
- } finally {
- Binder.restoreCallingIdentity(token);
+ final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
+ if (shortcutInfo != null) {
+ cb.complete(getShortcutIconUriInternal(launcherUserId, launcherPackage,
+ packageName, shortcutInfo, userId));
+ return;
}
- return uri;
}
+
+ // Otherwise check persisted shortcuts
+ getShortcutInfoAsync(launcherUserId, packageName, shortcutId, userId, si -> {
+ cb.complete(getShortcutIconUriInternal(launcherUserId, launcherPackage,
+ packageName, si, userId));
+ });
+ }
+
+ private String getShortcutIconUriInternal(int launcherUserId,
+ @NonNull String launcherPackage, @NonNull String packageName,
+ @NonNull ShortcutInfo shortcutInfo, int userId) {
+ if (!shortcutInfo.hasIconUri()) {
+ return null;
+ }
+ String uri = shortcutInfo.getIconUri();
+ if (uri == null) {
+ Slog.w(TAG, "null uri detected in getShortcutIconUri()");
+ return null;
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ int packageUid = mPackageManagerInternal.getPackageUid(packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
+ // Grant read uri permission to the caller on behalf of the shortcut owner. All
+ // granted permissions are revoked when the default launcher changes, or when
+ // device is rebooted.
+ mUriGrantsManager.grantUriPermissionFromOwner(mUriPermissionOwner, packageUid,
+ launcherPackage, Uri.parse(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ userId, launcherUserId);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to grant uri access to " + launcherPackage + " for " + uri,
+ e);
+ uri = null;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return uri;
}
@Override
@@ -5154,7 +5350,7 @@
}
List<ShortcutInfo> result = new ArrayList<>();
- ps.findAllByIds(result, resultIds, (ShortcutInfo si) -> resultIds.contains(si.getId()),
+ ps.findAll(result, (ShortcutInfo si) -> resultIds.contains(si.getId()),
ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
return result;
}
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index a5969a8..54ece73 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -138,7 +138,8 @@
// By default CLOSE_SYSTEM_DIALOGS broadcast is sent only for current user, which is user
// 10 on devices with headless system user enabled.
// In order to receive the broadcast, register the broadcast receiver with UserHandle.ALL.
- context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+ context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null,
+ Context.RECEIVER_EXPORTED);
mHasTelephony =
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index e94575c..b03db66 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -213,7 +213,7 @@
CloseDialogReceiver(Context context) {
mContext = context;
IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(this, filter);
+ context.registerReceiver(this, filter, Context.RECEIVER_EXPORTED);
}
@Override
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 4eae939..54ec884 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -18,6 +18,9 @@
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
+import static android.app.StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+import static android.app.StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
+import static android.app.StatusBarManager.NavBarModeOverride;
import static android.view.Display.DEFAULT_DISPLAY;
import android.Manifest;
@@ -59,6 +62,7 @@
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
+import android.provider.Settings;
import android.service.notification.NotificationStats;
import android.service.quicksettings.TileService;
import android.text.TextUtils;
@@ -1846,6 +1850,51 @@
return mContext.getResources().getStringArray(R.array.config_statusBarIcons);
}
+ /**
+ * Sets or removes the navigation bar mode override.
+ *
+ * @param navBarModeOverride the mode of the navigation bar override to be set.
+ */
+ public void setNavBarModeOverride(@NavBarModeOverride int navBarModeOverride) {
+ enforceStatusBar();
+ if (navBarModeOverride != NAV_BAR_MODE_OVERRIDE_NONE
+ && navBarModeOverride != NAV_BAR_MODE_OVERRIDE_KIDS) {
+ throw new UnsupportedOperationException(
+ "Supplied navBarModeOverride not supported: " + navBarModeOverride);
+ }
+
+ final int userId = mCurrentUserId;
+ final long userIdentity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NAV_BAR_KIDS_MODE, navBarModeOverride, userId);
+ } finally {
+ Binder.restoreCallingIdentity(userIdentity);
+ }
+ }
+
+ /**
+ * Gets the navigation bar mode override. Returns default value if no override is set.
+ *
+ * @hide
+ */
+ public @NavBarModeOverride int getNavBarModeOverride() {
+ enforceStatusBar();
+
+ int navBarKidsMode = NAV_BAR_MODE_OVERRIDE_NONE;
+ final int userId = mCurrentUserId;
+ final long userIdentity = Binder.clearCallingIdentity();
+ try {
+ navBarKidsMode = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.NAV_BAR_KIDS_MODE, userId);
+ } catch (Settings.SettingNotFoundException ex) {
+ return navBarKidsMode;
+ } finally {
+ Binder.restoreCallingIdentity(userIdentity);
+ }
+ return navBarKidsMode;
+ }
+
/** @hide */
public void passThroughShellCommand(String[] args, FileDescriptor fd) {
enforceStatusBarOrShell();
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 39d7a15..7697490 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -177,7 +177,7 @@
}
}
}
- }, intentFilter);
+ }, intentFilter, Context.RECEIVER_NOT_EXPORTED);
}
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 721907c..3d37278 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -799,6 +799,22 @@
}
/**
+ * Returns {@code true} if a given {@link WindowContainer} is an embedded Task.
+ *
+ * Note that this is a short term workaround to support Android Auto until it migrate to
+ * ShellTransition. This should only be used by {@link #getAnimationTargets}.
+ *
+ * TODO(b/213312721): Remove this predicate and its callers once ShellTransition is enabled.
+ */
+ private static boolean isEmbeddedTask(WindowContainer wc) {
+ // We use Task#mRemoveWithTaskOrganizer to identify an embedded Task, but this is a hack and
+ // it is not guaranteed to work this logic in the future version.
+ return !WindowManagerService.sEnableShellTransitions
+ && wc instanceof Task
+ && ((Task) wc).mRemoveWithTaskOrganizer;
+ }
+
+ /**
* Find WindowContainers to be animated from a set of opening and closing apps. We will promote
* animation targets to higher level in the window hierarchy if possible.
*
@@ -844,7 +860,13 @@
siblings.add(current);
boolean canPromote = true;
- if (parent == null || !parent.canCreateRemoteAnimationTarget()
+ if (isEmbeddedTask(current)) {
+ // Don't animate an embedded Task in app transition. This is a short term workaround
+ // to prevent conflict of surface hierarchy changes between legacy app transition
+ // and TaskView (b/205189147).
+ // TODO(b/213312721): Remove this once ShellTransition is enabled.
+ continue;
+ } else if (parent == null || !parent.canCreateRemoteAnimationTarget()
|| !parent.canBeAnimationTarget()
// We cannot promote the animation on Task's parent when the task is in
// clearing task in case the animating get stuck when performing the opening
@@ -887,7 +909,13 @@
for (int j = 0; j < parent.getChildCount(); ++j) {
final WindowContainer sibling = parent.getChildAt(j);
if (candidates.remove(sibling)) {
- siblings.add(sibling);
+ if (!isEmbeddedTask(sibling)) {
+ // Don't animate an embedded Task in app transition. This is a short
+ // term workaround to prevent conflict of surface hierarchy changes
+ // between legacy app transition and TaskView (b/205189147).
+ // TODO(b/213312721): Remove this once ShellTransition is enabled.
+ siblings.add(sibling);
+ }
} else if (sibling != current && sibling.isVisible()) {
canPromote = false;
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index e33c440..1a1101e 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -187,7 +187,6 @@
// Navigation bar doesn't get influenced by anything else
if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
- state.removeSource(ITYPE_IME);
state.removeSource(ITYPE_STATUS_BAR);
state.removeSource(ITYPE_CLIMATE_BAR);
state.removeSource(ITYPE_CAPTION_BAR);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index fad87e8..659c771 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4994,8 +4994,7 @@
if (topFragment == f) {
return;
}
- if (!f.isFocusableAndVisible()) {
- // No need to resume activity in TaskFragment that is not visible.
+ if (!f.canBeResumed(null /* starting */)) {
return;
}
resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 796a90a..dfb559f 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -38,7 +38,6 @@
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
-import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -1407,9 +1406,7 @@
leafTask.forAllLeafTaskFragments((taskFrag) -> {
final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
- if (resumedActivity != null
- && (taskFrag.getVisibility(resuming) != TASK_FRAGMENT_VISIBILITY_VISIBLE
- || !taskFrag.isTopActivityFocusable())) {
+ if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
someActivityPaused[0]++;
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 97cb512..8299cea 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1355,6 +1355,17 @@
return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
}
+ /**
+ * Returns {@code true} is the activity in this TaskFragment can be resumed.
+ *
+ * @param starting The currently starting activity or {@code null} if there is none.
+ */
+ boolean canBeResumed(@Nullable ActivityRecord starting) {
+ // No need to resume activity in TaskFragment that is not visible.
+ return isTopActivityFocusable()
+ && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
+ }
+
boolean isFocusableAndVisible() {
return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 863e3ca..573ff2f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2547,7 +2547,8 @@
if (DEBUG_INPUT_METHOD) {
Slog.i(TAG_WM, "isVisibleRequestedOrAdding " + this + ": "
- + isVisibleRequestedOrAdding());
+ + isVisibleRequestedOrAdding() + " isVisible: " + (isVisible()
+ && mActivityRecord != null && mActivityRecord.isVisible()));
if (!isVisibleRequestedOrAdding()) {
Slog.i(TAG_WM, " mSurfaceController=" + mWinAnimator.mSurfaceController
+ " relayoutCalled=" + mRelayoutCalled
@@ -2562,7 +2563,8 @@
}
}
}
- return isVisibleRequestedOrAdding();
+ return isVisibleRequestedOrAdding()
+ || (isVisible() && mActivityRecord != null && mActivityRecord.isVisible());
}
private final class DeadWindowEventReceiver extends InputEventReceiver {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 6aa6323..3cd4e5e 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1595,7 +1595,7 @@
if (!inputChannel.ok()) {
std::string message = inputChannel.error().message();
- message += StringPrintf(" Status=%d", inputChannel.error().code());
+ message += StringPrintf(" Status=%d", static_cast<int>(inputChannel.error().code()));
jniThrowRuntimeException(env, message.c_str());
return nullptr;
}
@@ -1629,7 +1629,7 @@
if (!inputChannel.ok()) {
std::string message = inputChannel.error().message();
- message += StringPrintf(" Status=%d", inputChannel.error().code());
+ message += StringPrintf(" Status=%d", static_cast<int>(inputChannel.error().code()));
jniThrowRuntimeException(env, message.c_str());
return nullptr;
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index f66f119..be656e3 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -232,6 +232,11 @@
namespace {
// Returns true if location has lat/long information.
+bool hasLatLong(const GnssLocationAidl& location) {
+ return (location.gnssLocationFlags & GnssLocationAidl::HAS_LAT_LONG) != 0;
+}
+
+// Returns true if location has lat/long information.
bool hasLatLong(const GnssLocation_V1_0& location) {
return (static_cast<uint32_t>(location.gnssLocationFlags) &
GnssLocationFlags::HAS_LAT_LONG) != 0;
@@ -248,6 +253,36 @@
return value ? JNI_TRUE : JNI_FALSE;
}
+static GnssLocationAidl createGnssLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters,
+ jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees, jlong timestamp,
+ jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ GnssLocationAidl location;
+ location.gnssLocationFlags = static_cast<int>(gnssLocationFlags);
+ location.latitudeDegrees = static_cast<double>(latitudeDegrees);
+ location.longitudeDegrees = static_cast<double>(longitudeDegrees);
+ location.altitudeMeters = static_cast<double>(altitudeMeters);
+ location.speedMetersPerSec = static_cast<double>(speedMetersPerSec);
+ location.bearingDegrees = static_cast<double>(bearingDegrees);
+ location.horizontalAccuracyMeters = static_cast<double>(horizontalAccuracyMeters);
+ location.verticalAccuracyMeters = static_cast<double>(verticalAccuracyMeters);
+ location.speedAccuracyMetersPerSecond = static_cast<double>(speedAccuracyMetersPerSecond);
+ location.bearingAccuracyDegrees = static_cast<double>(bearingAccuracyDegrees);
+ location.timestampMillis = static_cast<uint64_t>(timestamp);
+
+ location.elapsedRealtime.flags = static_cast<int>(elapsedRealtimeFlags);
+ location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
+ location.elapsedRealtime.timeUncertaintyNs =
+ static_cast<double>(elapsedRealtimeUncertaintyNanos);
+
+ return location;
+}
+
static GnssLocation_V1_0 createGnssLocation_V1_0(
jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
@@ -298,7 +333,8 @@
Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
Return<void> gnssStatusCb(const IGnssCallback_V1_0::GnssStatusValue status) override;
Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
- return gnssSvStatusCbImpl(svStatus);
+ return gnssSvStatusCbImpl<IGnssCallback_V1_0::GnssSvStatus, IGnssCallback_V1_0::GnssSvInfo>(
+ svStatus);
}
Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
@@ -318,73 +354,67 @@
Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) override {
- return gnssSvStatusCbImpl(svInfoList);
+ return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_0::GnssSvInfo>,
+ IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
}
// New in 2.1
Return<void> gnssSvStatusCb_2_1(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) override {
- return gnssSvStatusCbImpl(svInfoList);
+ return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_1::GnssSvInfo>,
+ IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
}
Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
// TODO: Reconsider allocation cost vs threadsafety on these statics
static const char* sNmeaString;
static size_t sNmeaStringLength;
+
+ template <class T>
+ static Return<void> gnssLocationCbImpl(const T& location);
+
+ template <class T_list, class T_sv_info>
+ static Return<void> gnssSvStatusCbImpl(const T_list& svStatus);
+
private:
- template<class T>
- Return<void> gnssLocationCbImpl(const T& location);
-
- template<class T>
- Return<void> gnssSvStatusCbImpl(const T& svStatus);
-
- template<class T>
- uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
+ template <class T>
+ static uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
return 0;
}
- template<class T>
- double getBasebandCn0DbHz(const T& svStatus, size_t i) {
+ template <class T>
+ static double getBasebandCn0DbHz(const T& svStatus, size_t i) {
return 0.0;
}
- uint32_t getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
- return svStatus.numSvs;
- }
-
- uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) {
+ template <class T>
+ static uint32_t getGnssSvInfoListSize(const T& svInfoList) {
return svInfoList.size();
}
- uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) {
- return svInfoList.size();
+ static const IGnssCallbackAidl::GnssSvInfo& getGnssSvInfoOfIndex(
+ const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i];
}
- const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+ static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
return svStatus.gnssSvList.data()[i];
}
- const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+ static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
return svInfoList[i].v1_0;
}
- const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+ static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
return svInfoList[i].v2_0.v1_0;
}
- uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
- return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
- }
-
- uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
+ template <class T>
+ static uint32_t getConstellationType(const T& svInfoList, size_t i) {
return static_cast<uint32_t>(svInfoList[i].constellation);
}
-
- uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
- return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
- }
};
Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
@@ -441,14 +471,43 @@
return SVID_FLAGS_HAS_BASEBAND_CN0;
}
+template <>
+uint32_t GnssCallback::getHasBasebandCn0DbHzFlag(
+ const std::vector<IGnssCallbackAidl::GnssSvInfo>& svStatus) {
+ return SVID_FLAGS_HAS_BASEBAND_CN0;
+}
+
+template <>
+double GnssCallback::getBasebandCn0DbHz(
+ const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i].basebandCN0DbHz;
+}
+
template<>
double GnssCallback::getBasebandCn0DbHz(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList,
size_t i) {
return svInfoList[i].basebandCN0DbHz;
}
-template<class T>
-Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
+template <>
+uint32_t GnssCallback::getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
+ return svStatus.numSvs;
+}
+
+template <>
+uint32_t GnssCallback::getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus,
+ size_t i) {
+ return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
+}
+
+template <>
+uint32_t GnssCallback::getConstellationType(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+ return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
+}
+
+template <class T_list, class T_sv_info>
+Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
JNIEnv* env = getJniEnv();
uint32_t listSize = getGnssSvInfoListSize(svStatus);
@@ -476,7 +535,7 @@
CONSTELLATION_TYPE_SHIFT_WIDTH = 8
};
- const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i);
+ const T_sv_info& info = getGnssSvInfoOfIndex(svStatus, i);
svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
(getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
static_cast<uint32_t>(info.svFlag);
@@ -586,6 +645,16 @@
class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
public:
Status gnssSetCapabilitiesCb(const int capabilities) override;
+ Status gnssStatusCb(const GnssStatusValue status) override;
+ Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
+ Status gnssLocationCb(const GnssLocationAidl& location) override;
+ Status gnssNmeaCb(const int64_t timestamp, const std::string& nmea) override;
+ Status gnssAcquireWakelockCb() override;
+ Status gnssReleaseWakelockCb() override;
+ Status gnssSetSystemInfoCb(const GnssSystemInfo& info) override;
+ Status gnssRequestTimeCb() override;
+ Status gnssRequestLocationCb(const bool independentFromGnss,
+ const bool isUserEmergency) override;
};
Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
@@ -596,6 +665,76 @@
return Status::ok();
}
+Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue status) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
+ GnssCallback::gnssSvStatusCbImpl<std::vector<GnssSvInfo>, GnssSvInfo>(svInfoList);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssLocationCb(const GnssLocationAidl& location) {
+ GnssCallback::gnssLocationCbImpl<GnssLocationAidl>(location);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+ JNIEnv* env = getJniEnv();
+ /*
+ * The Java code will call back to read these values.
+ * We do this to avoid creating unnecessary String objects.
+ */
+ GnssCallback::sNmeaString = nmea.c_str();
+ GnssCallback::sNmeaStringLength = nmea.size();
+
+ env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssAcquireWakelockCb() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssReleaseWakelockCb() {
+ release_wake_lock(WAKE_LOCK_NAME);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
+ ALOGD("%s: yearOfHw=%d, name=%s\n", __func__, info.yearOfHw, info.name.c_str());
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
+ jstring jstringName = env->NewStringUTF(info.name.c_str());
+ env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
+ if (jstringName) {
+ env->DeleteLocalRef(jstringName);
+ }
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestTimeCb() {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestLocationCb(const bool independentFromGnss,
+ const bool isUserEmergency) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
+ boolToJbool(isUserEmergency));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
/*
* GnssPowerIndicationCallback class implements the callback methods for the IGnssPowerIndication
* interface.
@@ -797,7 +936,10 @@
static void android_location_gnss_hal_GnssNative_set_gps_service_handle() {
gnssHalAidl = waitForVintfService<IGnssAidl>();
if (gnssHalAidl != nullptr) {
- ALOGD("Successfully got GNSS AIDL handle.");
+ ALOGD("Successfully got GNSS AIDL handle. Version=%d.", gnssHalAidl->getInterfaceVersion());
+ if (gnssHalAidl->getInterfaceVersion() >= 2) {
+ return;
+ }
}
ALOGD("Trying IGnss_V2_1::getService()");
@@ -952,15 +1094,17 @@
// TODO: linkToDeath for AIDL HAL
- gnssHalDeathRecipient = new GnssDeathRecipient();
- hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to GnssHAL death: %s",
- linked.description().c_str());
- } else if (!linked) {
- ALOGW("Unable to link to GnssHal death notifications");
- } else {
- ALOGD("Link to death notification successful");
+ if (gnssHal != nullptr) {
+ gnssHalDeathRecipient = new GnssDeathRecipient();
+ hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to GnssHAL death: %s",
+ linked.description().c_str());
+ } else if (!linked) {
+ ALOGW("Unable to link to GnssHal death notifications");
+ } else {
+ ALOGD("Link to death notification successful");
+ }
}
if (gnssHalAidl != nullptr) {
@@ -1163,7 +1307,7 @@
gnssConfigurationIface =
std::make_unique<gnss::GnssConfiguration_V1_1>(gnssConfiguration);
}
- } else {
+ } else if (gnssHal != nullptr) {
auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
if (checkHidlReturn(gnssConfiguration,
"Unable to get a handle to GnssConfiguration_V1_0")) {
@@ -1229,7 +1373,7 @@
}
static jboolean android_location_gnss_hal_GnssNative_is_supported(JNIEnv* /* env */, jclass) {
- return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssHalAidl != nullptr || gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
}
static jboolean android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported(
@@ -1263,26 +1407,26 @@
return JNI_FALSE;
}
- Return<bool> result = false;
-
// Set top level IGnss.hal callback.
- sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
- if (gnssHal_V2_1 != nullptr) {
- result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
- } else if (gnssHal_V2_0 != nullptr) {
- result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
- } else if (gnssHal_V1_1 != nullptr) {
- result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
- } else if (gnssHal != nullptr) {
- result = gnssHal->setCallback(gnssCbIface);
+ if (gnssHal != nullptr) {
+ Return<bool> result = false;
+ sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
+ if (gnssHal_V2_1 != nullptr) {
+ result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
+ } else if (gnssHal_V2_0 != nullptr) {
+ result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
+ } else if (gnssHal_V1_1 != nullptr) {
+ result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
+ } else {
+ result = gnssHal->setCallback(gnssCbIface);
+ }
+ if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
+ return JNI_FALSE;
+ }
}
- if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
- return JNI_FALSE;
- }
-
- sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
if (gnssHalAidl != nullptr) {
+ sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
auto status = gnssHalAidl->setCallback(gnssCbIfaceAidl);
if (!checkAidlStatus(status, "IGnssAidl setCallback() failed.")) {
return JNI_FALSE;
@@ -1298,7 +1442,7 @@
}
} else if (gnssXtraIface != nullptr) {
sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
- result = gnssXtraIface->setCallback(gnssXtraCbIface);
+ auto result = gnssXtraIface->setCallback(gnssXtraCbIface);
if (!checkHidlReturn(result, "IGnssXtra setCallback() failed.")) {
gnssXtraIface = nullptr;
} else {
@@ -1341,20 +1485,20 @@
if (gnssVisibilityControlIface != nullptr) {
sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
new GnssVisibilityControlCallback();
- result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
+ auto result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
checkHidlReturn(result, "IGnssVisibilityControl setCallback() failed.");
}
// Set IMeasurementCorrections.hal callback.
if (gnssCorrectionsIface_V1_1 != nullptr) {
- sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
- new MeasurementCorrectionsCallback();
- result = gnssCorrectionsIface_V1_1->setCallback(gnssCorrectionsIfaceCbIface);
- checkHidlReturn(result, "IMeasurementCorrections 1.1 setCallback() failed.");
+ sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
+ new MeasurementCorrectionsCallback();
+ auto result = gnssCorrectionsIface_V1_1->setCallback(gnssCorrectionsIfaceCbIface);
+ checkHidlReturn(result, "IMeasurementCorrections 1.1 setCallback() failed.");
} else if (gnssCorrectionsIface_V1_0 != nullptr) {
sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
new MeasurementCorrectionsCallback();
- result = gnssCorrectionsIface_V1_0->setCallback(gnssCorrectionsIfaceCbIface);
+ auto result = gnssCorrectionsIface_V1_0->setCallback(gnssCorrectionsIfaceCbIface);
checkHidlReturn(result, "IMeasurementCorrections 1.0 setCallback() failed.");
} else {
ALOGI("Unable to find IMeasurementCorrections.");
@@ -1388,6 +1532,15 @@
static jboolean android_location_gnss_hal_GnssNative_set_position_mode(
JNIEnv* /* env */, jclass, jint mode, jint recurrence, jint min_interval,
jint preferred_accuracy, jint preferred_time, jboolean low_power_mode) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->setPositionMode(static_cast<IGnssAidl::GnssPositionMode>(mode),
+ static_cast<IGnssAidl::GnssPositionRecurrence>(
+ recurrence),
+ min_interval, preferred_accuracy, preferred_time,
+ low_power_mode);
+ return checkAidlStatus(status, "IGnssAidl setPositionMode() failed.");
+ }
+
Return<bool> result = false;
if (gnssHal_V1_1 != nullptr) {
result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
@@ -1408,6 +1561,11 @@
}
static jboolean android_location_gnss_hal_GnssNative_start(JNIEnv* /* env */, jclass) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->start();
+ return checkAidlStatus(status, "IGnssAidl start() failed.");
+ }
+
if (gnssHal == nullptr) {
return JNI_FALSE;
}
@@ -1417,6 +1575,11 @@
}
static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jclass) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stop();
+ return checkAidlStatus(status, "IGnssAidl stop() failed.");
+ }
+
if (gnssHal == nullptr) {
return JNI_FALSE;
}
@@ -1427,6 +1590,12 @@
static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass,
jint flags) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->deleteAidingData(static_cast<IGnssAidl::GnssAidingData>(flags));
+ checkAidlStatus(status, "IGnssAidl deleteAidingData() failed.");
+ return;
+ }
+
if (gnssHal == nullptr) {
return;
}
@@ -1490,10 +1659,15 @@
static void android_location_gnss_hal_GnssNative_inject_time(JNIEnv* /* env */, jclass, jlong time,
jlong timeReference,
jint uncertainty) {
- if (gnssHal == nullptr) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->injectTime(time, timeReference, uncertainty);
+ checkAidlStatus(status, "IGnssAidl injectTime() failed.");
return;
}
+ if (gnssHal == nullptr) {
+ return;
+ }
auto result = gnssHal->injectTime(time, timeReference, uncertainty);
checkHidlReturn(result, "IGnss injectTime() failed.");
}
@@ -1505,6 +1679,19 @@
jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
jdouble elapsedRealtimeUncertaintyNanos) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ GnssLocationAidl location =
+ createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto status = gnssHalAidl->injectBestLocation(location);
+ checkAidlStatus(status, "IGnssAidl injectBestLocation() failed.");
+ return;
+ }
+
if (gnssHal_V2_0 != nullptr) {
GnssLocation_V2_0 location = createGnssLocation_V2_0(
gnssLocationFlags,
@@ -1546,15 +1733,31 @@
ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
}
-static void android_location_gnss_hal_GnssNative_inject_location(JNIEnv* /* env */, jclass,
- jdouble latitude,
- jdouble longitude,
- jfloat accuracy) {
- if (gnssHal == nullptr) {
+static void android_location_gnss_hal_GnssNative_inject_location(
+ JNIEnv* /* env */, jclass, jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters, jfloat speedMetersPerSec,
+ jfloat bearingDegrees, jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
+ jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ GnssLocationAidl location =
+ createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto status = gnssHalAidl->injectLocation(location);
+ checkAidlStatus(status, "IGnssAidl injectLocation() failed.");
return;
}
- auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
+ if (gnssHal == nullptr) {
+ return;
+ }
+ auto result =
+ gnssHal->injectLocation(latitudeDegrees, longitudeDegrees, horizontalAccuracyMeters);
checkHidlReturn(result, "IGnss injectLocation() failed.");
}
@@ -2207,7 +2410,7 @@
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_time)},
{"native_inject_best_location", "(IDDDFFFFFFJIJD)V",
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_best_location)},
- {"native_inject_location", "(DDF)V",
+ {"native_inject_location", "(IDDDFFFFFFJIJD)V",
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_location)},
{"native_supports_psds", "()Z",
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_supports_psds)},
diff --git a/services/core/jni/gnss/AGnss.cpp b/services/core/jni/gnss/AGnss.cpp
index 00403d6..091fffd 100644
--- a/services/core/jni/gnss/AGnss.cpp
+++ b/services/core/jni/gnss/AGnss.cpp
@@ -43,7 +43,7 @@
jboolean AGnss::dataConnOpen(JNIEnv* env, jlong networkHandle, jstring apn, jint apnIpType) {
ScopedJniString jniApn{env, apn};
- auto status = mIAGnss->dataConnOpen(networkHandle, String16(jniApn.c_str()),
+ auto status = mIAGnss->dataConnOpen(networkHandle, std::string(jniApn.c_str()),
static_cast<IAGnss::ApnIpType>(apnIpType));
return checkAidlStatus(status,
"IAGnssAidl dataConnOpen() failed. APN and its IP type not set.");
@@ -61,8 +61,8 @@
jboolean AGnss::setServer(JNIEnv* env, jint type, jstring hostname, jint port) {
ScopedJniString jniHostName{env, hostname};
- auto status =
- mIAGnss->setServer(static_cast<AGnssType>(type), String16(jniHostName.c_str()), port);
+ auto status = mIAGnss->setServer(static_cast<AGnssType>(type), std::string(jniHostName.c_str()),
+ port);
return checkAidlStatus(status, "IAGnssAidl setServer() failed. Host name and port not set.");
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java
index 7ebf014..c46884f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java
@@ -16,58 +16,28 @@
package com.android.server.communal;
-import static android.app.communal.CommunalManager.ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT;
-import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import static com.android.server.wm.ActivityInterceptorCallback.COMMUNAL_MODE_ORDERED_ID;
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.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import android.Manifest;
-import android.annotation.Nullable;
-import android.app.KeyguardManager;
import android.app.communal.ICommunalManager;
-import android.app.compat.CompatChanges;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.net.Uri;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
-import android.provider.Settings;
-import android.service.dreams.DreamManagerInternal;
-import android.test.mock.MockContentResolver;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-import com.android.server.wm.ActivityInterceptorCallback;
-import com.android.server.wm.ActivityTaskManagerInternal;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.quality.Strictness;
@@ -82,25 +52,9 @@
@SmallTest
@Presubmit
public class CommunalManagerServiceTest {
- private static final int TEST_USER_ID = 1;
- private static final int TEST_REAL_CALLING_UID = 2;
- private static final int TEST_REAL_CALLING_PID = 3;
- private static final String TEST_CALLING_PACKAGE = "com.test.caller";
- private static final String TEST_PACKAGE_NAME = "com.test.package";
-
private MockitoSession mMockingSession;
private CommunalManagerService mService;
- @Mock
- private ActivityTaskManagerInternal mAtmInternal;
- @Mock
- private KeyguardManager mKeyguardManager;
- @Mock
- private DreamManagerInternal mDreamManagerInternal;
-
- private ActivityInterceptorCallback mActivityInterceptorCallback;
- private BroadcastReceiver mPackageReceiver;
- private ActivityInfo mAInfo;
private ICommunalManager mBinder;
private ContextWrapper mContextSpy;
@@ -108,19 +62,10 @@
public final void setUp() {
mMockingSession = mockitoSession()
.initMocks(this)
- .spyStatic(CommunalManagerService.class)
- .mockStatic(CompatChanges.class)
.strictness(Strictness.WARN)
.startMocking();
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
- MockContentResolver cr = new MockContentResolver(mContextSpy);
- cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
- when(mContextSpy.getContentResolver()).thenReturn(cr);
-
- when(mContextSpy.getSystemService(KeyguardManager.class)).thenReturn(mKeyguardManager);
- addLocalServiceMock(ActivityTaskManagerInternal.class, mAtmInternal);
- addLocalServiceMock(DreamManagerInternal.class, mDreamManagerInternal);
doNothing().when(mContextSpy).enforceCallingPermission(
eq(Manifest.permission.WRITE_COMMUNAL_STATE), anyString());
@@ -128,83 +73,16 @@
eq(Manifest.permission.READ_COMMUNAL_STATE), anyString());
mService = new CommunalManagerService(mContextSpy);
- mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
-
- ArgumentCaptor<ActivityInterceptorCallback> activityInterceptorCaptor =
- ArgumentCaptor.forClass(ActivityInterceptorCallback.class);
- verify(mAtmInternal).registerActivityStartInterceptor(eq(COMMUNAL_MODE_ORDERED_ID),
- activityInterceptorCaptor.capture());
- mActivityInterceptorCallback = activityInterceptorCaptor.getValue();
-
- ArgumentCaptor<BroadcastReceiver> packageReceiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mContextSpy).registerReceiverAsUser(packageReceiverCaptor.capture(),
- eq(UserHandle.SYSTEM), any(), any(), any(), anyInt());
- mPackageReceiver = packageReceiverCaptor.getValue();
-
mBinder = mService.getBinderServiceInstance();
-
- mAInfo = new ActivityInfo();
- mAInfo.applicationInfo = new ApplicationInfo();
- mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
}
@After
public void tearDown() {
- FakeSettingsProvider.clearSettingsProvider();
if (mMockingSession != null) {
mMockingSession.finishMocking();
}
}
- /**
- * Creates a mock and registers it to {@link LocalServices}.
- */
- private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
- LocalServices.removeServiceForTest(clazz);
- LocalServices.addService(clazz, mock);
- }
-
- private ActivityInterceptorCallback.ActivityInterceptorInfo buildActivityInfo(Intent intent) {
- return new ActivityInterceptorCallback.ActivityInterceptorInfo(
- TEST_REAL_CALLING_UID,
- TEST_REAL_CALLING_PID,
- TEST_USER_ID,
- TEST_CALLING_PACKAGE,
- "featureId",
- intent,
- null,
- mAInfo,
- "resolvedType",
- TEST_REAL_CALLING_PID,
- TEST_REAL_CALLING_UID,
- null);
- }
-
- private void allowPackages(String packages) {
- Settings.Secure.putStringForUser(mContextSpy.getContentResolver(),
- Settings.Secure.COMMUNAL_MODE_PACKAGES, packages, UserHandle.USER_SYSTEM);
- }
-
- private String getAllowedPackages() {
- return Settings.Secure.getStringForUser(mContextSpy.getContentResolver(),
- Settings.Secure.COMMUNAL_MODE_PACKAGES, UserHandle.USER_SYSTEM);
- }
-
- private void assertDoesIntercept() {
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNotNull();
- }
-
- private void assertDoesNotIntercept() {
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- assertThat(mActivityInterceptorCallback.intercept(buildActivityInfo(intent))).isNull();
- }
-
- private Intent createPackageIntent(String packageName, @Nullable String action) {
- return new Intent(action, Uri.parse("package:" + packageName));
- }
-
@Test
public void testIsCommunalMode_isTrue() throws RemoteException {
mBinder.setCommunalViewShowing(true);
@@ -216,149 +94,4 @@
mBinder.setCommunalViewShowing(false);
assertThat(mBinder.isCommunalMode()).isFalse();
}
-
- @Test
- public void testIntercept_unlocked_communalOff_appNotEnabled_showWhenLockedOff() {
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
- mAInfo.flags = 0;
- assertDoesNotIntercept();
- }
-
- @Test
- public void testIntercept_unlocked_communalOn_appNotEnabled_showWhenLockedOff()
- throws RemoteException {
- mBinder.setCommunalViewShowing(true);
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(false);
- mAInfo.flags = 0;
- assertDoesNotIntercept();
- }
-
- @Test
- public void testIntercept_locked_communalOff_appNotEnabled_showWhenLockedOff() {
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- mAInfo.flags = 0;
- assertDoesNotIntercept();
- }
-
- @Test
- public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOff_allowlistEnabled()
- throws RemoteException {
- mBinder.setCommunalViewShowing(true);
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
- UserHandle.SYSTEM)).thenReturn(true);
- mAInfo.flags = 0;
- assertDoesIntercept();
- }
-
- @Test
- public void testIntercept_locked_communalOn_appNotEnabled_showWhenLockedOn_allowlistEnabled()
- throws RemoteException {
- mBinder.setCommunalViewShowing(true);
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
- UserHandle.SYSTEM)).thenReturn(true);
- mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
-
- allowPackages("package1,package2");
- assertDoesIntercept();
- }
-
- @Test
- public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOff_allowlistEnabled()
- throws RemoteException {
- mBinder.setCommunalViewShowing(true);
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
- UserHandle.SYSTEM)).thenReturn(true);
- mAInfo.flags = 0;
-
- allowPackages(TEST_PACKAGE_NAME);
- assertDoesIntercept();
- }
-
- @Test
- public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistEnabled()
- throws RemoteException {
- mBinder.setCommunalViewShowing(true);
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
- UserHandle.SYSTEM)).thenReturn(true);
-
- mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
-
- allowPackages(TEST_PACKAGE_NAME);
- assertDoesNotIntercept();
- }
-
- @Test
- public void testIntercept_locked_communalOn_appEnabled_showWhenLockedOn_allowlistDisabled()
- throws RemoteException {
- mBinder.setCommunalViewShowing(true);
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- when(CompatChanges.isChangeEnabled(ALLOW_COMMUNAL_MODE_WITH_USER_CONSENT, TEST_PACKAGE_NAME,
- UserHandle.SYSTEM)).thenReturn(false);
-
- mAInfo.flags = FLAG_SHOW_WHEN_LOCKED;
-
- allowPackages(TEST_PACKAGE_NAME);
- assertDoesIntercept();
- }
-
- @Test
- public void testIntercept_locked_communalOn_dream() throws RemoteException {
- mBinder.setCommunalViewShowing(true);
- when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
- when(mDreamManagerInternal.getActiveDreamComponent(false)).thenReturn(
- new ComponentName(TEST_PACKAGE_NAME, "SomeClass"));
-
- allowPackages(TEST_PACKAGE_NAME);
- assertDoesNotIntercept();
- }
-
- @Test
- public void testUpdateSettings_packageUninstalled() {
- allowPackages("package1,package2");
- assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
- mPackageReceiver.onReceive(mContextSpy,
- createPackageIntent("package1", ACTION_PACKAGE_REMOVED));
-
- assertThat(getAllowedPackages()).isEqualTo("package2");
- }
-
- @Test
- public void testUpdateSettings_nullAction_doesNothing() {
- allowPackages("package1,package2");
- assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
- mPackageReceiver.onReceive(mContextSpy,
- createPackageIntent("package1", null));
-
- assertThat(getAllowedPackages()).isEqualTo("package1,package2");
- }
-
- @Test
- public void testUpdateSettings_invalidPackage_doesNothing() {
- allowPackages("package1,package2");
- assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
- mPackageReceiver.onReceive(mContextSpy,
- createPackageIntent("package3", ACTION_PACKAGE_REMOVED));
-
- assertThat(getAllowedPackages()).isEqualTo("package1,package2");
- }
-
- @Test
- public void testUpdateSettings_onBoot() {
- allowPackages("package1,package2");
- assertThat(getAllowedPackages()).isEqualTo("package1,package2");
-
- when(CommunalManagerService.isPackageInstalled(eq("package1"), any())).thenReturn(true);
- when(CommunalManagerService.isPackageInstalled(eq("package2"), any())).thenReturn(false);
-
- mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
-
- assertThat(getAllowedPackages()).isEqualTo("package1");
- }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
index 16ffda8..93a2d31 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
@@ -429,11 +429,15 @@
}
@Override
- protected void injectLocation(double latitude, double longitude, float accuracy) {
+ protected void injectLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
+ double longitude, double altitude, float speed, float bearing, float horizontalAccuracy,
+ float verticalAccuracy, float speedAccuracy, float bearingAccuracy, long timestamp,
+ @GnssRealtimeFlags int elapsedRealtimeFlags, long elapsedRealtimeNanos,
+ double elapsedRealtimeUncertaintyNanos) {
mState.mInjectedLocation = new Location("injected");
mState.mInjectedLocation.setLatitude(latitude);
mState.mInjectedLocation.setLongitude(longitude);
- mState.mInjectedLocation.setAccuracy(accuracy);
+ mState.mInjectedLocation.setAccuracy(horizontalAccuracy);
}
@Override
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index e756124..202a54d 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -57,6 +57,7 @@
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
<uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+ <uses-permission android:name="android.permission.STATUS_BAR"/>
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE"/>
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/>
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
index d5a28f6..d2ea9c4 100644
--- a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -15,7 +15,7 @@
*/
package com.android.server.autofill;
-import static com.android.server.autofill.AutofillManagerService.getWhitelistedCompatModePackages;
+import static com.android.server.autofill.AutofillManagerService.getAllowedCompatModePackages;
import static com.google.common.truth.Truth.assertThat;
@@ -29,54 +29,54 @@
public class AutofillManagerServiceTest {
@Test
- public void testGetWhitelistedCompatModePackages_null() {
- assertThat(getWhitelistedCompatModePackages(null)).isNull();
+ public void testGetAllowedCompatModePackages_null() {
+ assertThat(getAllowedCompatModePackages(null)).isNull();
}
@Test
- public void testGetWhitelistedCompatModePackages_empty() {
- assertThat(getWhitelistedCompatModePackages("")).isNull();
+ public void testGetAllowedCompatModePackages_empty() {
+ assertThat(getAllowedCompatModePackages("")).isNull();
}
@Test
- public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
- assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
+ public void testGetAllowedCompatModePackages_onePackageNoUrls() {
+ assertThat(getAllowedCompatModePackages("one_is_the_loniest_package"))
.containsExactly("one_is_the_loniest_package", null);
}
@Test
- public void testGetWhitelistedCompatModePackages_onePackageMissingEndDelimiter() {
- assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package[")).isEmpty();
+ public void testGetAllowedCompatModePackages_onePackageMissingEndDelimiter() {
+ assertThat(getAllowedCompatModePackages("one_is_the_loniest_package[")).isEmpty();
}
@Test
- public void testGetWhitelistedCompatModePackages_onePackageOneUrl() {
+ public void testGetAllowedCompatModePackages_onePackageOneUrl() {
final Map<String, String[]> result =
- getWhitelistedCompatModePackages("one_is_the_loniest_package[url]");
+ getAllowedCompatModePackages("one_is_the_loniest_package[url]");
assertThat(result).hasSize(1);
assertThat(result.get("one_is_the_loniest_package")).asList().containsExactly("url");
}
@Test
- public void testGetWhitelistedCompatModePackages_onePackageMultipleUrls() {
+ public void testGetAllowedCompatModePackages_onePackageMultipleUrls() {
final Map<String, String[]> result =
- getWhitelistedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]");
+ getAllowedCompatModePackages("one_is_the_loniest_package[4,5,8,15,16,23,42]");
assertThat(result).hasSize(1);
assertThat(result.get("one_is_the_loniest_package")).asList()
.containsExactly("4", "5", "8", "15", "16", "23", "42");
}
@Test
- public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
- final Map<String, String[]> result = getWhitelistedCompatModePackages("one:two[");
+ public void testGetAllowedCompatModePackages_multiplePackagesOneInvalid() {
+ final Map<String, String[]> result = getAllowedCompatModePackages("one:two[");
assertThat(result).hasSize(1);
assertThat(result.get("one")).isNull();
}
@Test
- public void testGetWhitelistedCompatModePackages_multiplePackagesMultipleUrls() {
+ public void testGetAllowedCompatModePackages_multiplePackagesMultipleUrls() {
final Map<String, String[]> result =
- getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
+ getAllowedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
assertThat(result).hasSize(3);
assertThat(result.get("p1")).asList().containsExactly("p1u1");
assertThat(result.get("p2")).isNull();
@@ -84,9 +84,9 @@
}
@Test
- public void testGetWhitelistedCompatModePackages_threePackagesOneInvalid() {
+ public void testGetAllowedCompatModePackages_threePackagesOneInvalid() {
final Map<String, String[]> result =
- getWhitelistedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]");
+ getAllowedCompatModePackages("p1[p1u1]:p2[:p3[p3u1,p3u2]");
assertThat(result).hasSize(2);
assertThat(result.get("p1")).asList().containsExactly("p1u1");
assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
index 0708be2..78bcf0c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java
@@ -147,6 +147,11 @@
// Verifies pushDynamicShortcuts further persists shortcuts into AppSearch without
// removing previous shortcuts when max number of shortcuts is reached.
mManager.pushDynamicShortcut(makeShortcut("s6"));
+ // Increasing the max number of shortcuts since number of results per page in AppSearch
+ // is set to match the former.
+ mService.updateConfigurationLocked(
+ ShortcutService.ConfigConstants.KEY_MAX_SHORTCUTS + "=10,"
+ + ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");
shortcuts = getAllPersistedShortcuts();
assertNotNull(shortcuts);
assertEquals(6, shortcuts.size());
@@ -281,7 +286,7 @@
private List<ShortcutInfo> getAllPersistedShortcuts() {
try {
- SystemClock.sleep(500);
+ SystemClock.sleep(5000);
final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>();
getPersistedShortcut(future);
return future.get(10, TimeUnit.SECONDS);
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index c293b5e..d164d2a 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
@@ -575,6 +576,30 @@
}
}
+ @Test
+ public void testSetNavBarModeOverride_setsOverrideModeKids() {
+ int navBarModeOverrideKids = StatusBarManager.NAV_BAR_MODE_OVERRIDE_KIDS;
+ mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideKids);
+
+ assertEquals(navBarModeOverrideKids, mStatusBarManagerService.getNavBarModeOverride());
+ }
+
+ @Test
+ public void testSetNavBarModeOverride_setsOverrideModeNone() {
+ int navBarModeOverrideNone = StatusBarManager.NAV_BAR_MODE_OVERRIDE_NONE;
+ mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideNone);
+
+ assertEquals(navBarModeOverrideNone, mStatusBarManagerService.getNavBarModeOverride());
+ }
+
+ @Test
+ public void testSetNavBarModeOverride_invalidInputThrowsError() {
+ int navBarModeOverrideInvalid = -1;
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> mStatusBarManagerService.setNavBarModeOverride(navBarModeOverrideInvalid));
+ }
+
private void mockUidCheck() {
mockUidCheck(TEST_PACKAGE);
}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index add4cda..eeaf781 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -357,13 +357,13 @@
/**
* Tests that readPermissions works correctly for a library using the new
- * {@code updatable-library} tag.
+ * {@code apex-library} tag.
*/
@Test
public void readPermissions_allowLibs_parsesUpdatableLibrary() throws IOException {
String contents =
"<permissions>\n"
- + " <updatable-library \n"
+ + " <apex-library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
+ " on-bootclasspath-before=\"10\"\n"
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 5062706..0d67946 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -678,6 +678,66 @@
opening, closing, false /* visible */));
}
+ @Test
+ public void testGetAnimationTargets_embeddedTask() {
+ // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, invisible)
+ // +- [Task2] (embedded) - [ActivityRecord2] (opening, invisible)
+ final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
+ activity1.setVisible(false);
+ activity1.mVisibleRequested = true;
+
+ final Task task2 = createTask(mDisplayContent);
+ task2.mRemoveWithTaskOrganizer = true;
+ final ActivityRecord activity2 = createActivityRecord(task2);
+ activity2.setVisible(false);
+ activity2.mVisibleRequested = true;
+
+ final ArraySet<ActivityRecord> opening = new ArraySet<>();
+ opening.add(activity1);
+ opening.add(activity2);
+ final ArraySet<ActivityRecord> closing = new ArraySet<>();
+
+ // No animation on the embedded task.
+ assertEquals(
+ new ArraySet<>(new WindowContainer[]{activity1.getTask()}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, true /* visible */));
+ assertEquals(
+ new ArraySet<>(),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, false /* visible */));
+ }
+
+
+ @Test
+ public void testGetAnimationTargets_activityInEmbeddedTask() {
+ // [DisplayContent] - [Task] (embedded)-+- [ActivityRecord1] (opening, invisible)
+ // +- [ActivityRecord2] (closing, visible)
+ final Task task = createTask(mDisplayContent);
+ task.mRemoveWithTaskOrganizer = true;
+
+ final ActivityRecord activity1 = createActivityRecord(task);
+ activity1.setVisible(false);
+ activity1.mVisibleRequested = true;
+ final ActivityRecord activity2 = createActivityRecord(task);
+
+ final ArraySet<ActivityRecord> opening = new ArraySet<>();
+ opening.add(activity1);
+ final ArraySet<ActivityRecord> closing = new ArraySet<>();
+ closing.add(activity2);
+
+ // Even though embedded task itself doesn't animate, activities in an embedded task
+ // animate.
+ assertEquals(
+ new ArraySet<>(new WindowContainer[]{activity1}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, true /* visible */));
+ assertEquals(
+ new ArraySet<>(new WindowContainer[]{activity2}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, false /* visible */));
+ }
+
static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
@Override
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 0a8b2e7..fe41734 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -44,6 +44,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.google.common.truth.Truth.assertThat;
@@ -66,6 +67,7 @@
import static org.mockito.Mockito.never;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.ComponentName;
@@ -1424,6 +1426,29 @@
verify(task2).moveToFrontInner(anyString(), isNull());
}
+ @Test
+ public void testResumeTask_doNotResumeTaskFragmentBehindTranslucent() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment tfBehind = createTaskFragmentWithParentTask(
+ task, false /* createEmbeddedTask */);
+ final TaskFragment tfFront = createTaskFragmentWithParentTask(
+ task, false /* createEmbeddedTask */);
+ spyOn(tfFront);
+ doReturn(true).when(tfFront).isTranslucent(any());
+
+ // TaskFragment behind another translucent TaskFragment should not be resumed.
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ tfBehind.getVisibility(null /* starting */));
+ assertTrue(tfBehind.isFocusable());
+ assertFalse(tfBehind.canBeResumed(null /* starting */));
+
+ spyOn(tfBehind);
+ task.resumeTopActivityUncheckedLocked(null /* prev */, ActivityOptions.makeBasic(),
+ false /* deferPause */);
+
+ verify(tfBehind, never()).resumeTopActivity(any(), any(), anyBoolean());
+ }
+
private Task getTestTask() {
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
return task.getBottomMostTask();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index ca2b4ae..ec8ec2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -252,6 +252,11 @@
assertFalse(appWindow.canBeImeTarget());
appWindow.mActivityRecord.setWindowingMode(initialMode);
+ // Verify that app window can still be IME target as long as it is visible (even if
+ // it is going to become invisible).
+ appWindow.mActivityRecord.mVisibleRequested = false;
+ assertTrue(appWindow.canBeImeTarget());
+
// Make windows invisible
appWindow.hide(false /* doAnimation */, false /* requestAnim */);
imeWindow.hide(false /* doAnimation */, false /* requestAnim */);
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index fabe612..184e154 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
@@ -261,6 +262,14 @@
public static final String EXTRA_RESOLUTION_PORT_INDEX =
"android.service.euicc.extra.RESOLUTION_PORT_INDEX";
+ /**
+ * Intent extra set for resolution requests containing a bool indicating whether to use the
+ * given port index. For example, if {@link #switchToSubscription(int, PendingIntent)} is
+ * called, then no portIndex has been provided by the caller, and this extra will be false.
+ */
+ public static final String EXTRA_RESOLUTION_USE_PORT_INDEX =
+ "android.service.euicc.extra.RESOLUTION_USE_PORT_INDEX";
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "RESULT_" }, value = {
@@ -852,14 +861,19 @@
}
@Override
public void switchToSubscription(int slotId, int portIndex, String iccid,
- boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback) {
+ boolean forceDeactivateSim, ISwitchToSubscriptionCallback callback,
+ boolean usePortIndex) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
- // TODO(b/207392528: use portIndex API once implemented)
- int result =
- EuiccService.this.onSwitchToSubscription(
- slotId, iccid, forceDeactivateSim);
+ int result = 0;
+ if (usePortIndex) {
+ result = EuiccService.this.onSwitchToSubscriptionWithPort(
+ slotId, portIndex, iccid, forceDeactivateSim);
+ } else {
+ result = EuiccService.this.onSwitchToSubscription(
+ slotId, iccid, forceDeactivateSim);
+ }
try {
callback.onComplete(result);
} catch (RemoteException e) {
diff --git a/telephony/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl
index aa30c9e..030e11a 100644
--- a/telephony/java/android/service/euicc/IEuiccService.aidl
+++ b/telephony/java/android/service/euicc/IEuiccService.aidl
@@ -49,7 +49,7 @@
void getEuiccInfo(int slotId, in IGetEuiccInfoCallback callback);
void deleteSubscription(int slotId, String iccid, in IDeleteSubscriptionCallback callback);
void switchToSubscription(int slotId, int portIndex, String iccid, boolean forceDeactivateSim,
- in ISwitchToSubscriptionCallback callback);
+ in ISwitchToSubscriptionCallback callback, boolean useLegacyApi);
void updateSubscriptionNickname(int slotId, String iccid, String nickname,
in IUpdateSubscriptionNicknameCallback callback);
void eraseSubscriptions(int slotId, in IEraseSubscriptionsCallback callback);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 82113f2..cd399c0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -798,6 +798,14 @@
"carrier_cross_sim_ims_available_bool";
/**
+ * Flag specifying whether cross sim calling on opportunistic data is supported for carrier.
+ * When {@code false} the carrier does not support cross sim calling on opportunistic data.
+ * When {@code true} the carrier does support cross sim calling on opportunistic data.
+ */
+ public static final String KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL =
+ "enable_cross_sim_calling_on_opportunistic_data_bool";
+
+ /**
* Specifies a map from dialstrings to replacements for roaming network service numbers which
* cannot be replaced on the carrier side.
* <p>
@@ -5587,6 +5595,7 @@
sDefaults.putBoolean(KEY_VILTE_DATA_IS_METERED_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL, false);
+ sDefaults.putBoolean(KEY_ENABLE_CROSS_SIM_CALLING_ON_OPPORTUNISTIC_DATA_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL, false);
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 389cc6d..2e5402c5 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -16,7 +16,6 @@
package android.telephony.euicc;
import android.Manifest;
-import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,7 +29,6 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
-import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.telephony.TelephonyFrameworkInitializer;
@@ -38,13 +36,11 @@
import android.telephony.euicc.EuiccCardManager.ResetOption;
import com.android.internal.telephony.euicc.IEuiccController;
-import com.android.internal.telephony.euicc.IResultCallback;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.Executor;
import java.util.stream.Collectors;
/**
@@ -221,20 +217,6 @@
"android.telephony.euicc.action.START_EUICC_ACTIVATION";
/**
- * Result codes passed to the ResultListener by
- * {@link #switchToSubscription(int, int, Executor, ResultListener)}
- *
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"EMBEDDED_SUBSCRIPTION_RESULT_"}, value = {
- EMBEDDED_SUBSCRIPTION_RESULT_OK,
- EMBEDDED_SUBSCRIPTION_RESULT_ERROR,
- EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
- })
- public @interface ResultCode{}
-
- /**
* Result code for an operation indicating that the operation succeeded.
*/
public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0;
@@ -1147,7 +1129,7 @@
* @param callbackIntent a PendingIntent to launch when the operation completes.
*
* @deprecated From T, callers should use
- * {@link #switchToSubscription(int, int, Executor, ResultListener)} instead to specify a port
+ * {@link #switchToSubscription(int, int, PendingIntent)} instead to specify a port
* index on the card to switch to.
*/
@Deprecated
@@ -1190,47 +1172,24 @@
* permission, or the calling app must be authorized to manage the active subscription on
* the target eUICC.
* @param portIndex the index of the port to target for the enabled subscription
- * @param executor an Executor on which to run the callback
- * @param callback a {@link ResultListener} which will run when the operation completes
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subscriptionId, int portIndex,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull ResultListener callback) {
+ @NonNull PendingIntent callbackIntent) {
if (!isEnabled()) {
- sendUnavailableErrorToCallback(executor, callback);
+ sendUnavailableError(callbackIntent);
return;
}
try {
- IResultCallback internalCallback = new IResultCallback.Stub() {
- @Override
- public void onComplete(int result, Intent resultIntent) {
- executor.execute(() -> Binder.withCleanCallingIdentity(
- () -> callback.onComplete(result, resultIntent)));
- }
- };
- getIEuiccController().switchToSubscriptionWithPort(mCardId, portIndex,
- subscriptionId, mContext.getOpPackageName(), internalCallback);
+ getIEuiccController().switchToSubscriptionWithPort(mCardId,
+ subscriptionId, portIndex, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Callback to receive the result of an EuiccManager API.
- */
- public interface ResultListener {
- /**
- * Called on completion of some operation.
- * @param resultCode representing success or specific failure of the operation
- * (See {@link ResultCode})
- * @param resultIntent an intent used to start a resolution activity when an error
- * occurs that can be resolved by the user
- */
- void onComplete(@ResultCode int resultCode, @Nullable Intent resultIntent);
- }
-
- /**
* Update the nickname for the given subscription.
*
* <p>Requires that the calling app has carrier privileges according to the metadata of the
@@ -1501,13 +1460,6 @@
}
}
- private static void sendUnavailableErrorToCallback(@NonNull Executor executor,
- ResultListener callback) {
- Integer result = EMBEDDED_SUBSCRIPTION_RESULT_ERROR;
- executor.execute(() ->
- Binder.withCleanCallingIdentity(() -> callback.onComplete(result, null)));
- }
-
private static IEuiccController getIEuiccController() {
return IEuiccController.Stub.asInterface(
TelephonyFrameworkInitializer
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 7f5982f..dda95b1 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -22,8 +22,6 @@
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccInfo;
-import com.android.internal.telephony.euicc.IResultCallback;
-
import java.util.List;
/** @hide */
@@ -45,8 +43,8 @@
in PendingIntent callbackIntent);
oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
in PendingIntent callbackIntent);
- oneway void switchToSubscriptionWithPort(int cardId, int portIndex, int subscriptionId,
- String callingPackage, in IResultCallback callback);
+ oneway void switchToSubscriptionWithPort(int cardId, int subscriptionId, int portIndex,
+ String callingPackage, in PendingIntent callbackIntent);
oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
String callingPackage, in PendingIntent callbackIntent);
oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index 68e213b..fe2b018 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -13,15 +13,18 @@
EMOJI_VS = 0xFE0F
LANG_TO_SCRIPT = {
+ 'af': 'Latn',
'as': 'Beng',
'am': 'Latn',
'be': 'Cyrl',
'bg': 'Cyrl',
'bn': 'Beng',
+ 'cs': 'Latn',
'cu': 'Cyrl',
'cy': 'Latn',
'da': 'Latn',
'de': 'Latn',
+ 'el': 'Latn',
'en': 'Latn',
'es': 'Latn',
'et': 'Latn',
@@ -36,19 +39,24 @@
'hy': 'Armn',
'it': 'Latn',
'ja': 'Jpan',
+ 'ka': 'Latn',
'kn': 'Knda',
'ko': 'Kore',
'la': 'Latn',
'lt': 'Latn',
+ 'lv': 'Latn',
'ml': 'Mlym',
'mn': 'Cyrl',
'mr': 'Deva',
'nb': 'Latn',
+ 'nl': 'Latn',
'nn': 'Latn',
'or': 'Orya',
'pa': 'Guru',
'pt': 'Latn',
+ 'sk': 'Latn',
'sl': 'Latn',
+ 'sq': 'Latn',
'ta': 'Taml',
'te': 'Telu',
'tk': 'Latn',