diff options
390 files changed, 7911 insertions, 1914 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 591e8ba859fc..4becc6b7c44a 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -1008,13 +1008,21 @@ public class JobSchedulerService extends com.android.server.SystemService } @Override - public void onUserUnlocked(@NonNull TargetUser user) { + public void onUserStarting(@NonNull TargetUser user) { synchronized (mLock) { - // Note that the user has started after its unlocked instead of when the user - // actually starts because the storage won't be decrypted until unlock. mStartedUsers = ArrayUtils.appendInt(mStartedUsers, user.getUserIdentifier()); } - // Let's kick any outstanding jobs for this user. + // The user is starting but credential encrypted storage is still locked. + // Only direct-boot-aware jobs can safely run. + // Let's kick off any eligible jobs for this user. + mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); + } + + @Override + public void onUserUnlocked(@NonNull TargetUser user) { + // The user is fully unlocked and credential encrypted storage is now decrypted. + // Direct-boot-UNaware jobs can now safely run. + // Let's kick off any outstanding jobs for this user. mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget(); } diff --git a/core/api/current.txt b/core/api/current.txt index 9a16390baf10..1d03370e698d 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -1298,7 +1298,7 @@ package android { field public static final int shortcutLongLabel = 16844074; // 0x101052a field public static final int shortcutShortLabel = 16844073; // 0x1010529 field public static final int shouldDisableView = 16843246; // 0x10101ee - field public static final int shouldUseDefaultDeviceStateChangeTransition; + field public static final int shouldUseDefaultDisplayStateChangeTransition; field public static final int showAsAction = 16843481; // 0x10102d9 field public static final int showDefault = 16843258; // 0x10101fa field public static final int showDividers = 16843561; // 0x1010329 @@ -6927,7 +6927,7 @@ package android.app { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager); - method public boolean shouldUseDefaultDeviceStateChangeTransition(); + method public boolean shouldUseDefaultDisplayStateChangeTransition(); method public boolean supportsMultipleDisplays(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR; diff --git a/core/api/test-current.txt b/core/api/test-current.txt index d484100373af..887f7617a17f 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -448,6 +448,7 @@ package android.app.admin { method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public void resetDefaultCrossProfileIntentFilters(int); method @RequiresPermission(allOf={"android.permission.MANAGE_DEVICE_ADMINS", android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void setActiveAdmin(@NonNull android.content.ComponentName, boolean, int); method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public boolean setDeviceOwner(@NonNull android.content.ComponentName, @Nullable String, int); + method @RequiresPermission("android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS") public boolean setDeviceOwnerOnly(@NonNull android.content.ComponentName, @Nullable String, int); method @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public void setNextOperationSafety(int, int); field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED"; field public static final String ACTION_DEVICE_POLICY_CONSTANTS_CHANGED = "android.app.action.DEVICE_POLICY_CONSTANTS_CHANGED"; diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 12025f98ada8..22091fcde86f 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2507,12 +2507,11 @@ public class Activity extends ContextThemeWrapper * * <p>To get the voice interactor you need to call {@link #getVoiceInteractor()} * which would return non <code>null</code> only if there is an ongoing voice - * interaction session. You an also detect when the voice interactor is no + * interaction session. You can also detect when the voice interactor is no * longer valid because the voice interaction session that is backing is finished * by calling {@link VoiceInteractor#registerOnDestroyedCallback(Executor, Runnable)}. * - * <p>This method will be called only after {@link #onStart()} is being called and - * before {@link #onStop()} is being called. + * <p>This method will be called only after {@link #onStart()} and before {@link #onStop()}. * * <p>You should pass to the callback the currently supported direct actions which * cannot be <code>null</code> or contain <code>null</code> elements. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 80554d7939f2..d0680f8c9268 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -526,9 +526,6 @@ public final class ActivityThread extends ClientTransactionHandler // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be // used without security checks public IBinder shareableActivityToken; - // The token of the initial TaskFragment that embedded this activity. Do not rely on it - // after creation because the activity could be reparented. - @Nullable public IBinder mInitialTaskFragmentToken; int ident; @UnsupportedAppUsage Intent intent; @@ -622,8 +619,7 @@ public final class ActivityThread extends ClientTransactionHandler List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client, IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments, - IBinder shareableActivityToken, boolean launchedFromBubble, - IBinder initialTaskFragmentToken) { + IBinder shareableActivityToken, boolean launchedFromBubble) { this.token = token; this.assistToken = assistToken; this.shareableActivityToken = shareableActivityToken; @@ -645,7 +641,6 @@ public final class ActivityThread extends ClientTransactionHandler mActivityOptions = activityOptions; mPendingFixedRotationAdjustments = fixedRotationAdjustments; mLaunchedFromBubble = launchedFromBubble; - mInitialTaskFragmentToken = initialTaskFragmentToken; init(); } diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 4b87a647a80b..f5b3b40d88d6 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -871,6 +871,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { if (view.isAttachedToWindow()) { tempMatrix.reset(); mSharedElementParentMatrices.get(i).invert(tempMatrix); + decor.transformMatrixToLocal(tempMatrix); GhostView.addGhost(view, decor, tempMatrix); ViewGroup parent = (ViewGroup) view.getParent(); if (moveWithParent && !isInTransitionGroup(parent, decor)) { diff --git a/core/java/android/app/DirectAction.java b/core/java/android/app/DirectAction.java index b0ed490369ad..ac3868b2ece9 100644 --- a/core/java/android/app/DirectAction.java +++ b/core/java/android/app/DirectAction.java @@ -22,14 +22,13 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; -import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.util.Preconditions; import java.util.Objects; /** - * Represents a abstract action that can be perform on this app. This are requested from + * Represents an abstract action that can be perform on this app. This are requested from * outside the app's UI (eg by SystemUI or assistant). The semantics of these actions are * not specified by the OS. This allows open-ended and scalable approach for defining how * an app interacts with components that expose alternative interaction models to the user diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index c552cb62749b..a969b10c15a3 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -81,7 +81,7 @@ public final class WallpaperInfo implements Parcelable { final int mContextDescriptionResource; final boolean mShowMetadataInPreview; final boolean mSupportsAmbientMode; - final boolean mShouldUseDefaultDeviceStateChangeTransition; + final boolean mShouldUseDefaultDisplayStateChangeTransition; final String mSettingsSliceUri; final boolean mSupportMultipleDisplays; @@ -146,9 +146,9 @@ public final class WallpaperInfo implements Parcelable { mSupportsAmbientMode = sa.getBoolean( com.android.internal.R.styleable.Wallpaper_supportsAmbientMode, false); - mShouldUseDefaultDeviceStateChangeTransition = sa.getBoolean( + mShouldUseDefaultDisplayStateChangeTransition = sa.getBoolean( com.android.internal.R.styleable - .Wallpaper_shouldUseDefaultDeviceStateChangeTransition, true); + .Wallpaper_shouldUseDefaultDisplayStateChangeTransition, true); mSettingsSliceUri = sa.getString( com.android.internal.R.styleable.Wallpaper_settingsSliceUri); mSupportMultipleDisplays = sa.getBoolean( @@ -175,7 +175,7 @@ public final class WallpaperInfo implements Parcelable { mSupportsAmbientMode = source.readInt() != 0; mSettingsSliceUri = source.readString(); mSupportMultipleDisplays = source.readInt() != 0; - mShouldUseDefaultDeviceStateChangeTransition = source.readInt() != 0; + mShouldUseDefaultDisplayStateChangeTransition = source.readInt() != 0; mService = ResolveInfo.CREATOR.createFromParcel(source); } @@ -400,24 +400,24 @@ public final class WallpaperInfo implements Parcelable { /** * Returns whether this wallpaper should receive default zooming updates when the device - * changes its state (e.g. when folding or unfolding a foldable device). + * changes its display state (e.g. when folding or unfolding a foldable device). * If set to false the wallpaper will not receive zoom events when changing the device state, * so it can implement its own transition instead. * <p> * This corresponds to the value {@link - * android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition} in the + * android.R.styleable#Wallpaper_shouldUseDefaultDisplayStateChangeTransition} in the * XML description of the wallpaper. * <p> * The default value is {@code true}. * - * @see android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition + * @see android.R.styleable#Wallpaper_shouldUseDefaultDisplayStateChangeTransition * @return {@code true} if wallpaper should receive default device state change * transition updates * - * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultDeviceStateChangeTransition + * @attr ref android.R.styleable#Wallpaper_shouldUseDefaultDisplayStateChangeTransition */ - public boolean shouldUseDefaultDeviceStateChangeTransition() { - return mShouldUseDefaultDeviceStateChangeTransition; + public boolean shouldUseDefaultDisplayStateChangeTransition() { + return mShouldUseDefaultDisplayStateChangeTransition; } public void dump(Printer pw, String prefix) { @@ -450,7 +450,7 @@ public final class WallpaperInfo implements Parcelable { dest.writeInt(mSupportsAmbientMode ? 1 : 0); dest.writeString(mSettingsSliceUri); dest.writeInt(mSupportMultipleDisplays ? 1 : 0); - dest.writeInt(mShouldUseDefaultDeviceStateChangeTransition ? 1 : 0); + dest.writeInt(mShouldUseDefaultDisplayStateChangeTransition ? 1 : 0); mService.writeToParcel(dest, flags); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 12444ab9ab09..5b01a7d2de66 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -7726,27 +7726,64 @@ public class DevicePolicyManager { } /** - * @hide - * Sets the given package as the device owner. The package must already be installed. There - * must not already be a device owner. - * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call - * this method. - * Calling this after the setup phase of the primary user has completed is allowed only if - * the caller is the shell uid, and there are no additional users and no accounts. + * Sets the given package as the device owner. + * + * <p>Preconditions: + * <ul> + * <li>The package must already be installed. + * <li>There must not already be a device owner. + * <li>Only apps with the {@code MANAGE_PROFILE_AND_DEVICE_OWNERS} permission or the + * {@link Process#SHELL_UID Shell UID} can call this method. + * </ul> + * + * <p>Calling this after the setup phase of the device owner user has completed is allowed only + * if the caller is the {@link Process#SHELL_UID Shell UID}, and there are no additional users + * (except when the device runs on headless system user mode, in which case it could have exact + * one extra user, which is the current user - the device owner will be set in the + * {@link UserHandle#SYSTEM system} user and a profile owner will be set in the current user) + * and no accounts. + * * @param who the component name to be registered as device owner. * @param ownerName the human readable name of the institution that owns this device. * @param userId ID of the user on which the device owner runs. + * * @return whether the package was successfully registered as the device owner. - * @throws IllegalArgumentException if the package name is null or invalid + * + * @throws IllegalArgumentException if the package name is {@code null} or invalid. * @throws IllegalStateException If the preconditions mentioned are not met. + * + * @hide */ @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) - public boolean setDeviceOwner( + public boolean setDeviceOwner(@NonNull ComponentName who, @Nullable String ownerName, + @UserIdInt int userId) { + if (mService != null) { + try { + return mService.setDeviceOwner(who, ownerName, userId, + /* setProfileOwnerOnCurrentUserIfNecessary= */ true); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Same as {@link #setDeviceOwner(ComponentName, String, int)}, but without setting the profile + * owner on current user when running on headless system user mode - should be used only by + * testing infra. + * + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) + public boolean setDeviceOwnerOnly( @NonNull ComponentName who, @Nullable String ownerName, @UserIdInt int userId) { if (mService != null) { try { - return mService.setDeviceOwner(who, ownerName, userId); + return mService.setDeviceOwner(who, ownerName, userId, + /* setProfileOwnerOnCurrentUserIfNecessary= */ false); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -9734,6 +9771,27 @@ public class DevicePolicyManager { } /** + * @param userId The user for whom to retrieve information. + * @param restriction The restriction enforced by admin. It could be any user restriction or + * policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and + * {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}. + * @return Details of admin and user which enforced the restriction for the userId. If + * restriction is null, profile owner for the user or device owner info is returned. + * @hide + */ + public @Nullable Bundle getEnforcingAdminAndUserDetails(int userId, + @Nullable String restriction) { + if (mService != null) { + try { + return mService.getEnforcingAdminAndUserDetails(userId, restriction); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return null; + } + + /** * Hide or unhide packages. When a package is hidden it is unavailable for use, but the data and * actual package file remain. This function can be called by a device owner, profile owner, or * by a delegate given the {@link #DELEGATION_PACKAGE_ACCESS} scope via diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index b1364b500d4a..1c9187d8d22c 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -159,7 +159,7 @@ interface IDevicePolicyManager { void reportKeyguardDismissed(int userHandle); void reportKeyguardSecured(int userHandle); - boolean setDeviceOwner(in ComponentName who, String ownerName, int userId); + boolean setDeviceOwner(in ComponentName who, String ownerName, int userId, boolean setProfileOwnerOnCurrentUserIfNecessary); ComponentName getDeviceOwnerComponent(boolean callingUserOnly); boolean hasDeviceOwner(); String getDeviceOwnerName(); @@ -251,6 +251,7 @@ interface IDevicePolicyManager { boolean isNotificationListenerServicePermitted(in String packageName, int userId); Intent createAdminSupportIntent(in String restriction); + Bundle getEnforcingAdminAndUserDetails(int userId,String restriction); boolean setApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean hidden, boolean parent); boolean isApplicationHidden(in ComponentName admin, in String callerPackage, in String packageName, boolean parent); diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java index e059f177e344..27d104b59284 100644 --- a/core/java/android/app/servertransaction/ActivityResultItem.java +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -16,6 +16,8 @@ package android.app.servertransaction; +import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; +import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import android.annotation.NonNull; @@ -23,6 +25,9 @@ import android.annotation.Nullable; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ResultInfo; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -41,11 +46,19 @@ public class ActivityResultItem extends ActivityTransactionItem { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private List<ResultInfo> mResultInfoList; - /* TODO(b/78294732) + /** + * Correct the lifecycle of activity result after {@link android.os.Build.VERSION_CODES#S} to + * guarantee that an activity gets activity result just before resume. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S) + public static final long CALL_ACTIVITY_RESULT_BEFORE_RESUME = 78294732L; + @Override public int getPostExecutionState() { - return ON_RESUME; - }*/ + return CompatChanges.isChangeEnabled(CALL_ACTIVITY_RESULT_BEFORE_RESUME) + ? ON_RESUME : UNDEFINED; + } @Override public void execute(ClientTransactionHandler client, ActivityClientRecord r, diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 37cbccb89735..34e4fcdb9140 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -73,7 +73,6 @@ public class LaunchActivityItem extends ClientTransactionItem { private IBinder mAssistToken; private IBinder mShareableActivityToken; private boolean mLaunchedFromBubble; - private IBinder mTaskFragmentToken; /** * It is only non-null if the process is the first time to launch activity. It is only an * optimization for quick look up of the interface so the field is ignored for comparison. @@ -87,7 +86,7 @@ public class LaunchActivityItem extends ClientTransactionItem { mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken, - mLaunchedFromBubble, mTaskFragmentToken); + mLaunchedFromBubble); client.addLaunchingActivity(token, r); client.updateProcessState(mProcState, false); client.updatePendingConfiguration(mCurConfig); @@ -125,7 +124,7 @@ public class LaunchActivityItem extends ClientTransactionItem { boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, IActivityClientController activityClientController, FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken, - boolean launchedFromBubble, IBinder taskFragmentToken) { + boolean launchedFromBubble) { LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); if (instance == null) { instance = new LaunchActivityItem(); @@ -134,7 +133,7 @@ public class LaunchActivityItem extends ClientTransactionItem { voiceInteractor, procState, state, persistentState, pendingResults, pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken, activityClientController, fixedRotationAdjustments, shareableActivityToken, - launchedFromBubble, taskFragmentToken); + launchedFromBubble); return instance; } @@ -142,7 +141,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public void recycle() { setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null, - null, false, null, null, null, null, null, false, null); + null, false, null, null, null, null, null, false); ObjectPool.recycle(this); } @@ -173,7 +172,6 @@ public class LaunchActivityItem extends ClientTransactionItem { dest.writeTypedObject(mFixedRotationAdjustments, flags); dest.writeStrongBinder(mShareableActivityToken); dest.writeBoolean(mLaunchedFromBubble); - dest.writeStrongBinder(mTaskFragmentToken); } /** Read from Parcel. */ @@ -192,8 +190,7 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readStrongBinder(), IActivityClientController.Stub.asInterface(in.readStrongBinder()), in.readTypedObject(FixedRotationAdjustments.CREATOR), in.readStrongBinder(), - in.readBoolean(), - in.readStrongBinder()); + in.readBoolean()); } public static final @NonNull Creator<LaunchActivityItem> CREATOR = @@ -232,8 +229,7 @@ public class LaunchActivityItem extends ClientTransactionItem { && Objects.equals(mProfilerInfo, other.mProfilerInfo) && Objects.equals(mAssistToken, other.mAssistToken) && Objects.equals(mFixedRotationAdjustments, other.mFixedRotationAdjustments) - && Objects.equals(mShareableActivityToken, other.mShareableActivityToken) - && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken); + && Objects.equals(mShareableActivityToken, other.mShareableActivityToken); } @Override @@ -256,7 +252,6 @@ public class LaunchActivityItem extends ClientTransactionItem { result = 31 * result + Objects.hashCode(mAssistToken); result = 31 * result + Objects.hashCode(mFixedRotationAdjustments); result = 31 * result + Objects.hashCode(mShareableActivityToken); - result = 31 * result + Objects.hashCode(mTaskFragmentToken); return result; } @@ -306,7 +301,7 @@ public class LaunchActivityItem extends ClientTransactionItem { ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, IActivityClientController activityClientController, FixedRotationAdjustments fixedRotationAdjustments, IBinder shareableActivityToken, - boolean launchedFromBubble, IBinder taskFragmentToken) { + boolean launchedFromBubble) { instance.mIntent = intent; instance.mIdent = ident; instance.mInfo = info; @@ -328,6 +323,5 @@ public class LaunchActivityItem extends ClientTransactionItem { instance.mFixedRotationAdjustments = fixedRotationAdjustments; instance.mShareableActivityToken = shareableActivityToken; instance.mLaunchedFromBubble = launchedFromBubble; - instance.mTaskFragmentToken = taskFragmentToken; } } diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 8aa27853b462..dd147cc26e59 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -552,6 +552,10 @@ public class AppWidgetHostView extends FrameLayout { inflateAsync(rvToApply); return; } + // Prepare a local reference to the remote Context so we're ready to + // inflate any requested LayoutParams. + mRemoteContext = getRemoteContext(); + int layoutId = rvToApply.getLayoutId(); if (rvToApply.canRecycleView(mView)) { try { @@ -727,6 +731,9 @@ public class AppWidgetHostView extends FrameLayout { } catch (NameNotFoundException e) { Log.e(TAG, "Package name " + mInfo.providerInfo.packageName + " not found"); return mContext; + } catch (NullPointerException e) { + Log.e(TAG, "Error trying to create the remote context.", e); + return mContext; } } diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index a1f7aa12264b..518b22bd5e10 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -22,6 +22,7 @@ import android.os.Build; import android.os.SystemProperties; import android.provider.Settings; import android.text.TextUtils; +import android.util.Log; import com.android.internal.R; @@ -32,7 +33,7 @@ import com.android.internal.R; */ @TestApi public class AmbientDisplayConfiguration { - + private static final String TAG = "AmbientDisplayConfig"; private final Context mContext; private final boolean mAlwaysOnByDefault; @@ -141,11 +142,20 @@ public class AmbientDisplayConfiguration { } /** {@hide} */ - public String tapSensorType() { + private String tapSensorType() { return mContext.getResources().getString(R.string.config_dozeTapSensorType); } /** {@hide} */ + public String tapSensorType(int posture) { + return getSensorFromPostureMapping( + mContext.getResources().getStringArray(R.array.config_dozeTapSensorPostureMapping), + tapSensorType(), + posture + ); + } + + /** {@hide} */ public String longPressSensorType() { return mContext.getResources().getString(R.string.config_dozeLongPressSensorType); } @@ -241,4 +251,19 @@ public class AmbientDisplayConfiguration { private boolean boolSetting(String name, int user, int def) { return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, def, user) != 0; } + + /** {@hide} */ + public static String getSensorFromPostureMapping( + String[] postureMapping, + String defaultValue, + int posture) { + String sensorType = defaultValue; + if (posture < postureMapping.length) { + sensorType = postureMapping[posture]; + } else { + Log.e(TAG, "Unsupported doze posture " + posture); + } + + return TextUtils.isEmpty(sensorType) ? defaultValue : sensorType; + } } diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 73961ff373dd..d8f20391098c 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -1288,6 +1288,23 @@ public final class DisplayManager { */ String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS = "fixed_refresh_rate_high_ambient_brightness_thresholds"; + + /** + * Key for refresh rate when the device is in high brightness mode for sunlight visility. + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.integer#config_defaultRefreshRateInHbmSunlight + */ + String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight"; + + /** + * Key for refresh rate when the device is in high brightness mode for HDR. + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.integer#config_defaultRefreshRateInHbmHdr + */ + String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr"; + /** * Key for default peak refresh rate * diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 1f11d10052fe..1a7ec7f99c95 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -782,7 +782,7 @@ public class TextLine { int spanStart = runStart; int spanLimit; - if (mSpanned == null) { + if (mSpanned == null || runStart == runLimit) { spanLimit = runLimit; } else { int target = after ? offset + 1 : offset; diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java index 971e16185815..aecde4415117 100644 --- a/core/java/android/util/MathUtils.java +++ b/core/java/android/util/MathUtils.java @@ -165,6 +165,10 @@ public final class MathUtils { return start + (stop - start) * amount; } + public static float lerp(int start, int stop, float amount) { + return lerp((float) start, (float) stop, amount); + } + /** * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link * #lerp}{@code (a, b, s)} diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index afdb755179a6..b729c9fb01b1 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -20889,13 +20889,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; } + notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); + mAttachInfo = null; if (mOverlay != null) { mOverlay.getOverlayView().dispatchDetachedFromWindow(); } notifyEnterOrExitForAutoFillIfNeeded(false); - notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); } /** diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index aae6f5016891..f8eb95cbd48c 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -59,6 +59,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_ROW_SWIPE; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION; import android.annotation.IntDef; @@ -171,6 +172,7 @@ public class InteractionJankMonitor { public static final int CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP = 34; public static final int CUJ_PIP_TRANSITION = 35; public static final int CUJ_WALLPAPER_TRANSITION = 36; + public static final int CUJ_USER_SWITCH = 37; private static final int NO_STATSD_LOGGING = -1; @@ -216,6 +218,7 @@ public class InteractionJankMonitor { UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PIP_TRANSITION, UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION, + UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH, }; private static volatile InteractionJankMonitor sInstance; @@ -272,6 +275,7 @@ public class InteractionJankMonitor { CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP, CUJ_PIP_TRANSITION, CUJ_WALLPAPER_TRANSITION, + CUJ_USER_SWITCH, }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { @@ -642,6 +646,8 @@ public class InteractionJankMonitor { return "PIP_TRANSITION"; case CUJ_WALLPAPER_TRANSITION: return "WALLPAPER_TRANSITION"; + case CUJ_USER_SWITCH: + return "USER_SWITCH"; } return "UNKNOWN"; } diff --git a/core/res/res/anim-ldrtl/task_close_exit.xml b/core/res/res/anim-ldrtl/task_close_exit.xml index 76fbdffd1760..0887019ca608 100644 --- a/core/res/res/anim-ldrtl/task_close_exit.xml +++ b/core/res/res/anim-ldrtl/task_close_exit.xml @@ -28,9 +28,4 @@ android:startOffset="0" android:duration="500"/> - <!-- This is needed to keep the animation running while task_open_enter completes --> - <alpha - android:fromAlpha="1.0" - android:toAlpha="1.0" - android:duration="600"/> -</set>
\ No newline at end of file +</set> diff --git a/core/res/res/anim-ldrtl/task_open_exit.xml b/core/res/res/anim-ldrtl/task_open_exit.xml index beb6fca5632a..88cdcceae415 100644 --- a/core/res/res/anim-ldrtl/task_open_exit.xml +++ b/core/res/res/anim-ldrtl/task_open_exit.xml @@ -28,9 +28,4 @@ android:startOffset="0" android:duration="500"/> - <!-- This is needed to keep the animation running while task_open_enter completes --> - <alpha - android:fromAlpha="1.0" - android:toAlpha="1.0" - android:duration="600"/> -</set>
\ No newline at end of file +</set> diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml index 736f3f2083e5..3a8dd934cd17 100644 --- a/core/res/res/anim/task_close_exit.xml +++ b/core/res/res/anim/task_close_exit.xml @@ -30,9 +30,4 @@ android:startOffset="0" android:duration="500"/> - <!-- This is needed to keep the animation running while task_open_enter completes --> - <alpha - android:fromAlpha="1.0" - android:toAlpha="1.0" - android:duration="600"/> -</set>
\ No newline at end of file +</set> diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml index d1703170e16f..21fec7f694bf 100644 --- a/core/res/res/anim/task_open_exit.xml +++ b/core/res/res/anim/task_open_exit.xml @@ -30,9 +30,4 @@ android:startOffset="0" android:duration="500"/> - <!-- This is needed to keep the animation running while task_open_enter completes --> - <alpha - android:fromAlpha="1.0" - android:toAlpha="1.0" - android:duration="600"/> -</set>
\ No newline at end of file +</set> diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml index 16df45290302..6c40f10a03c3 100644 --- a/core/res/res/drawable/ic_corp_badge.xml +++ b/core/res/res/drawable/ic_corp_badge.xml @@ -22,8 +22,5 @@ Copyright (C) 2018 The Android Open Source Project android:viewportHeight="24"> <path android:fillColor="@android:color/white" - android:pathData="M20,6h-4V4c0-1.1-0.9-2-2-2h-4C8.9,2,8,2.9,8,4v2H4C2.9,6,2,6.9,2,8l0,11c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8 C22,6.9,21.1,6,20,6z M10,4h4v2h-4V4z M20,19H4V8h16V19z" /> - <path - android:fillColor="@android:color/white" - android:pathData="M 12 12 C 12.8284271247 12 13.5 12.6715728753 13.5 13.5 C 13.5 14.3284271247 12.8284271247 15 12 15 C 11.1715728753 15 10.5 14.3284271247 10.5 13.5 C 10.5 12.6715728753 11.1715728753 12 12 12 Z" /> + android:pathData="@string/config_work_badge_path_24"/> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_corp_badge_case.xml b/core/res/res/drawable/ic_corp_badge_case.xml index 1cd995eea171..838426ecd9a0 100644 --- a/core/res/res/drawable/ic_corp_badge_case.xml +++ b/core/res/res/drawable/ic_corp_badge_case.xml @@ -1,9 +1,9 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" - android:viewportWidth="20.0" - android:viewportHeight="20.0"> + android:viewportWidth="24.0" + android:viewportHeight="24.0"> <path - android:pathData="M14.67,6.5h-2.33V5.33c0,-0.65 -0.52,-1.17 -1.17,-1.17H8.83c-0.65,0 -1.17,0.52 -1.17,1.17V6.5H5.33c-0.65,0 -1.16,0.52 -1.16,1.17l-0.01,6.42c0,0.65 0.52,1.17 1.17,1.17h9.33c0.65,0 1.17,-0.52 1.17,-1.17V7.67C15.83,7.02 15.31,6.5 14.67,6.5zM10,11.75c-0.64,0 -1.17,-0.52 -1.17,-1.17c0,-0.64 0.52,-1.17 1.17,-1.17c0.64,0 1.17,0.52 1.17,1.17C11.17,11.22 10.64,11.75 10,11.75zM11.17,6.5H8.83V5.33h2.33V6.5z" + android:pathData="@string/config_work_badge_path_24" android:fillColor="#1A73E8"/> </vector> diff --git a/core/res/res/drawable/ic_corp_badge_no_background.xml b/core/res/res/drawable/ic_corp_badge_no_background.xml index 8f7fb70d5b83..e81e69f1b5d5 100644 --- a/core/res/res/drawable/ic_corp_badge_no_background.xml +++ b/core/res/res/drawable/ic_corp_badge_no_background.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,15 12,15zM14,6h-4V4h4V6z" + android:pathData="@string/config_work_badge_path_24" android:fillColor="#FFFFFF"/> </vector> diff --git a/core/res/res/drawable/ic_corp_icon.xml b/core/res/res/drawable/ic_corp_icon.xml index 48531dd8c539..86bb98e0996b 100644 --- a/core/res/res/drawable/ic_corp_icon.xml +++ b/core/res/res/drawable/ic_corp_icon.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z" + android:pathData="@string/config_work_badge_path_24" android:fillColor="#000000"/> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_corp_icon_badge_case.xml b/core/res/res/drawable/ic_corp_icon_badge_case.xml index 50551d401120..09cf9cb89abe 100644 --- a/core/res/res/drawable/ic_corp_icon_badge_case.xml +++ b/core/res/res/drawable/ic_corp_icon_badge_case.xml @@ -22,9 +22,15 @@ Copyright (C) 2016 The Android Open Source Project <path android:pathData="M 42 42 L 58 42 L 58 58 L 42 58 L 42 42 Z" /> - <path - android:fillColor="#1A73E8" - android:pathData="M55.33,46H52.67V44.67a1.33,1.33,0,0,0-1.33-1.33H48.67a1.33,1.33,0,0,0-1.33,1.33V46H44.67a1.32,1.32,0,0,0-1.33,1.33v7.33A1.33,1.33,0,0,0,44.67,56H55.33a1.33,1.33,0,0,0,1.33-1.33V47.33A1.33,1.33,0,0,0,55.33,46ZM50,52a1.33,1.33,0,1,1,1.33-1.33A1.34,1.34,0,0,1,50,52Zm1.33-6H48.67V44.67h2.67Z" /> + <group + android:scaleX=".66" + android:scaleY=".66" + android:translateX="42" + android:translateY="42"> + <path + android:pathData="@string/config_work_badge_path_24" + android:fillColor="#1A73E8"/> + </group> <path android:pathData="M 0 0 H 64 V 64 H 0 V 0 Z" /> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_corp_statusbar_icon.xml b/core/res/res/drawable/ic_corp_statusbar_icon.xml index 8f7fb70d5b83..e81e69f1b5d5 100644 --- a/core/res/res/drawable/ic_corp_statusbar_icon.xml +++ b/core/res/res/drawable/ic_corp_statusbar_icon.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:pathData="M20,6h-4V4c0,-1.11 -0.89,-2 -2,-2h-4C8.89,2 8,2.89 8,4v2H4C2.89,6 2.01,6.89 2.01,8L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V8C22,6.89 21.11,6 20,6zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,15 12,15zM14,6h-4V4h4V6z" + android:pathData="@string/config_work_badge_path_24" android:fillColor="#FFFFFF"/> </vector> diff --git a/core/res/res/drawable/ic_corp_user_badge.xml b/core/res/res/drawable/ic_corp_user_badge.xml index a08f2d4845e1..76ba4506426d 100644 --- a/core/res/res/drawable/ic_corp_user_badge.xml +++ b/core/res/res/drawable/ic_corp_user_badge.xml @@ -8,9 +8,6 @@ android:pathData="M16.3,11.3h3.4v1.7h-3.4z" android:fillColor="#FFFFFF"/> <path - android:pathData="M18,17.17c-0.92,0 -1.67,0.75 -1.67,1.67c0,0.92 0.75,1.67 1.67,1.67c0.92,0 1.67,-0.75 1.67,-1.67C19.67,17.92 18.92,17.17 18,17.17z" - android:fillColor="#FFFFFF"/> - <path android:pathData="M18,0C8.06,0 0,8.06 0,18s8.06,18 18,18s18,-8.06 18,-18S27.94,0 18,0zM26.3,23.83c0,0.92 -0.71,1.67 -1.63,1.67H11.33c-0.93,0 -1.67,-0.74 -1.67,-1.67l0.01,-9.17c0,-0.92 0.73,-1.67 1.66,-1.67h3.37v-1.67c0,-0.93 0.71,-1.63 1.63,-1.63h3.33c0.93,0 1.63,0.71 1.63,1.63V13h3.37c0.93,0 1.63,0.74 1.63,1.67V23.83z" android:fillColor="#FFFFFF"/> </vector> diff --git a/core/res/res/values-mcc334-mnc020-af/strings.xml b/core/res/res/values-mcc334-mnc020-af/strings.xml new file mode 100644 index 000000000000..c9177f3cb772 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-af/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"STAWINGMISLUKKING -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NIE INGETEKEN OP DIENS NIE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Veelvuldige PDN-verbindings vir \'n bepaalde APN word nie toegelaat nie -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-am/strings.xml b/core/res/res/values-mcc334-mnc020-am/strings.xml new file mode 100644 index 000000000000..609fcf95630b --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-am/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"የማረጋገጫ አለመሳካት -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ለአገልግሎት ደንበኝነት አልተመዘገበም -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ለተሰጠው ኤፒኤን ብዙ የፒዲኤን ግንኙነቶች አይፈቀዱም -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ar/strings.xml b/core/res/res/values-mcc334-mnc020-ar/strings.xml new file mode 100644 index 000000000000..ac7dec0da313 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ar/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"تعذّرت المصادقة -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"غير مشترك في الخدمة -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"غير مسموح باتصالات PDN متعددة لاسم نقطة وصول محددة (APN) -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-as/strings.xml b/core/res/res/values-mcc334-mnc020-as/strings.xml new file mode 100644 index 000000000000..25b074eec145 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-as/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <!-- no translation found for config_pdp_reject_user_authentication_failed (4683454131283459978) --> + <skip /> + <!-- no translation found for config_pdp_reject_service_not_subscribed (9021140729932308119) --> + <skip /> + <!-- no translation found for config_pdp_reject_multi_conn_to_same_pdn_not_allowed (3838388706348367865) --> + <skip /> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-az/strings.xml b/core/res/res/values-mcc334-mnc020-az/strings.xml new file mode 100644 index 000000000000..83b210d90eaa --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-az/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"DOĞRULAMA XƏTASI -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"XİDMƏTƏ ABUNƏ OLUNMAYIB -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Verilmiş APN üçün birdən çox PDN bağlantısına icazə verilmir -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-b+sr+Latn/strings.xml b/core/res/res/values-mcc334-mnc020-b+sr+Latn/strings.xml new file mode 100644 index 000000000000..b27e485e5f73 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-b+sr+Latn/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"POTVRDA IDENTITETA NIJE USPELA -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NISTE PRETPLAĆENI NA USLUGU -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Nije dozvoljeno više PDN veza za određeni APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-be/strings.xml b/core/res/res/values-mcc334-mnc020-be/strings.xml new file mode 100644 index 000000000000..3ee9e8f1ce60 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-be/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ЗБОЙ АЎТЭНТЫФІКАЦЫІ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"У ВАС НЯМА ПАДПІСКІ НА СЭРВІС -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Да гэтага APN нельга падключаць некалькі сетак PDN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-bg/strings.xml b/core/res/res/values-mcc334-mnc020-bg/strings.xml new file mode 100644 index 000000000000..257cf585ca21 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-bg/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"НЕУСПЕШНО УДОСТОВЕРЯВАНЕ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"НЯМА АБОНАМЕНТ ЗА УСЛУГАТА -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Не е разрешено да има повече от една PDN връзка за дадено име на точката за достъп (APN) -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-bn/strings.xml b/core/res/res/values-mcc334-mnc020-bn/strings.xml new file mode 100644 index 000000000000..25b074eec145 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-bn/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <!-- no translation found for config_pdp_reject_user_authentication_failed (4683454131283459978) --> + <skip /> + <!-- no translation found for config_pdp_reject_service_not_subscribed (9021140729932308119) --> + <skip /> + <!-- no translation found for config_pdp_reject_multi_conn_to_same_pdn_not_allowed (3838388706348367865) --> + <skip /> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-bs/strings.xml b/core/res/res/values-mcc334-mnc020-bs/strings.xml new file mode 100644 index 000000000000..4bf1b8f6cbae --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-bs/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTENTIFIKACIJA NIJE USPJELA -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NISTE PRETPLAĆENI NA USLUGU -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Više PDN veza za određeni APN nije dozvoljeno -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ca/strings.xml b/core/res/res/values-mcc334-mnc020-ca/strings.xml new file mode 100644 index 000000000000..0ad1f1cfc77d --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ca/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ERROR D\'AUTENTICACIÓ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NO ESTÀS SUBSCRIT AL SERVEI -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"No es permeten diverses connexions PDN per a un APN determinat -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-cs/strings.xml b/core/res/res/values-mcc334-mnc020-cs/strings.xml new file mode 100644 index 000000000000..cfa1a44340da --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-cs/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"SELHÁNÍ OVĚŘENÍ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NEJSTE PŘIHLÁŠENI K ODBĚRU SLUŽBY -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"U jednoho APN není povoleno více než jedno připojení PDN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-da/strings.xml b/core/res/res/values-mcc334-mnc020-da/strings.xml new file mode 100644 index 000000000000..7d349cf67f5c --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-da/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"GODKENDELSESFEJL -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"IKKE TILMELDT TJENESTEN -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Flere PDN-forbindelser for en given APN er ikke tilladt -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-de/strings.xml b/core/res/res/values-mcc334-mnc020-de/strings.xml new file mode 100644 index 000000000000..084bf46ee569 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-de/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTHENTIFIZIERUNGSFEHLER -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"DIENST NICHT ABONNIERT -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Mehrere PDN-Verbindungen für einen bestimmten APN sind nicht zulässig -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-el/strings.xml b/core/res/res/values-mcc334-mnc020-el/strings.xml new file mode 100644 index 000000000000..27c5f9548a08 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-el/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ΑΠΟΤΥΧΙΑ ΕΛΕΓΧΟΥ ΤΑΥΤΟΤΗΤΑΣ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ΔΕΝ ΕΓΙΝΕ ΕΓΓΡΑΦΗ ΣΤΗΝ ΥΠΗΡΕΣΙΑ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Δεν επιτρέπονται πολλές συνδέσεις PDN για ένα δεδομένο APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-en-rAU/strings.xml b/core/res/res/values-mcc334-mnc020-en-rAU/strings.xml new file mode 100644 index 000000000000..6dce3455d452 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-en-rAU/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTHENTICATION FAILURE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NOT SUBSCRIBED TO SERVICE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Multiple PDN connections for a given APN not allowed -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-en-rCA/strings.xml b/core/res/res/values-mcc334-mnc020-en-rCA/strings.xml new file mode 100644 index 000000000000..6dce3455d452 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-en-rCA/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTHENTICATION FAILURE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NOT SUBSCRIBED TO SERVICE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Multiple PDN connections for a given APN not allowed -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-en-rGB/strings.xml b/core/res/res/values-mcc334-mnc020-en-rGB/strings.xml new file mode 100644 index 000000000000..6dce3455d452 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-en-rGB/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTHENTICATION FAILURE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NOT SUBSCRIBED TO SERVICE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Multiple PDN connections for a given APN not allowed -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-en-rIN/strings.xml b/core/res/res/values-mcc334-mnc020-en-rIN/strings.xml new file mode 100644 index 000000000000..6dce3455d452 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-en-rIN/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTHENTICATION FAILURE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NOT SUBSCRIBED TO SERVICE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Multiple PDN connections for a given APN not allowed -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-en-rXC/strings.xml b/core/res/res/values-mcc334-mnc020-en-rXC/strings.xml new file mode 100644 index 000000000000..ec8f4ab19bce --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-en-rXC/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTHENTICATION FAILURE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NOT SUBSCRIBED TO SERVICE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Multiple PDN connections for a given APN not allowed -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-es-rUS/strings.xml b/core/res/res/values-mcc334-mnc020-es-rUS/strings.xml new file mode 100644 index 000000000000..8cb181d371ee --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-es-rUS/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"FALLO EN LA AUTENTICACIÓN -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NO TE SUSCRIBISTE AL SERVICIO -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"No se permiten varias conexiones PDN para un APN determinado -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-es/strings.xml b/core/res/res/values-mcc334-mnc020-es/strings.xml new file mode 100644 index 000000000000..0744699804e5 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-es/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ERROR DE AUTENTICACIÓN -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NO SUSCRITO AL SERVICIO -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"No se permiten varias conexiones PDN de un APN concreto -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-et/strings.xml b/core/res/res/values-mcc334-mnc020-et/strings.xml new file mode 100644 index 000000000000..a7e9e1665ee0 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-et/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTENTIMINE EBAÕNNESTUS -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"TEENUST POLE TELLITUD -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Antud APN-i puhul pole mitu PDN-ühendust lubatud -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-eu/strings.xml b/core/res/res/values-mcc334-mnc020-eu/strings.xml new file mode 100644 index 000000000000..2d05b3fea78d --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-eu/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"EZIN IZAN DA AUTENTIFIKATU -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"EZ DAGO HARPIDETUTA ZERBITZURA -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Ezin da konektatu APN jakin bat PDN batera baino gehiagotara -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-fa/strings.xml b/core/res/res/values-mcc334-mnc020-fa/strings.xml new file mode 100644 index 000000000000..8bf364f5b118 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-fa/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"اصالتسنجی انجام نشد -۲۹-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"مشترک سرویس نیستید -۳۳-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"تعدادی از اتصالهای PDN مربوط به APN تعیینشده مجاز نیست -۵۵-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-fi/strings.xml b/core/res/res/values-mcc334-mnc020-fi/strings.xml new file mode 100644 index 000000000000..f8d01ba03fc4 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-fi/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"TODENNUS EPÄONNISTUI -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"PALVELUA EI TILATTU -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Useat yhteydet eivät ole sallittuja yhdelle APN:lle -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml b/core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml new file mode 100644 index 000000000000..25b074eec145 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-fr-rCA/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <!-- no translation found for config_pdp_reject_user_authentication_failed (4683454131283459978) --> + <skip /> + <!-- no translation found for config_pdp_reject_service_not_subscribed (9021140729932308119) --> + <skip /> + <!-- no translation found for config_pdp_reject_multi_conn_to_same_pdn_not_allowed (3838388706348367865) --> + <skip /> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-fr/strings.xml b/core/res/res/values-mcc334-mnc020-fr/strings.xml new file mode 100644 index 000000000000..6eaa7cd61589 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-fr/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ÉCHEC DE L\'AUTHENTIFICATION -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NON INSCRIT AU SERVICE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Vous n\'êtes pas autorisé à avoir plusieurs connexions PDN pour un APN donné -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-gl/strings.xml b/core/res/res/values-mcc334-mnc020-gl/strings.xml new file mode 100644 index 000000000000..49baed94d1c7 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-gl/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ERRO DE AUTENTICACIÓN -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"SEN SUBSCRICIÓN AO SERVIZO -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Non está permitido establecer varias conexións de tipo PDN para un determinado APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-gu/strings.xml b/core/res/res/values-mcc334-mnc020-gu/strings.xml new file mode 100644 index 000000000000..25b074eec145 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-gu/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <!-- no translation found for config_pdp_reject_user_authentication_failed (4683454131283459978) --> + <skip /> + <!-- no translation found for config_pdp_reject_service_not_subscribed (9021140729932308119) --> + <skip /> + <!-- no translation found for config_pdp_reject_multi_conn_to_same_pdn_not_allowed (3838388706348367865) --> + <skip /> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-hi/strings.xml b/core/res/res/values-mcc334-mnc020-hi/strings.xml new file mode 100644 index 000000000000..8a11053764b9 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-hi/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"पुष्टि नहीं की जा सकी -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"सेवा की सदस्यता नहीं ली गई है -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"किसी भी एपीएन के लिए एक से ज़्यादा पीडीएन कनेक्शन की अनुमति नहीं है -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-hr/strings.xml b/core/res/res/values-mcc334-mnc020-hr/strings.xml new file mode 100644 index 000000000000..ff9b427e0df4 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-hr/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTENTIFIKACIJA NIJE USPJELA -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NISTE PRETPLAĆENI NA USLUGU -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Više PDN veza za određeni APN nije dopušteno -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-hu/strings.xml b/core/res/res/values-mcc334-mnc020-hu/strings.xml new file mode 100644 index 000000000000..42776c1e9619 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-hu/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"SIKERTELEN HITELESÍTÉS -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NINCS ELŐFIZETÉSE A SZOLGÁLTATÁSRA -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Nem engedélyezett több PDN-kapcsolat egy adott APN-nél -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-hy/strings.xml b/core/res/res/values-mcc334-mnc020-hy/strings.xml new file mode 100644 index 000000000000..6633bb30e01d --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-hy/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ՆՈՒՅՆԱԿԱՆԱՑՄԱՆ ՍԽԱԼ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ԴՈՒՔ ԲԱԺԱՆՈՐԴԱԳՐՎԱԾ ՉԵՔ ԱՅՍ ԾԱՌԱՅՈՒԹՅԱՆԸ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Այս APN-ով չի թույլատրվում միանալ տվյալների փոխանցման մեկից ավել բաց ցանցի -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-in/strings.xml b/core/res/res/values-mcc334-mnc020-in/strings.xml new file mode 100644 index 000000000000..79a9dfdf971e --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-in/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"KEGAGALAN AUTENTIKASI -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"TIDAK BERLANGGANAN KE LAYANAN -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Beberapa koneksi PDN untuk APN tertentu tidak diizinkan -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-is/strings.xml b/core/res/res/values-mcc334-mnc020-is/strings.xml new file mode 100644 index 000000000000..c9049e8821aa --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-is/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUÐKENNING MISTÓKST -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"EKKI ÁSKRIFANDI AÐ ÞJÓNUSTU -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Margar PDN-tengingar fyrir tiltekinn aðgangsstað eru ekki leyfðar -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-it/strings.xml b/core/res/res/values-mcc334-mnc020-it/strings.xml new file mode 100644 index 000000000000..add9b0d24c20 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-it/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ERRORE DI AUTENTICAZIONE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"SOTTOSCRIZIONE AL SERVIZIO NON EFFETTUATA -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Più connessioni PDN per un dato APN non consentite -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-iw/strings.xml b/core/res/res/values-mcc334-mnc020-iw/strings.xml new file mode 100644 index 000000000000..b8b1ab5ad3b4 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-iw/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"האימות נכשל -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"לא נרשמת כמנוי לשירות -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"אין הרשאה למספר חיבורי PDN ל-APN מסוים -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ja/strings.xml b/core/res/res/values-mcc334-mnc020-ja/strings.xml new file mode 100644 index 000000000000..ec543faa0119 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ja/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"認証エラーが発生しました -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"サービスに登録していません -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"特定の APN に対する複数の PDN 接続は許可されていません -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ka/strings.xml b/core/res/res/values-mcc334-mnc020-ka/strings.xml new file mode 100644 index 000000000000..e55057b90f4b --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ka/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ავტორიზაციის შეცდომა -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"გამოწერილი არ გაქვთ სერვისი -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"მრავალი PDN კავშირი მოცემული APN-ისთვის დაუშვებელია -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-kk/strings.xml b/core/res/res/values-mcc334-mnc020-kk/strings.xml new file mode 100644 index 000000000000..f19d2c727c22 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-kk/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"АУТЕНТИФИКАЦИЯЛАУ ҚАТЕСІ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ҚЫЗМЕТКЕ ЖАЗЫЛМАҒАН -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Бұл APN үшін бірнеше PDN-ге қосылуға рұқсат берілмеген -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-km/strings.xml b/core/res/res/values-mcc334-mnc020-km/strings.xml new file mode 100644 index 000000000000..08e1a0d8a6f3 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-km/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"មិនអាចផ្ទៀងផ្ទាត់បានទេ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"មិនបានជាវសេវាកម្មទេ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ការតភ្ជាប់ PDN ច្រើនសម្រាប់ APN ដែលបានផ្ដល់មិនត្រូវបានអនុញ្ញាតទេ -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-kn/strings.xml b/core/res/res/values-mcc334-mnc020-kn/strings.xml new file mode 100644 index 000000000000..e5780b3e8abb --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-kn/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ದೃಢೀಕರಣ ವಿಫಲಗೊಂಡಿದೆ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ಸೇವೆಗೆ ಸಬ್ಸ್ಕ್ರೈಬ್ ಮಾಡಿಲ್ಲ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ನೀಡಲಾದ APN ಗಾಗಿ ಬಹು PDN ಸಂಪರ್ಕಗಳನ್ನು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ko/strings.xml b/core/res/res/values-mcc334-mnc020-ko/strings.xml new file mode 100644 index 000000000000..444d05097663 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ko/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"인증할 수 없음 -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"서비스 구독 중이 아님 -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"지정된 APN에 여러 PDN을 연결할 수 없음 -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ky/strings.xml b/core/res/res/values-mcc334-mnc020-ky/strings.xml new file mode 100644 index 000000000000..240c6debee1c --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ky/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"АНЫКТЫГЫ ТЕКШЕРИЛГЕН ЖОК -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"КЫЗМАТКА ЖАЗЫЛГАН ЭМЕССИЗ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Бул APN менен бир нече PDN\'ге туташууга болбойт -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-lo/strings.xml b/core/res/res/values-mcc334-mnc020-lo/strings.xml new file mode 100644 index 000000000000..89eb9fc9f896 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-lo/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ການພິສູດຢືນຢັນບໍ່ສຳເລັດ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ບໍ່ໄດ້ສະໝັກໃຊ້ບໍລິການ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ບໍ່ອະນຸຍາດການເຊື່ອມຕໍ່ PDN ຫຼາຍອັນສຳລັບ APN ທີ່ລະບຸ -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-lt/strings.xml b/core/res/res/values-mcc334-mnc020-lt/strings.xml new file mode 100644 index 000000000000..9157b8d72b81 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-lt/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTENTIFIKAVIMO TRIKTIS -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"PASLAUGA NEPRENUMERUOJAMA -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Kelių PDN ryšiai su APN neleidžiami -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-lv/strings.xml b/core/res/res/values-mcc334-mnc020-lv/strings.xml new file mode 100644 index 000000000000..33af8634f1dc --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-lv/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTENTIFIKĀCIJAS KĻŪME -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"PAKALPOJUMS NAV ABONĒTS -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Norādītajam APN nav atļauti vairāki PDN savienojumi -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-mk/strings.xml b/core/res/res/values-mcc334-mnc020-mk/strings.xml new file mode 100644 index 000000000000..5b6b62193440 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-mk/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"НЕУСПЕШНА ПРОВЕРКА -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"НЕ СТЕ ПРЕТПЛАТЕНИ НА УСЛУГАТА -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Не се дозволени повеќекратни PDN-врски за дадена APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ml/strings.xml b/core/res/res/values-mcc334-mnc020-ml/strings.xml new file mode 100644 index 000000000000..d56b4c889896 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ml/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"പരിശോധിച്ചുറപ്പിക്കൽ പരാജയം -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"സേവനം സബ്സ്ക്രൈബ് ചെയ്തിട്ടില്ല -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"നൽകിയിരിക്കുന്ന ഒരു APN-ൽ ഒന്നിലധികം PDN കണക്ഷനുകൾ അനുവദനീയമല്ല -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-mn/strings.xml b/core/res/res/values-mcc334-mnc020-mn/strings.xml new file mode 100644 index 000000000000..9eb4753155af --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-mn/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"БАТАЛГААЖУУЛЖ ЧАДСАНГҮЙ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ҮЙЛЧИЛГЭЭГ ЗАХИАЛААГҮЙ БАЙНА -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Өгсөн APN-д хэд хэдэн PDN холболтыг зөвшөөрдөггүй -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-mr/strings.xml b/core/res/res/values-mcc334-mnc020-mr/strings.xml new file mode 100644 index 000000000000..7adf6667ebaa --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-mr/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ऑथेंटिकेशन यशस्वी झाले नाही -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"सेवेचे सदस्यत्व घेतलेले नाही -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"दिलेल्या APN साठी एकपेक्षा जास्त PDN कनेक्शनची अनुमती नाही -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ms/strings.xml b/core/res/res/values-mcc334-mnc020-ms/strings.xml new file mode 100644 index 000000000000..cbae67e73bad --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ms/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"KEGAGALAN PENGESAHAN -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"TIDAK MELANGGAN PERKHIDMATAN -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Sambungan berbilang PDN untuk APN yang diberikan tidak dibenarkan -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-my/strings.xml b/core/res/res/values-mcc334-mnc020-my/strings.xml new file mode 100644 index 000000000000..f1e7d6e24b83 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-my/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"အထောက်အထားစိစစ်ခြင်း မအောင်မြင်ပါ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ဝန်ဆောင်မှုကို စာရင်းသွင်းမထားပါ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ပေးထားသော APN အတွက် PDN ချိတ်ဆက်မှုအများအပြားကို ခွင့်မပြုပါ -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-nb/strings.xml b/core/res/res/values-mcc334-mnc020-nb/strings.xml new file mode 100644 index 000000000000..623f2d98663f --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-nb/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTENTISERINGSFEIL -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ABONNERER IKKE PÅ TJENESTEN -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Flere PDN-tilkoblinger for et gitt APN er ikke tillatt -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ne/strings.xml b/core/res/res/values-mcc334-mnc020-ne/strings.xml new file mode 100644 index 000000000000..fd692766c5d2 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ne/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"पुष्टि गर्न सकिएन -२९-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"सेवाको सदस्यता लिइएको छैन -३३-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"कुनै निश्चित APN का हकमा एकभन्दा बढी PDN कनेक्सन गर्ने अनुमति दिइएको छैन -५५-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-nl/strings.xml b/core/res/res/values-mcc334-mnc020-nl/strings.xml new file mode 100644 index 000000000000..40cb2fa4e6e2 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-nl/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"VERIFICATIE MISLUKT -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NIET GEABONNEERD OP SERVICE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Meerdere PDN-verbindingen voor een bepaalde APN niet toegestaan -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-or/strings.xml b/core/res/res/values-mcc334-mnc020-or/strings.xml new file mode 100644 index 000000000000..49810d511372 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-or/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ପ୍ରାମାଣିକତା ବିଫଳ ହୋଇଛି -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ସେବା ପାଇଁ ସଦସ୍ୟତା ନିଆଯାଇନାହିଁ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ଦିଆଯାଇଥିବା ଏକ APN ପାଇଁ ଏକାଧିକ PDN ସଂଯୋଗକୁ ଅନୁମତି ଦିଆଯାଇନାହିଁ -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-pa/strings.xml b/core/res/res/values-mcc334-mnc020-pa/strings.xml new file mode 100644 index 000000000000..3cf6bc88e70e --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-pa/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ਪ੍ਰਮਾਣੀਕਰਨ ਅਸਫਲ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ਸੇਵਾ ਦੀ ਗਾਹਕੀ ਨਹੀਂ ਲਈ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ਕਿਸੇ ਵੀ APN ਲਈ ਇੱਕ ਤੋਂ ਵੱਧ PDN ਕਨੈਕਸ਼ਨਾਂ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-pl/strings.xml b/core/res/res/values-mcc334-mnc020-pl/strings.xml new file mode 100644 index 000000000000..9c5fd78b9527 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-pl/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"BŁĄD UWIERZYTELNIANIA -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"USŁUGA NIESUBSKRYBOWANA -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Wielokrotne połączenia PDN w danym APN nie są dozwolone -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-pt-rBR/strings.xml b/core/res/res/values-mcc334-mnc020-pt-rBR/strings.xml new file mode 100644 index 000000000000..1292978cc840 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-pt-rBR/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"FALHA NA AUTENTICAÇÃO -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"A CONTA NÃO ESTÁ INSCRITA NO SERVIÇO -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Não é permitido ter várias conexões PDN para um determinado APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-pt-rPT/strings.xml b/core/res/res/values-mcc334-mnc020-pt-rPT/strings.xml new file mode 100644 index 000000000000..68248f3f6d94 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-pt-rPT/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"FALHA NA AUTENTICAÇÃO -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NÃO SUBSCREVEU O SERVIÇO -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Não são permitidas várias ligações PDN para um determinado APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-pt/strings.xml b/core/res/res/values-mcc334-mnc020-pt/strings.xml new file mode 100644 index 000000000000..1292978cc840 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-pt/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"FALHA NA AUTENTICAÇÃO -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"A CONTA NÃO ESTÁ INSCRITA NO SERVIÇO -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Não é permitido ter várias conexões PDN para um determinado APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ro/strings.xml b/core/res/res/values-mcc334-mnc020-ro/strings.xml new file mode 100644 index 000000000000..92564e977617 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ro/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"EROARE DE AUTENTIFICARE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"FĂRĂ ABONAMENT LA SERVICIU -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Nu se permit mai multe conexiuni PDN pentru un anumit APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ru/strings.xml b/core/res/res/values-mcc334-mnc020-ru/strings.xml new file mode 100644 index 000000000000..f4647ba04139 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ru/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ОШИБКА АУТЕНТИФИКАЦИИ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"НЕТ ПОДПИСКИ НА СЕРВИС -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Указанная точка доступа не поддерживает несколько PDN-соединений -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-si/strings.xml b/core/res/res/values-mcc334-mnc020-si/strings.xml new file mode 100644 index 000000000000..cb839758b29d --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-si/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"සත්යාපනය අසාර්ථකයි -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"සේවාවකට ග්රාහක වී නැත -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"දී ඇති APN එකක් සඳහා බහුවිධ PDN සම්බන්ධතා ඉඩ නොදේ -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-sk/strings.xml b/core/res/res/values-mcc334-mnc020-sk/strings.xml new file mode 100644 index 000000000000..77efe302ecc0 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-sk/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"NEPODARILO SA OVERIŤ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"SLUŽBU NEODOBERÁTE -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Pre daný názov prístupového bodu (APN) nie je povolených viacero pripojení PDN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-sl/strings.xml b/core/res/res/values-mcc334-mnc020-sl/strings.xml new file mode 100644 index 000000000000..118c3dde0411 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-sl/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"NAPAKA PRI PREVERJANJU PRISTNOSTI. -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NISTE NAROČENI NA STORITEV. -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Za dano ime dostopne točke (APN) ni dovoljenih več povezav PDN. -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-sq/strings.xml b/core/res/res/values-mcc334-mnc020-sq/strings.xml new file mode 100644 index 000000000000..315a8abba377 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-sq/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"DËSHTIM NË VERIFIKIM -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"NUK JE ABONUAR NË SHËRBIM -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Disa lidhje PDN për një APN të caktuar nuk lejohen -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-sr/strings.xml b/core/res/res/values-mcc334-mnc020-sr/strings.xml new file mode 100644 index 000000000000..ddf0ce15aa78 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-sr/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ПОТВРДА ИДЕНТИТЕТА НИЈЕ УСПЕЛА -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"НИСТЕ ПРЕТПЛАЋЕНИ НА УСЛУГУ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Није дозвољено више PDN веза за одређени APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-sv/strings.xml b/core/res/res/values-mcc334-mnc020-sv/strings.xml new file mode 100644 index 000000000000..75bc6427cf55 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-sv/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"AUTENTISERINGSFEL -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"PRENUMERERAR INTE PÅ TJÄNSTEN -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Flera PDN-anslutningar för samma APN tillåts inte -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-sw/strings.xml b/core/res/res/values-mcc334-mnc020-sw/strings.xml new file mode 100644 index 000000000000..275f628eab06 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-sw/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"IMESHINDWA KUTHIBITISHA -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"HUJAJISAJILI KWENYE HUDUMA -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Miunganisho mingi ya PDN kwenye APN husika hairuhusiwi -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ta/strings.xml b/core/res/res/values-mcc334-mnc020-ta/strings.xml new file mode 100644 index 000000000000..699ea71f7d8d --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ta/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"அங்கீகரிக்க முடியவில்லை -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"சேவைக்குச் சந்தா பெறவில்லை -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ஒரு APNக்குப் பல PDN இணைப்புகள் அனுமதிக்கப்படாது -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-te/strings.xml b/core/res/res/values-mcc334-mnc020-te/strings.xml new file mode 100644 index 000000000000..eee21aa44677 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-te/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ప్రామాణీకరణ వైఫల్యం -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ఈ సర్వీస్ కోసం సబ్స్క్రయిబ్ చేసుకోలేదు -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ఈ APNలో బహుళ PDN కనెక్షన్లు అనుమతించబడవు -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-th/strings.xml b/core/res/res/values-mcc334-mnc020-th/strings.xml new file mode 100644 index 000000000000..e4e62f0a0417 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-th/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"การตรวจสอบสิทธิ์ล้มเหลว -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"ไม่ได้สมัครใช้บริการ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"ไม่อนุญาตการเชื่อมต่อ PDN หลายรายการสำหรับ APN ที่กำหนด -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-tl/strings.xml b/core/res/res/values-mcc334-mnc020-tl/strings.xml new file mode 100644 index 000000000000..e05ef9ba28c3 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-tl/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"HINDI NA-AUTHENTICATE -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"HINDI NAKA-SUBSCRIBE SA SERBISYO -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Hindi pinapayagan ang maraming PDN na koneksyon para sa isang partikular na APN -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-tr/strings.xml b/core/res/res/values-mcc334-mnc020-tr/strings.xml new file mode 100644 index 000000000000..7c83aeee3d7f --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-tr/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"KİMLİK DOĞRULAMA HATASI -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"HİZMETE ABONE OLUNMADI -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Belirli bir APN için birden fazla PDN bağlantısına izin verilmez -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-uk/strings.xml b/core/res/res/values-mcc334-mnc020-uk/strings.xml new file mode 100644 index 000000000000..dc18a3ed520f --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-uk/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"ПОМИЛКА АВТЕНТИФІКАЦІЇ -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"НЕМАЄ ПІДПИСКИ НА СЕРВІС -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"З цієї APN не можна підключатися до кількох відкритих мереж -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-ur/strings.xml b/core/res/res/values-mcc334-mnc020-ur/strings.xml new file mode 100644 index 000000000000..25b074eec145 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-ur/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <!-- no translation found for config_pdp_reject_user_authentication_failed (4683454131283459978) --> + <skip /> + <!-- no translation found for config_pdp_reject_service_not_subscribed (9021140729932308119) --> + <skip /> + <!-- no translation found for config_pdp_reject_multi_conn_to_same_pdn_not_allowed (3838388706348367865) --> + <skip /> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-uz/strings.xml b/core/res/res/values-mcc334-mnc020-uz/strings.xml new file mode 100644 index 000000000000..321aff2efbd2 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-uz/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"HAQIQIYLIK TEKSHIRUVIDA XATO -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"XIZMATGA OBUNA QILINMAGAN -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"APN uchun bir nechta PDN ulanishiga ruxsat berilmagan -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-vi/strings.xml b/core/res/res/values-mcc334-mnc020-vi/strings.xml new file mode 100644 index 000000000000..bb77bb5298c2 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-vi/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"KHÔNG XÁC THỰC ĐƯỢC -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"CHƯA ĐĂNG KÝ DỊCH VỤ -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Không cho phép có nhiều kết nối PDN với một APN đã cho -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml b/core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml new file mode 100644 index 000000000000..25b074eec145 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-zh-rCN/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <!-- no translation found for config_pdp_reject_user_authentication_failed (4683454131283459978) --> + <skip /> + <!-- no translation found for config_pdp_reject_service_not_subscribed (9021140729932308119) --> + <skip /> + <!-- no translation found for config_pdp_reject_multi_conn_to_same_pdn_not_allowed (3838388706348367865) --> + <skip /> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-zh-rHK/strings.xml b/core/res/res/values-mcc334-mnc020-zh-rHK/strings.xml new file mode 100644 index 000000000000..af2057828128 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-zh-rHK/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"認證錯誤 -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"未訂閱服務 -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"指定的 APN 不允許有多個 PDN 連線 -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-zh-rTW/strings.xml b/core/res/res/values-mcc334-mnc020-zh-rTW/strings.xml new file mode 100644 index 000000000000..2d74d5abfa55 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-zh-rTW/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"驗證失敗 -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"未訂閱服務 -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"指定的 APN 不允許有多個 PDN 連線 -55-"</string> +</resources> diff --git a/core/res/res/values-mcc334-mnc020-zu/strings.xml b/core/res/res/values-mcc334-mnc020-zu/strings.xml new file mode 100644 index 000000000000..ef0f3cbbde89 --- /dev/null +++ b/core/res/res/values-mcc334-mnc020-zu/strings.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/* +** Copyright 2020, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="config_pdp_reject_dialog_title" msgid="41208110171880430"></string> + <string name="config_pdp_reject_user_authentication_failed" msgid="4683454131283459978">"UKWEHLULEKA KOKUFAKAZELA UBUQINISO -29-"</string> + <string name="config_pdp_reject_service_not_subscribed" msgid="9021140729932308119">"AWUBHALISELE ISEVISI -33-"</string> + <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="3838388706348367865">"Uxhumano lwe-PDN oluningi lwe-APN enikeziwe aluvunyelwe -55-"</string> +</resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index eeb2b5760297..4bb06bb0145d 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1040,7 +1040,7 @@ <string name="menu_space_shortcut_label" msgid="5949311515646872071">"स्पेस"</string> <string name="menu_enter_shortcut_label" msgid="6709499510082897320">"एंटर"</string> <string name="menu_delete_shortcut_label" msgid="4365787714477739080">"हटवा"</string> - <string name="search_go" msgid="2141477624421347086">"Search"</string> + <string name="search_go" msgid="2141477624421347086">"शोध"</string> <string name="search_hint" msgid="455364685740251925">"शोधा…"</string> <string name="searchview_description_search" msgid="1045552007537359343">"शोधा"</string> <string name="searchview_description_query" msgid="7430242366971716338">"शोध क्वेरी"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 53eb2b7e87bf..7b80f606c99e 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -2010,7 +2010,7 @@ <string name="app_category_image" msgid="7307840291864213007">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਚਿੱਤਰ"</string> <string name="app_category_social" msgid="2278269325488344054">"ਸਮਾਜਕ ਅਤੇ ਸੰਚਾਰ"</string> <string name="app_category_news" msgid="1172762719574964544">"ਖਬਰਾਂ ਅਤੇ ਰਸਾਲੇ"</string> - <string name="app_category_maps" msgid="6395725487922533156">"ਨਕਸ਼ੇ ਅਤੇ ਆਵਾਗੌਣ"</string> + <string name="app_category_maps" msgid="6395725487922533156">"Maps ਅਤੇ ਨੈਵੀਗੇਸ਼ਨ"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ਉਤਪਾਦਕਤਾ"</string> <string name="app_category_accessibility" msgid="6643521607848547683">"ਪਹੁੰਚਯੋਗਤਾ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"ਡੀਵਾਈਸ ਸਟੋਰੇਜ"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 680fbd2b7a24..0cadb45eb0e5 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -124,7 +124,7 @@ <string name="roamingTextSearching" msgid="5323235489657753486">"సేవ కోసం శోధిస్తోంది"</string> <string name="wfcRegErrorTitle" msgid="3193072971584858020">"Wi‑Fi కాలింగ్ని సెటప్ చేయడం సాధ్యపడలేదు"</string> <string-array name="wfcOperatorErrorAlertMessages"> - <item msgid="468830943567116703">"Wi-Fiతో కాల్స్ను చేయడానికి మరియు మెసేజ్లను పంపించడానికి, మొదట ఈ సేవను సెటప్ చేయాల్సిందిగా మీ క్యారియర్కి చెప్పండి. ఆ తర్వాత సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ని మళ్లీ ఆన్ చేయండి. (లోపం కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item> + <item msgid="468830943567116703">"Wi-Fiతో కాల్స్ను చేయడానికి, మెసేజ్లను పంపించడానికి, ముందుగా ఈ సర్వీస్ను సెటప్ చేయాల్సిందిగా మీ క్యారియర్ను అడగండి. ఆ తర్వాత సెట్టింగ్ల నుండి Wi-Fi కాలింగ్ను మళ్లీ ఆన్ చేయండి. (ఎర్రర్ కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item> </string-array> <string-array name="wfcOperatorErrorNotificationMessages"> <item msgid="4795145070505729156">"మీ క్యారియర్తో Wi‑Fi కాలింగ్ని నమోదు చేయడంలో సమస్య: <xliff:g id="CODE">%1$s</xliff:g>"</item> @@ -306,10 +306,10 @@ <string name="permgroupdesc_contacts" msgid="9163927941244182567">"మీ కాంటాక్ట్లను యాక్సెస్ చేయడానికి"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"లొకేషన్"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర లొకేషన్ను యాక్సెస్ చేయడానికి"</string> - <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string> + <string name="permgrouplab_calendar" msgid="6426860926123033230">"క్యాలెండర్"</string> <string name="permgroupdesc_calendar" msgid="6762751063361489379">"మీ క్యాలెండర్ను యాక్సెస్ చేయడానికి"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> - <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS మెసేజ్లను పంపడం మరియు వీక్షించడం"</string> + <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS మెసేజ్లను పంపడం, వీక్షించడం"</string> <string name="permgrouplab_storage" msgid="1938416135375282333">"ఫైల్స్, మీడియా"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైళ్లను యాక్సెస్ చేయడానికి"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"మైక్రోఫోన్"</string> @@ -356,10 +356,10 @@ <string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"కాల్ను వేరే నంబర్కు దారి మళ్లించే లేదా మొత్తంగా కాల్ను ఆపివేసే ఎంపిక సహాయంతో అవుట్గోయింగ్ కాల్ సమయంలో డయల్ చేయబడుతున్న నంబర్ను చూడటానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"ఫోన్ కాల్స్కు సమాధానమివ్వు"</string> <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్కమింగ్ ఫోన్ కాల్స్కు సమాధానమివ్వడానికి యాప్ను అనుమతిస్తుంది."</string> - <string name="permlab_receiveSms" msgid="505961632050451881">"వచన మెసేజ్లను (SMS) స్వీకరించడం"</string> - <string name="permdesc_receiveSms" msgid="1797345626687832285">"SMS మెసేజ్లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. యాప్ మీ డివైజ్కు పంపబడిన మెసేజ్లను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string> - <string name="permlab_receiveMms" msgid="4000650116674380275">"వచన మెసేజ్లను (MMS) స్వీకరించడం"</string> - <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS మెసేజ్లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. యాప్ మీ డివైజ్కు పంపబడిన మెసేజ్లను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string> + <string name="permlab_receiveSms" msgid="505961632050451881">"టెక్స్ట్ మెసేజ్లను (SMS) స్వీకరించడం"</string> + <string name="permdesc_receiveSms" msgid="1797345626687832285">"SMS మెసేజ్లను స్వీకరించడానికి, ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. మీ డివైజ్కు వచ్చిన మెసేజ్లను మీకు చూపకుండానే యాప్ పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string> + <string name="permlab_receiveMms" msgid="4000650116674380275">"టెక్స్ట్ మెసేజ్లను (MMS) స్వీకరించడం"</string> + <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS మెసేజ్లను స్వీకరించడానికి, ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. మీ డివైజ్కు వచ్చిన మెసేజ్లను మీకు చూపకుండానే యాప్ పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string> <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"సెల్ ప్రసార మెసేజ్లను ఫార్వర్డ్ చేయడం"</string> <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్లను స్వీకరించినప్పుడు, వాటిని ఫార్వర్డ్ చేయడానికి సెల్ ప్రసార మాడ్యూల్కు కట్టుబడి ఉండేందుకు యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string> <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్ను మేనేజ్ చేయి"</string> @@ -368,14 +368,14 @@ <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string> <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"చందా చేయబడిన ఫీడ్లను చదవడం"</string> <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"ప్రస్తుతం సమకాలీకరించిన ఫీడ్ల గురించి వివరాలను పొందడానికి యాప్ను అనుమతిస్తుంది."</string> - <string name="permlab_sendSms" msgid="7757368721742014252">"SMS మెసేజ్లను పంపడం మరియు వీక్షించడం"</string> + <string name="permlab_sendSms" msgid="7757368721742014252">"SMS మెసేజ్లను పంపడం, వీక్షించడం"</string> <string name="permdesc_sendSms" msgid="6757089798435130769">"SMS మెసేజ్లు పంపడానికి యాప్ను అనుమతిస్తుంది. దీని వలన ఊహించని ఛార్జీలు విధించబడవచ్చు. హానికరమైన యాప్లు మీ నిర్ధారణ లేకుండానే మెసేజ్లను పంపడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string> - <string name="permlab_readSms" msgid="5164176626258800297">"మీ వచన మెసేజ్లు (SMS లేదా MMS) చదవడం"</string> - <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ఈ యాప్ మీ టాబ్లెట్లో నిల్వ చేసిన అన్ని SMS (వచన) మెసేజ్లను చదవగలదు."</string> - <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"ఈ యాప్ మీ Android TV పరికరంలో నిల్వ అయిన SMS (వచనం) సందేశాలన్నింటినీ చదవగలదు."</string> - <string name="permdesc_readSms" product="default" msgid="774753371111699782">"ఈ యాప్ మీ ఫోన్లో నిల్వ చేసిన అన్ని SMS (వచన) మెసేజ్లను చదవగలదు."</string> - <string name="permlab_receiveWapPush" msgid="4223747702856929056">"వచన మెసేజ్లను (WAP) స్వీకరించడం"</string> - <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP మెసేజ్లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఈ అనుమతి మీకు పంపబడిన మెసేజ్లను మీకు చూపకుండానే పర్యవేక్షించగల లేదా తొలగించగల సామర్థ్యాన్ని కలిగి ఉంటుంది."</string> + <string name="permlab_readSms" msgid="5164176626258800297">"మీ టెక్స్ట్ మెసేజ్లు (SMS లేదా MMS) చదవడం"</string> + <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ఈ యాప్ మీ టాబ్లెట్లో స్టోర్ చేసిన అన్ని SMS (టెక్స్ట్) మెసేజ్లను చదవగలదు."</string> + <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"ఈ యాప్ మీ Android TV పరికరంలో స్టోర్ అయిన SMS (టెక్స్ట్) మెసేజ్లు అన్నింటిని చదవగలదు."</string> + <string name="permdesc_readSms" product="default" msgid="774753371111699782">"ఈ యాప్ మీ ఫోన్లో నిల్వ చేసిన అన్ని SMS (టెక్స్ట్) మెసేజ్లను చదవగలదు."</string> + <string name="permlab_receiveWapPush" msgid="4223747702856929056">"టెక్స్ట్ మెసేజ్లను (WAP) స్వీకరించడం"</string> + <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP మెసేజ్లను స్వీకరించడానికి, ప్రాసెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఈ అనుమతి మీకు వచ్చిన మెసేజ్లను మీకు చూపకుండానే పర్యవేక్షించగల లేదా తొలగించగల సామర్థ్యాన్ని కలిగి ఉంటుంది."</string> <string name="permlab_getTasks" msgid="7460048811831750262">"అమలవుతున్న యాప్లను పునరుద్ధరించడం"</string> <string name="permdesc_getTasks" msgid="7388138607018233726">"ప్రస్తుతం మరియు ఇటీవల అమలవుతున్న విధుల గురించి వివరణాత్మక సమాచారాన్ని తిరిగి పొందడానికి యాప్ను అనుమతిస్తుంది. ఇది పరికరంలో ఉపయోగించబడిన యాప్ల గురించి సమాచారాన్ని కనుగొనడానికి యాప్ను అనుమతించవచ్చు."</string> <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"ప్రొఫైల్ మరియు పరికర యజమానులను నిర్వహించడం"</string> @@ -431,9 +431,9 @@ <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"ఈ యాప్ మీ Android TV పరికరంలో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్లన్నీ చదవగలదు, మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string> <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"ఈ యాప్ మీ ఫోన్లో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్లన్నీ చదవగలదు మరియు మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string> <string name="permlab_writeCalendar" msgid="6422137308329578076">"యజమానికి తెలియకుండానే క్యాలెండర్ ఈవెంట్లను జోడించి లేదా సవరించి, అతిథులకు ఇమెయిల్ పంపడం"</string> - <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string> - <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string> - <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string> + <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ ఓనర్ల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి ఓనర్లకు తెలియకుండానే మార్చగలదు."</string> + <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ ఓనర్ల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి ఓనర్లకు తెలియకుండానే మార్చగలదు."</string> + <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ ఓనర్ల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు, లేదా ఈవెంట్లను వాటి ఓనర్లకు తెలియకుండానే మార్చగలదు."</string> <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"అదనపు లొకేషన్ ప్రొవైడర్ కమాండ్లను యాక్సెస్ చేయడం"</string> <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"అదనపు లొకేషన్ ప్రొవైడర్ కమాండ్లను యాక్సెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర లొకేషన్ సోర్స్ల నిర్వహణలో యాప్ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string> <string name="permlab_accessFineLocation" msgid="6426318438195622966">"స్క్రీన్పై ఉన్నప్పుడు మాత్రమే ఖచ్చితమైన లొకేషన్ను యాక్సెస్ చేయండి"</string> @@ -817,7 +817,7 @@ <string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string> <string name="phoneTypeWorkMobile" msgid="7522314392003565121">"కార్యాలయ మొబైల్"</string> <string name="phoneTypeWorkPager" msgid="3748332310638505234">"కార్యాలయ పేజర్"</string> - <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string> + <string name="phoneTypeAssistant" msgid="757550783842231039">"అసిస్టెంట్"</string> <string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string> <string name="eventTypeCustom" msgid="3257367158986466481">"అనుకూలం"</string> <string name="eventTypeBirthday" msgid="7770026752793912283">"పుట్టినరోజు"</string> @@ -850,7 +850,7 @@ <string name="orgTypeOther" msgid="5450675258408005553">"ఇతరం"</string> <string name="orgTypeCustom" msgid="1126322047677329218">"అనుకూలం"</string> <string name="relationTypeCustom" msgid="282938315217441351">"అనుకూలం"</string> - <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string> + <string name="relationTypeAssistant" msgid="4057605157116589315">"అసిస్టెంట్"</string> <string name="relationTypeBrother" msgid="7141662427379247820">"సోదరుడు"</string> <string name="relationTypeChild" msgid="9076258911292693601">"బిడ్డ"</string> <string name="relationTypeDomesticPartner" msgid="7825306887697559238">"జీవిత భాగస్వామి"</string> @@ -1014,7 +1014,7 @@ <string name="permlab_setAlarm" msgid="1158001610254173567">"అలారం సెట్ చేయడం"</string> <string name="permdesc_setAlarm" msgid="2185033720060109640">"ఇన్స్టాల్ చేయబడిన అలారం గడియారం యాప్లో అలారంను సెట్ చేయడానికి యాప్ను అనుమతిస్తుంది. కొన్ని అలారం గల గడియారం యాప్లు ఈ ఫీచర్ను అమలు చేయకపోవచ్చు."</string> <string name="permlab_addVoicemail" msgid="4770245808840814471">"వాయిస్ మెయిల్ను జోడించడం"</string> - <string name="permdesc_addVoicemail" msgid="5470312139820074324">"మీ వాయిస్ మెయిల్ ఇన్బాక్స్కి మెసేజ్లను జోడించడానికి యాప్ను అనుమతిస్తుంది."</string> + <string name="permdesc_addVoicemail" msgid="5470312139820074324">"మీ వాయిస్ మెయిల్ ఇన్బాక్స్కు మెసేజ్లను జోడించడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"బ్రౌజర్ భౌగోళిక స్థానం అనుమతులను సవరించడం"</string> <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"బ్రౌజర్ యొక్క భౌగోళిక లొకేషన్ అనుమతులను సవరించడానికి యాప్ను అనుమతిస్తుంది. హానికరమైన యాప్లు ఏకపక్ష వెబ్ సైట్లకు లొకేషన్ సమాచారాన్ని అనుమతించడానికి దీన్ని ఉపయోగించవచ్చు."</string> <string name="save_password_message" msgid="2146409467245462965">"మీరు బ్రౌజర్ ఈ పాస్వర్డ్ను గుర్తుపెట్టుకోవాలని కోరుకుంటున్నారా?"</string> @@ -1043,7 +1043,7 @@ <string name="search_go" msgid="2141477624421347086">"సెర్చ్"</string> <string name="search_hint" msgid="455364685740251925">"సెర్చ్ చేయండి..."</string> <string name="searchview_description_search" msgid="1045552007537359343">"సెర్చ్"</string> - <string name="searchview_description_query" msgid="7430242366971716338">"ప్రశ్నను వెతకండి"</string> + <string name="searchview_description_query" msgid="7430242366971716338">"సెర్చ్ క్వెరీ"</string> <string name="searchview_description_clear" msgid="1989371719192982900">"ప్రశ్నను క్లియర్ చేయి"</string> <string name="searchview_description_submit" msgid="6771060386117334686">"ప్రశ్నని సమర్పించండి"</string> <string name="searchview_description_voice" msgid="42360159504884679">"వాయిస్ సెర్చ్"</string> @@ -1412,7 +1412,7 @@ <string name="ext_media_new_notification_message" msgid="6095403121990786986">"సెటప్ చేయడానికి నొక్కండి"</string> <string name="ext_media_new_notification_message" product="tv" msgid="216863352100263668">"సెటప్ చేయడానికి ఎంచుకోండి"</string> <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"మీరు పరికరాన్ని తిరిగి ఫార్మాట్ చేయాల్సి ఉంటుంది. తొలగించడానికి ట్యాప్ చేయండి"</string> - <string name="ext_media_ready_notification_message" msgid="777258143284919261">"ఫోటోలు మరియు మీడియాను బదిలీ చేయడానికి"</string> + <string name="ext_media_ready_notification_message" msgid="777258143284919261">"ఫోటోలు, మీడియాను బదిలీ చేయడానికి"</string> <string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"మీడియా ఫైల్స్ను బ్రౌజ్ చేయండి"</string> <string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"<xliff:g id="NAME">%s</xliff:g>తో సమస్య ఉంది"</string> <string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> పని చేయటం లేదు"</string> @@ -1524,7 +1524,7 @@ <string name="progress_erasing" msgid="6891435992721028004">"షేర్ చేసిన నిల్వను తొలగిస్తోంది…"</string> <string name="share" msgid="4157615043345227321">"షేర్"</string> <string name="find" msgid="5015737188624767706">"కనుగొనండి"</string> - <string name="websearch" msgid="5624340204512793290">"వెబ్ శోధన"</string> + <string name="websearch" msgid="5624340204512793290">"వెబ్ సెర్చ్"</string> <string name="find_next" msgid="5341217051549648153">"తదుపరిదాన్ని కనుగొను"</string> <string name="find_previous" msgid="4405898398141275532">"మునుపటిదాన్ని కనుగొను"</string> <string name="gpsNotifTicker" msgid="3207361857637620780">"<xliff:g id="NAME">%s</xliff:g> నుండి లొకేషన్ రిక్వెస్ట్"</string> @@ -2010,7 +2010,7 @@ <string name="app_category_image" msgid="7307840291864213007">"ఫోటోలు, ఇమేజ్లు"</string> <string name="app_category_social" msgid="2278269325488344054">"సామాజికం & కమ్యూనికేషన్"</string> <string name="app_category_news" msgid="1172762719574964544">"వార్తలు & వార్తాపత్రికలు"</string> - <string name="app_category_maps" msgid="6395725487922533156">"Maps & నావిగేషన్"</string> + <string name="app_category_maps" msgid="6395725487922533156">"మ్యాప్స్ & నావిగేషన్"</string> <string name="app_category_productivity" msgid="1844422703029557883">"ఉత్పాదకత"</string> <string name="app_category_accessibility" msgid="6643521607848547683">"యాక్సెసిబిలిటీ"</string> <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"పరికర నిల్వ"</string> @@ -2055,7 +2055,7 @@ <string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string> <string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"వెంటనే తీర ప్రాంతాలు మరియు నదీ పరీవాహక ప్రాంతాలను ఖాళీ చేసి మెట్ట ప్రాంతాలకు తరలి వెళ్లండి."</string> <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string> - <string name="etws_primary_default_message_test" msgid="4583367373909549421">"అత్యవసర మెసేజ్ల పరీక్ష"</string> + <string name="etws_primary_default_message_test" msgid="4583367373909549421">"అత్యవసర మెసేజ్ల టెస్ట్"</string> <string name="notification_reply_button_accessibility" msgid="5235776156579456126">"రిప్లయి పంపండి"</string> <string name="etws_primary_default_message_others" msgid="7958161706019130739"></string> <string name="mmcc_authentication_reject" msgid="4891965994643876369">"వాయిస్ కోసం SIM అనుమతించబడదు"</string> @@ -2101,7 +2101,7 @@ <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"సరే"</string> <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ఆఫ్ చేయండి"</string> <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"మరింత తెలుసుకోండి"</string> - <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్లను, మెరుగైన నోటిఫికేషన్లు భర్తీ చేశాయి. సూచించిన చర్యలు, రిప్లయిలను ఈ ఫీచర్ చూపించి, మీ నోటిఫికేషన్లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్లు లాంటి వ్యక్తిగత సమాచారంతో సహా నోటిఫికేషన్ కంటెంట్ను మెరుగైన నోటిఫికేషన్లు యాక్సెస్ చేయవచ్చు. ఫోన్ కాల్స్కు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్ను కంట్రోల్ చేయడం లాంటి నోటిఫికేషన్లను విస్మరించడం లేదా ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string> + <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్లను, మెరుగైన నోటిఫికేషన్లు రీప్లేస్ చేశాయి. ఈ ఫీచర్, సూచించిన చర్యలను, రిప్లయిలను చూపించి, మీ నోటిఫికేషన్లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్లు లాంటి వ్యక్తిగత సమాచారంతో పాటు నోటిఫికేషన్ కంటెంట్ను మెరుగైన నోటిఫికేషన్లు యాక్సెస్ చేస్తాయి. ఫోన్ కాల్స్కు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్ను కంట్రోల్ చేయడం వంటి నోటిఫికేషన్లను విస్మరించడం లేదా వాటికి ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string> <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"మామూలుగా ఛార్జ్ చేసేలోపు బ్యాటరీ ఖాళీ కావచ్చు"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి బ్యాటరీ సేవర్ యాక్టివేట్ చేయబడింది"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 53396407904a..77820d1dfa38 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8372,8 +8372,8 @@ <attr name="supportsAmbientMode" format="boolean" /> <!-- Indicates that this wallpaper service should receive zoom transition updates when - changing the device state (e.g. when folding or unfolding a foldable device). - When this value is set to true + changing the display state of the device (e.g. when folding or unfolding + a foldable device). When this value is set to true {@link android.service.wallpaper.WallpaperService.Engine} could receive zoom updates before or after changing the device state. Wallpapers receive zoom updates using {@link android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)} and @@ -8381,8 +8381,8 @@ {@link android.service.wallpaper.WallpaperService.Engine} is created and not destroyed. Default value is true. Corresponds to - {@link android.app.WallpaperInfo#shouldUseDefaultDeviceStateChangeTransition()} --> - <attr name="shouldUseDefaultDeviceStateChangeTransition" format="boolean" /> + {@link android.app.WallpaperInfo#shouldUseDefaultDisplayStateChangeTransition()} --> + <attr name="shouldUseDefaultDisplayStateChangeTransition" format="boolean" /> <!-- Uri that specifies a settings Slice for this wallpaper. --> <attr name="settingsSliceUri" format="string"/> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index b191584345ef..59d6005ba193 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -246,37 +246,37 @@ <!-- Lightest shade of the accent color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_0">#ffffff</color> - <!-- Shade of the accent system color at 99% lightness. + <!-- Shade of the accent system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_10">#F9FCFF</color> - <!-- Shade of the accent system color at 95% lightness. + <!-- Shade of the accent system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_50">#E0F3FF</color> - <!-- Shade of the accent system color at 90% lightness. + <!-- Shade of the accent system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_100">#C1E8FF</color> - <!-- Shade of the accent system color at 80% lightness. + <!-- Shade of the accent system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_200">#76D1FF</color> - <!-- Shade of the accent system color at 70% lightness. + <!-- Shade of the accent system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_300">#4BB6E8</color> - <!-- Shade of the accent system color at 60% lightness. + <!-- Shade of the accent system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_400">#219BCC</color> - <!-- Shade of the accent system color at 49% lightness. + <!-- Shade of the accent system color at 49.6% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_500">#007FAC</color> - <!-- Shade of the accent system color at 40% lightness. + <!-- Shade of the accent system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_600">#00668B</color> - <!-- Shade of the accent system color at 30% lightness. + <!-- Shade of the accent system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_700">#004C69</color> - <!-- Shade of the accent system color at 20% lightness. + <!-- Shade of the accent system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_800">#003549</color> - <!-- Shade of the accent system color at 10% lightness. + <!-- Shade of the accent system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent1_900">#001E2C</color> <!-- Darkest shade of the accent color used by the system. Black. @@ -286,37 +286,37 @@ <!-- Lightest shade of the secondary accent color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_0">#ffffff</color> - <!-- Shade of the secondary accent system color at 99% lightness. + <!-- Shade of the secondary accent system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_10">#F9FCFF</color> - <!-- Shade of the secondary accent system color at 95% lightness. + <!-- Shade of the secondary accent system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_50">#E0F3FF</color> - <!-- Shade of the secondary accent system color at 90% lightness. + <!-- Shade of the secondary accent system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_100">#D1E5F4</color> - <!-- Shade of the secondary accent system color at 80% lightness. + <!-- Shade of the secondary accent system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_200">#B5CAD7</color> - <!-- Shade of the secondary accent system color at 70% lightness. + <!-- Shade of the secondary accent system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_300">#9AAEBB</color> - <!-- Shade of the secondary accent system color at 60% lightness. + <!-- Shade of the secondary accent system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_400">#8094A0</color> - <!-- Shade of the secondary accent system color at 49% lightness. + <!-- Shade of the secondary accent system color at 49.6% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_500">#657985</color> - <!-- Shade of the secondary accent system color at 40% lightness. + <!-- Shade of the secondary accent system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_600">#4E616C</color> - <!-- Shade of the secondary accent system color at 30% lightness. + <!-- Shade of the secondary accent system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_700">#374955</color> - <!-- Shade of the secondary accent system color at 20% lightness. + <!-- Shade of the secondary accent system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_800">#20333D</color> - <!-- Shade of the secondary accent system color at 10% lightness. + <!-- Shade of the secondary accent system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent2_900">#091E28</color> <!-- Darkest shade of the secondary accent color used by the system. Black. @@ -326,37 +326,37 @@ <!-- Lightest shade of the tertiary accent color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_0">#ffffff</color> - <!-- Shade of the tertiary accent system color at 99% lightness. + <!-- Shade of the tertiary accent system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_10">#FFFBFF</color> - <!-- Shade of the tertiary accent system color at 95% lightness. + <!-- Shade of the tertiary accent system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_50">#F5EEFF</color> - <!-- Shade of the tertiary accent system color at 90% lightness. + <!-- Shade of the tertiary accent system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_100">#E6DEFF</color> - <!-- Shade of the tertiary accent system color at 80% lightness. + <!-- Shade of the tertiary accent system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_200">#CAC1EA</color> - <!-- Shade of the tertiary accent system color at 70% lightness. + <!-- Shade of the tertiary accent system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_300">#AEA6CE</color> - <!-- Shade of the tertiary accent system color at 60% lightness. + <!-- Shade of the tertiary accent system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_400">#938CB1</color> - <!-- Shade of the tertiary accent system color at 49% lightness. + <!-- Shade of the tertiary accent system color at 49% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_500">#787296</color> - <!-- Shade of the tertiary accent system color at 40% lightness. + <!-- Shade of the tertiary accent system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_600">#605A7C</color> - <!-- Shade of the tertiary accent system color at 30% lightness. + <!-- Shade of the tertiary accent system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_700">#484264</color> - <!-- Shade of the tertiary accent system color at 20% lightness. + <!-- Shade of the tertiary accent system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_800">#322C4C</color> - <!-- Shade of the tertiary accent system color at 10% lightness. + <!-- Shade of the tertiary accent system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_accent3_900">#1D1736</color> <!-- Darkest shade of the tertiary accent color used by the system. Black. @@ -366,37 +366,37 @@ <!-- Lightest shade of the neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_0">#ffffff</color> - <!-- Shade of the neutral system color at 99% lightness. + <!-- Shade of the neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_10">#FCFCFF</color> - <!-- Shade of the neutral system color at 95% lightness. + <!-- Shade of the neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_50">#F0F0F3</color> - <!-- Shade of the neutral system color at 90% lightness. + <!-- Shade of the neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_100">#E1E3E5</color> - <!-- Shade of the neutral system color at 80% lightness. + <!-- Shade of the neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_200">#C5C7C9</color> - <!-- Shade of the neutral system color at 70% lightness. + <!-- Shade of the neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_300">#AAABAE</color> - <!-- Shade of the neutral system color at 60% lightness. + <!-- Shade of the neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_400">#8F9193</color> - <!-- Shade of the neutral system color at 49% lightness. + <!-- Shade of the neutral system color at 49% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_500">#747679</color> - <!-- Shade of the neutral system color at 40% lightness. + <!-- Shade of the neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_600">#5C5F61</color> - <!-- Shade of the neutral system color at 30% lightness. + <!-- Shade of the neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_700">#454749</color> - <!-- Shade of the neutral system color at 20% lightness. + <!-- Shade of the neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_800">#2E3133</color> - <!-- Shade of the neutral system color at 10% lightness. + <!-- Shade of the neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral1_900">#191C1E</color> <!-- Darkest shade of the neutral color used by the system. Black. @@ -406,37 +406,37 @@ <!-- Lightest shade of the secondary neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_0">#ffffff</color> - <!-- Shade of the secondary neutral system color at 99% lightness. + <!-- Shade of the secondary neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_10">#F9FCFF</color> - <!-- Shade of the secondary neutral system color at 95% lightness. + <!-- Shade of the secondary neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_50">#EBF1F8</color> - <!-- Shade of the secondary neutral system color at 90% lightness. + <!-- Shade of the secondary neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_100">#DCE3E9</color> - <!-- Shade of the secondary neutral system color at 80% lightness. + <!-- Shade of the secondary neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_200">#C0C7CD</color> - <!-- Shade of the secondary neutral system color at 70% lightness. + <!-- Shade of the secondary neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_300">#A5ACB2</color> - <!-- Shade of the secondary neutral system color at 60% lightness. + <!-- Shade of the secondary neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_400">#8A9297</color> - <!-- Shade of the secondary neutral system color at 49% lightness. + <!-- Shade of the secondary neutral system color at 49% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_500">#70777C</color> - <!-- Shade of the secondary neutral system color at 40% lightness. + <!-- Shade of the secondary neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_600">#585F65</color> - <!-- Shade of the secondary neutral system color at 30% lightness. + <!-- Shade of the secondary neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_700">#40484D</color> - <!-- Shade of the secondary neutral system color at 20% lightness. + <!-- Shade of the secondary neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_800">#2A3136</color> - <!-- Shade of the secondary neutral system color at 10% lightness. + <!-- Shade of the secondary neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs. --> <color name="system_neutral2_900">#161C20</color> <!-- Darkest shade of the secondary neutral color used by the system. Black. diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index cbe0eef6408b..ddc9f0225025 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2323,6 +2323,15 @@ <!-- Type of the tap sensor. Empty if tap is not supported. --> <string name="config_dozeTapSensorType" translatable="false"></string> + <!-- Type of the ambient tap sensor per device posture (defined by WM Jetpack posture). + Unspecified values use config_dozeTapSensor --> + <string-array name="config_dozeTapSensorPostureMapping" translatable="false"> + <item></item> <!-- UNKNOWN --> + <item></item> <!-- CLOSED --> + <item></item> <!-- HALF_OPENED --> + <item></item> <!-- OPENED --> + </string-array> + <!-- Type of the long press sensor. Empty if long press is not supported. --> <string name="config_dozeLongPressSensorType" translatable="false"></string> @@ -4533,6 +4542,13 @@ If non-positive, then the refresh rate is unchanged even if thresholds are configured. --> <integer name="config_fixedRefreshRateInHighZone">0</integer> + <!-- Default refresh rate while the device has high brightness mode enabled for Sunlight. + This value overrides values from DisplayDeviceConfig --> + <integer name="config_defaultRefreshRateInHbmSunlight">0</integer> + + <!-- Default refresh rate while the device has high brightness mode enabled for HDR. --> + <integer name="config_defaultRefreshRateInHbmHdr">0</integer> + <!-- The type of the light sensor to be used by the display framework for things like auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. --> <string name="config_displayLightSensorType" translatable="false" /> @@ -4908,16 +4924,15 @@ device orientation. --> <bool name="config_letterboxIsReachabilityEnabled">false</bool> - <!-- Default horizonal position of a center of the letterboxed app window when reachability is - enabled and an app is fullscreen in landscape device orientation. - 0 corresponds to the left side of the screen and 1 to the right side. If given value < 0.0 - or > 1, it is ignored and right positionis used (1.0). The position multiplier is changed - to a symmetrical value computed as (1 - current multiplier) after each double tap in the - letterbox area. --> - <item name="config_letterboxDefaultPositionMultiplierForReachability" - format="float" type="dimen"> - 0.9 - </item> + <!-- Default horizonal position of the letterboxed app window when reachability is + enabled and an app is fullscreen in landscape device orientation. When reachability is + enabled, the position can change between left, center and right. This config defines the + default one: + - Option 0 - Left. + - Option 1 - Center. + - Option 2 - Right. + If given value is outside of this range, the option 1 (center) is assummed. --> + <integer name="config_letterboxDefaultPositionForReachability">1</integer> <!-- If true, hide the display cutout with display area --> <bool name="config_hideDisplayCutoutWithDisplayArea">false</bool> @@ -5260,4 +5275,9 @@ <item>@dimen/rounded_corner_radius_bottom_adjustment</item> <item>@dimen/secondary_rounded_corner_radius_bottom_adjustment</item> </array> + + <!-- Shape of the work badge icon for viewport size 24. --> + <string name="config_work_badge_path_24" translatable="false"> + M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2z + </string> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 9ed4e65f7c91..ab923d0b8023 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -60,6 +60,9 @@ <!-- How much we expand the touchable region of the status bar below the notch to catch touches that just start below the notch. --> <dimen name="display_cutout_touchable_region_size">12dp</dimen> + <!-- The default margin used in immersive mode to capture the start of a swipe gesture from the + edge of the screen to show the system bars. --> + <dimen name="system_gestures_start_threshold">24dp</dimen> <!-- Height of the bottom navigation bar frame; this is different than navigation_bar_height where that is the height reported to all the other windows to resize themselves around the diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index e17daf09e4da..462b1883e29d 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3221,7 +3221,7 @@ <eat-comment /> <staging-public-group type="attr" first-id="0x01ff0000"> - <public name="shouldUseDefaultDeviceStateChangeTransition" /> + <public name="shouldUseDefaultDisplayStateChangeTransition" /> </staging-public-group> <staging-public-group type="id" first-id="0x01fe0000"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index fbc629e2dc81..758990df7159 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1745,6 +1745,7 @@ <java-symbol type="dimen" name="taskbar_frame_height" /> <java-symbol type="dimen" name="status_bar_height" /> <java-symbol type="dimen" name="display_cutout_touchable_region_size" /> + <java-symbol type="dimen" name="system_gestures_start_threshold" /> <java-symbol type="dimen" name="quick_qs_offset_height" /> <java-symbol type="drawable" name="ic_jog_dial_sound_off" /> <java-symbol type="drawable" name="ic_jog_dial_sound_on" /> @@ -3255,6 +3256,7 @@ <java-symbol type="string" name="config_dozeDoubleTapSensorType" /> <java-symbol type="string" name="config_dozeTapSensorType" /> + <java-symbol type="array" name="config_dozeTapSensorPostureMapping" /> <java-symbol type="bool" name="config_dozePulsePickup" /> <!-- Used for MimeIconUtils. --> @@ -3964,6 +3966,8 @@ <java-symbol type="integer" name="config_defaultRefreshRateInZone" /> <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" /> <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" /> + <java-symbol type="integer" name="config_defaultRefreshRateInHbmSunlight" /> + <java-symbol type="integer" name="config_defaultRefreshRateInHbmHdr" /> <!-- For fixed refresh rate displays in high brightness--> <java-symbol type="integer" name="config_fixedRefreshRateInHighZone" /> @@ -4260,7 +4264,7 @@ <java-symbol type="color" name="config_letterboxBackgroundColor" /> <java-symbol type="dimen" name="config_letterboxHorizontalPositionMultiplier" /> <java-symbol type="bool" name="config_letterboxIsReachabilityEnabled" /> - <java-symbol type="dimen" name="config_letterboxDefaultPositionMultiplierForReachability" /> + <java-symbol type="integer" name="config_letterboxDefaultPositionForReachability" /> <java-symbol type="bool" name="config_hideDisplayCutoutWithDisplayArea" /> diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index 50639be57f22..3e261a7113ac 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -157,7 +157,7 @@ public class ObjectPoolTests { .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList()) .setIsForward(true).setAssistToken(assistToken) .setShareableActivityToken(shareableActivityToken) - .setTaskFragmentToken(new Binder()).build(); + .build(); LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build(); LaunchActivityItem item = itemSupplier.get(); diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java index 1173c9210ed5..75da0bfba581 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java +++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java @@ -112,7 +112,6 @@ class TestUtils { private IBinder mShareableActivityToken; private FixedRotationAdjustments mFixedRotationAdjustments; private boolean mLaunchedFromBubble; - private IBinder mTaskFragmentToken; LaunchActivityItemBuilder setIntent(Intent intent) { mIntent = intent; @@ -214,18 +213,13 @@ class TestUtils { return this; } - LaunchActivityItemBuilder setTaskFragmentToken(IBinder taskFragmentToken) { - mTaskFragmentToken = taskFragmentToken; - return this; - } - LaunchActivityItem build() { return LaunchActivityItem.obtain(mIntent, mIdent, mInfo, mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */, mFixedRotationAdjustments, - mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken); + mShareableActivityToken, mLaunchedFromBubble); } } } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index 98c9afd2eb6b..df0c64c810c6 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -209,7 +209,6 @@ public class TransactionParcelTests { .setPendingNewIntents(referrerIntentList()).setIsForward(true) .setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments) .setShareableActivityToken(new Binder()) - .setTaskFragmentToken(new Binder()) .build(); writeAndPrepareForReading(item); diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 516a5d288c0f..269d8424a78f 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -299,7 +299,7 @@ public class ActivityThreadClientTest { null /* activityOptions */, true /* isForward */, null /* profilerInfo */, mThread /* client */, null /* asssitToken */, null /* fixedRotationAdjustments */, null /* shareableActivityToken */, - false /* launchedFromBubble */, null /* taskfragmentToken */); + false /* launchedFromBubble */); } @Override diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 791aeb73ffa3..909ca3988c5d 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -3505,6 +3505,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "1805116444": { + "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.", + "level": "ERROR", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, "1810019902": { "message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", "level": "DEBUG", diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index e1c8b11a835c..42b438041d7a 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -172,7 +172,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen void handleActivityCreated(@NonNull Activity launchedActivity) { final List<EmbeddingRule> splitRules = getSplitRules(); final TaskFragmentContainer currentContainer = getContainerWithActivity( - launchedActivity.getActivityToken(), launchedActivity); + launchedActivity.getActivityToken()); // Check if the activity is configured to always be expanded. if (shouldExpand(launchedActivity, null, splitRules)) { @@ -262,29 +262,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Nullable TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) { - return getContainerWithActivity(activityToken, null /* activityToAdd */); - } - - /** - * This method can only be called from {@link #onActivityCreated(Activity)}, use - * {@link #getContainerWithActivity(IBinder) } otherwise. - * - * Returns a container that this activity is registered with. The activity could be created - * before the container appeared, adding the activity to the container if so. - */ - @Nullable - private TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken, - Activity activityToAdd) { - final IBinder taskFragmentToken = ActivityThread.currentActivityThread().getActivityClient( - activityToken).mInitialTaskFragmentToken; for (TaskFragmentContainer container : mContainers) { if (container.hasActivity(activityToken)) { return container; - } else if (container.getTaskFragmentToken().equals(taskFragmentToken)) { - if (activityToAdd != null) { - container.addPendingAppearedActivity(activityToAdd); - } - return container; } } diff --git a/libs/WindowManager/Shell/res/layout/split_outline.xml b/libs/WindowManager/Shell/res/layout/split_outline.xml index 4e2a77f213a0..13a30f5a0423 100644 --- a/libs/WindowManager/Shell/res/layout/split_outline.xml +++ b/libs/WindowManager/Shell/res/layout/split_outline.xml @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.wm.shell.splitscreen.OutlineRoot +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> @@ -23,4 +23,4 @@ android:layout_height="match_parent" android:layout_width="match_parent" /> -</com.android.wm.shell.splitscreen.OutlineRoot> +</FrameLayout> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index d3265346036a..d925a9218a77 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -233,14 +233,14 @@ public class ShellTaskOrganizer extends TaskOrganizer implements + " already exists"); } mTaskListeners.put(listenerType, listener); + } - // Notify the listener of all existing tasks with the given type. - for (int i = mTasks.size() - 1; i >= 0; --i) { - final TaskAppearedInfo data = mTasks.valueAt(i); - final TaskListener taskListener = getTaskListener(data.getTaskInfo()); - if (taskListener != listener) continue; - listener.onTaskAppeared(data.getTaskInfo(), data.getLeash()); - } + // Notify the listener of all existing tasks with the given type. + for (int i = mTasks.size() - 1; i >= 0; --i) { + final TaskAppearedInfo data = mTasks.valueAt(i); + final TaskListener taskListener = getTaskListener(data.getTaskInfo()); + if (taskListener != listener) continue; + listener.onTaskAppeared(data.getTaskInfo(), data.getLeash()); } } } @@ -266,8 +266,12 @@ public class ShellTaskOrganizer extends TaskOrganizer implements tasks.add(data); } - // Remove listener - mTaskListeners.removeAt(index); + // Remove listener, there can be the multiple occurrences, so search the whole list. + for (int i = mTaskListeners.size() - 1; i >= 0; --i) { + if (mTaskListeners.valueAt(i) == listener) { + mTaskListeners.removeAt(i); + } + } // Associate tasks with new listeners if needed. for (int i = tasks.size() - 1; i >= 0; --i) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java index c2cb72a530a3..10d7725b6184 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java @@ -27,7 +27,6 @@ import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_UNDEF import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; import android.app.ActivityManager; -import android.graphics.Rect; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.window.WindowContainerToken; @@ -40,6 +39,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.SurfaceUtils; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.split.SplitLayout; @@ -69,6 +69,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou private final SyncTransactionQueue mSyncQueue; private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; + private final DisplayInsetsController mDisplayInsetsController; private SplitLayout mSplitLayout; private final SplitWindowManager.ParentContainerCallbacks mParentContainerCallbacks = @@ -80,7 +81,12 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou @Override public void onLeashReady(SurfaceControl leash) { - mSyncQueue.runInSync(t -> t.show(leash)); + mSyncQueue.runInSync(t -> t + .show(leash) + .setLayer(leash, SPLIT_DIVIDER_LAYER) + .setPosition(leash, + mSplitLayout.getDividerBounds().left, + mSplitLayout.getDividerBounds().top)); } }; @@ -89,6 +95,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou mSyncQueue = controller.getSyncTransactionQueue(); mDisplayController = controller.getDisplayController(); mDisplayImeController = controller.getDisplayImeController(); + mDisplayInsetsController = controller.getDisplayInsetsController(); } int getRootTaskId() { @@ -125,6 +132,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou mDisplayController.getDisplayContext(mRootTaskInfo.displayId), mRootTaskInfo.configuration, this /* layoutChangeListener */, mParentContainerCallbacks, mDisplayImeController, mController.getTaskOrganizer()); + mDisplayInsetsController.addInsetsChangedListener(mRootTaskInfo.displayId, mSplitLayout); final WindowContainerToken token1 = task1.token; final WindowContainerToken token2 = task2.token; @@ -190,22 +198,17 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou if (mTaskLeash1 == null || mTaskLeash2 == null) return; mSplitLayout.init(); - final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); - final Rect dividerBounds = mSplitLayout.getDividerBounds(); - - // TODO: Is there more we need to do here? - mSyncQueue.runInSync(t -> { - t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER) - .setPosition(mTaskLeash1, mTaskInfo1.positionInParent.x, - mTaskInfo1.positionInParent.y) - .setPosition(mTaskLeash2, mTaskInfo2.positionInParent.x, - mTaskInfo2.positionInParent.y) - .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) - .show(dividerLeash) - .show(mRootTaskLeash) - .show(mTaskLeash1) - .show(mTaskLeash2); - }); + + mSyncQueue.runInSync(t -> t + .show(mRootTaskLeash) + .show(mTaskLeash1) + .show(mTaskLeash2) + .setPosition(mTaskLeash1, + mTaskInfo1.positionInParent.x, + mTaskInfo1.positionInParent.y) + .setPosition(mTaskLeash2, + mTaskInfo2.positionInParent.x, + mTaskInfo2.positionInParent.y)); } @Override @@ -227,10 +230,9 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou } mRootTaskInfo = taskInfo; - if (mSplitLayout != null) { - if (mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) { - onLayoutChanged(mSplitLayout); - } + if (mSplitLayout != null + && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) { + onLayoutChanged(mSplitLayout); } } else if (taskInfo.taskId == getTaskId1()) { mTaskInfo1 = taskInfo; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java index b159333e9a0e..53234ab971d6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPairsController.java @@ -29,6 +29,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; @@ -50,14 +51,17 @@ public class AppPairsController { private final SparseArray<AppPair> mActiveAppPairs = new SparseArray<>(); private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; + private final DisplayInsetsController mDisplayInsetsController; public AppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue, DisplayController displayController, ShellExecutor mainExecutor, - DisplayImeController displayImeController) { + DisplayImeController displayImeController, + DisplayInsetsController displayInsetsController) { mTaskOrganizer = organizer; mSyncQueue = syncQueue; mDisplayController = displayController; mDisplayImeController = displayImeController; + mDisplayInsetsController = displayInsetsController; mMainExecutor = mainExecutor; } @@ -148,6 +152,10 @@ public class AppPairsController { return mDisplayImeController; } + DisplayInsetsController getDisplayInsetsController() { + return mDisplayInsetsController; + } + public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; final String childPrefix = innerPrefix + " "; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 1c308a3daf34..596a2f4467c3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -189,24 +189,28 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange final int rotation = configuration.windowConfiguration.getRotation(); final Rect rootBounds = configuration.windowConfiguration.getBounds(); final int orientation = configuration.orientation; - if (rotation != mRotation || !mRootBounds.equals(rootBounds) - || orientation != mOrientation) { - mContext = mContext.createConfigurationContext(configuration); - mSplitWindowManager.setConfiguration(configuration); - mOrientation = orientation; - mTempRect.set(mRootBounds); - mRootBounds.set(rootBounds); - mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); - initDividerPosition(mTempRect); - affectsLayout = true; + + if (mOrientation == orientation + && rotation == mRotation + && mRootBounds.equals(rootBounds)) { + return false; } + mContext = mContext.createConfigurationContext(configuration); + mSplitWindowManager.setConfiguration(configuration); + mOrientation = orientation; + mTempRect.set(mRootBounds); + mRootBounds.set(rootBounds); + mRotation = rotation; + mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds); + initDividerPosition(mTempRect); + if (mInitialized) { release(); init(); } - return affectsLayout; + return true; } private void initDividerPosition(Rect oldBounds) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 3ab062499845..38079aff9a6f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -537,6 +537,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( mContext.getContentResolver(), mUserId); setSwipeToNotificationEnabled(enabled); + notifyShortcutStateChanged(mState.getState()); mOneHandedUiEventLogger.writeEvent(enabled ? OneHandedUiEventLogger.EVENT_ONE_HANDED_SETTINGS_SHOW_NOTIFICATION_ENABLED_ON diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java index 0b763f2d05f7..a459c8dbfa34 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineManager.java @@ -22,19 +22,23 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Binder; import android.view.IWindow; +import android.view.InsetsSource; +import android.view.InsetsState; import android.view.LayoutInflater; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; -import android.view.WindowInsets; +import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager; -import android.view.WindowMetrics; import android.view.WindowlessWindowManager; +import android.widget.FrameLayout; import com.android.wm.shell.R; @@ -45,17 +49,22 @@ import com.android.wm.shell.R; class OutlineManager extends WindowlessWindowManager { private static final String WINDOW_NAME = "SplitOutlineLayer"; private final Context mContext; - private final Rect mOutlineBounds = new Rect(); - private final Rect mTmpBounds = new Rect(); + private final Rect mRootBounds = new Rect(); + private final Rect mTempRect = new Rect(); + private final Rect mLastOutlineBounds = new Rect(); + private final InsetsState mInsetsState = new InsetsState(); + private final int mExpandedTaskBarHeight; + private OutlineView mOutlineView; private SurfaceControlViewHost mViewHost; private SurfaceControl mHostLeash; private SurfaceControl mLeash; - private int mOutlineColor; OutlineManager(Context context, Configuration configuration) { super(configuration, null /* rootSurface */, null /* hostInputToken */); mContext = context.createWindowContext(context.getDisplay(), TYPE_APPLICATION_OVERLAY, null /* options */); + mExpandedTaskBarHeight = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.taskbar_frame_height); } @Override @@ -63,65 +72,110 @@ class OutlineManager extends WindowlessWindowManager { b.setParent(mHostLeash); } - boolean drawOutlineBounds(Rect rootBounds) { - if (mLeash == null || mViewHost == null) return false; - - computeOutlineBounds(mContext, rootBounds, mTmpBounds); - if (mOutlineBounds.equals(mTmpBounds)) { - return false; - } - mOutlineBounds.set(mTmpBounds); - - ((OutlineRoot) mViewHost.getView()).updateOutlineBounds(mOutlineBounds, mOutlineColor); - final WindowManager.LayoutParams lp = - (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams(); - lp.width = rootBounds.width(); - lp.height = rootBounds.height(); - mViewHost.relayout(lp); - - return true; - } - - void inflate(SurfaceControl.Transaction t, SurfaceControl hostLeash, int color) { + void inflate(SurfaceControl rootLeash, Rect rootBounds) { if (mLeash != null || mViewHost != null) return; - mHostLeash = hostLeash; - mOutlineColor = color; + mHostLeash = rootLeash; + mRootBounds.set(rootBounds); mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); - final OutlineRoot rootView = (OutlineRoot) LayoutInflater.from(mContext) + + final FrameLayout rootLayout = (FrameLayout) LayoutInflater.from(mContext) .inflate(R.layout.split_outline, null); + mOutlineView = rootLayout.findViewById(R.id.split_outline); final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 0 /* width */, 0 /* height */, TYPE_APPLICATION_OVERLAY, FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT); + lp.width = mRootBounds.width(); + lp.height = mRootBounds.height(); lp.token = new Binder(); lp.setTitle(WINDOW_NAME); lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; // TODO(b/189839391): Set INPUT_FEATURE_NO_INPUT_CHANNEL after WM supports // TRUSTED_OVERLAY for windowless window without input channel. - mViewHost.setView(rootView, lp); + mViewHost.setView(rootLayout, lp); mLeash = getSurfaceControl(mViewHost.getWindowToken()); - t.setLayer(mLeash, Integer.MAX_VALUE); + + drawOutline(); } void release() { if (mViewHost != null) { mViewHost.release(); + mViewHost = null; } + mRootBounds.setEmpty(); + mLastOutlineBounds.setEmpty(); + mOutlineView = null; + mHostLeash = null; + mLeash = null; + } + + @Nullable + SurfaceControl getOutlineLeash() { + return mLeash; } - private static void computeOutlineBounds(Context context, Rect rootBounds, Rect outBounds) { - computeDisplayStableBounds(context, outBounds); - outBounds.intersect(rootBounds); + void setVisibility(boolean visible) { + if (mOutlineView != null) { + mOutlineView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); + } + } + + void setRootBounds(Rect rootBounds) { + if (mViewHost == null || mViewHost.getView() == null) { + return; + } + + if (!mRootBounds.equals(rootBounds)) { + WindowManager.LayoutParams lp = + (WindowManager.LayoutParams) mViewHost.getView().getLayoutParams(); + lp.width = rootBounds.width(); + lp.height = rootBounds.height(); + mViewHost.relayout(lp); + mRootBounds.set(rootBounds); + drawOutline(); + } + } + + void onInsetsChanged(InsetsState insetsState) { + if (!mInsetsState.equals(insetsState)) { + mInsetsState.set(insetsState); + drawOutline(); + } + } + + private void computeOutlineBounds(Rect rootBounds, InsetsState insetsState, Rect outBounds) { + outBounds.set(rootBounds); + final InsetsSource taskBarInsetsSource = + insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR); + // Only insets the divider bar with task bar when it's expanded so that the rounded corners + // will be drawn against task bar. + if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) { + outBounds.inset(taskBarInsetsSource.calculateVisibleInsets(outBounds)); + } + // Offset the coordinate from screen based to surface based. outBounds.offset(-rootBounds.left, -rootBounds.top); } - private static void computeDisplayStableBounds(Context context, Rect outBounds) { - final WindowMetrics windowMetrics = - context.getSystemService(WindowManager.class).getMaximumWindowMetrics(); - outBounds.set(windowMetrics.getBounds()); - outBounds.inset(windowMetrics.getWindowInsets().getInsets( - WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout())); + void drawOutline() { + if (mOutlineView == null) { + return; + } + + computeOutlineBounds(mRootBounds, mInsetsState, mTempRect); + if (mTempRect.equals(mLastOutlineBounds)) { + return; + } + + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) mOutlineView.getLayoutParams(); + lp.leftMargin = mTempRect.left; + lp.topMargin = mTempRect.top; + lp.width = mTempRect.width(); + lp.height = mTempRect.height(); + mOutlineView.setLayoutParams(lp); + mLastOutlineBounds.set(mTempRect); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineRoot.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineRoot.java deleted file mode 100644 index 71d48eeca71d..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineRoot.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.splitscreen; - -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.wm.shell.R; - -/** Root layout for holding split outline. */ -public class OutlineRoot extends FrameLayout { - public OutlineRoot(@NonNull Context context) { - super(context); - } - - public OutlineRoot(@NonNull Context context, - @Nullable AttributeSet attrs) { - super(context, attrs); - } - - public OutlineRoot(@NonNull Context context, @Nullable AttributeSet attrs, - int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public OutlineRoot(@NonNull Context context, @Nullable AttributeSet attrs, - int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - private OutlineView mOutlineView; - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mOutlineView = findViewById(R.id.split_outline); - } - - void updateOutlineBounds(Rect bounds, int color) { - mOutlineView.updateOutlineBounds(bounds, color); - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java index ea66180e3dd2..94dd9b24875a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OutlineView.java @@ -16,13 +16,17 @@ package com.android.wm.shell.splitscreen; +import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT; +import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT; +import static android.view.RoundedCorner.POSITION_TOP_LEFT; +import static android.view.RoundedCorner.POSITION_TOP_RIGHT; + import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; -import android.graphics.Rect; -import android.graphics.Region; import android.util.AttributeSet; +import android.view.RoundedCorner; import android.view.View; import androidx.annotation.NonNull; @@ -33,44 +37,46 @@ import com.android.internal.R; /** View for drawing split outline. */ public class OutlineView extends View { private final Paint mPaint = new Paint(); - private final Rect mBounds = new Rect(); - - public OutlineView(@NonNull Context context) { - super(context); - } + private final Path mPath = new Path(); + private final float[] mRadii = new float[8]; - public OutlineView(@NonNull Context context, - @Nullable AttributeSet attrs) { + public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth( + getResources().getDimension(R.dimen.accessibility_focus_highlight_stroke_width)); + mPaint.setColor(getResources().getColor(R.color.system_accent1_100, null)); } - public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); + @Override + protected void onAttachedToWindow() { + // TODO(b/200850654): match the screen corners with the actual display decor. + mRadii[0] = mRadii[1] = getCornerRadius(POSITION_TOP_LEFT); + mRadii[2] = mRadii[3] = getCornerRadius(POSITION_TOP_RIGHT); + mRadii[4] = mRadii[5] = getCornerRadius(POSITION_BOTTOM_RIGHT); + mRadii[6] = mRadii[7] = getCornerRadius(POSITION_BOTTOM_LEFT); } - public OutlineView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, - int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); + private int getCornerRadius(@RoundedCorner.Position int position) { + final RoundedCorner roundedCorner = getDisplay().getRoundedCorner(position); + return roundedCorner == null ? 0 : roundedCorner.getRadius(); } @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mPaint.setStyle(Paint.Style.STROKE); - mPaint.setStrokeWidth(getResources() - .getDimension(R.dimen.accessibility_focus_highlight_stroke_width)); + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (changed) { + mPath.reset(); + mPath.addRoundRect(0, 0, getWidth(), getHeight(), mRadii, Path.Direction.CW); + } } - void updateOutlineBounds(Rect bounds, int color) { - if (mBounds.equals(bounds) && mPaint.getColor() == color) return; - mBounds.set(bounds); - mPaint.setColor(color); + @Override + protected void onDraw(Canvas canvas) { + canvas.drawPath(mPath, mPaint); } @Override - protected void onDraw(Canvas canvas) { - if (mBounds.isEmpty()) return; - final Path path = new Region(mBounds).getBoundaryPath(); - canvas.drawPath(path, mPaint); + public boolean hasOverlappingRendering() { + return false; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java index 2b19bb965fed..0e7ccd3515c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java @@ -17,15 +17,19 @@ package com.android.wm.shell.splitscreen; import android.annotation.CallSuper; +import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; -import android.graphics.Color; import android.graphics.Rect; +import android.view.InsetsSourceControl; +import android.view.InsetsState; +import android.view.SurfaceControl; import android.view.SurfaceSession; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.SyncTransactionQueue; /** @@ -34,7 +38,8 @@ import com.android.wm.shell.common.SyncTransactionQueue; * * @see StageCoordinator */ -class SideStage extends StageTaskListener { +class SideStage extends StageTaskListener implements + DisplayInsetsController.OnInsetsChangedListener { private static final String TAG = SideStage.class.getSimpleName(); private final Context mContext; private OutlineManager mOutlineManager; @@ -77,33 +82,61 @@ class SideStage extends StageTaskListener { return true; } + @Nullable + public SurfaceControl getOutlineLeash() { + return mOutlineManager.getOutlineLeash(); + } + + @Override + @CallSuper + public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { + super.onTaskAppeared(taskInfo, leash); + if (isRootTask(taskInfo)) { + mOutlineManager = new OutlineManager(mContext, taskInfo.configuration); + enableOutline(true); + } + } + + @Override + @CallSuper + public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + super.onTaskInfoChanged(taskInfo); + if (isRootTask(taskInfo)) { + mOutlineManager.setRootBounds(taskInfo.configuration.windowConfiguration.getBounds()); + } + } + + private boolean isRootTask(ActivityManager.RunningTaskInfo taskInfo) { + return mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId; + } + void enableOutline(boolean enable) { + if (mOutlineManager == null) { + return; + } + if (enable) { - if (mOutlineManager == null && mRootTaskInfo != null) { - mOutlineManager = new OutlineManager(mContext, mRootTaskInfo.configuration); - mSyncQueue.runInSync(t -> mOutlineManager.inflate(t, mRootLeash, Color.YELLOW)); - updateOutlineBounds(); + if (mRootTaskInfo != null) { + mOutlineManager.inflate(mRootLeash, + mRootTaskInfo.configuration.windowConfiguration.getBounds()); } } else { - if (mOutlineManager != null) { - mOutlineManager.release(); - mOutlineManager = null; - } + mOutlineManager.release(); } } - private void updateOutlineBounds() { - if (mOutlineManager == null || mRootTaskInfo == null || !mRootTaskInfo.isVisible) return; - mOutlineManager.drawOutlineBounds( - mRootTaskInfo.configuration.windowConfiguration.getBounds()); + void setOutlineVisibility(boolean visible) { + mOutlineManager.setVisibility(visible); } @Override - @CallSuper - public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { - super.onTaskInfoChanged(taskInfo); - if (mRootTaskInfo != null && mRootTaskInfo.taskId == taskInfo.taskId) { - updateOutlineBounds(); - } + public void insetsChanged(InsetsState insetsState) { + mOutlineManager.onInsetsChanged(insetsState); + } + + @Override + public void insetsControlChanged(InsetsState insetsState, + InsetsSourceControl[] activeControls) { + insetsChanged(insetsState); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 6527cabb0d34..ac68b3b8a6a9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -257,11 +257,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } } - final RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget(); - if (divider.leash != null) { - t.show(divider.leash); - } - t.apply(); if (finishedCallback != null) { try { @@ -300,7 +295,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } transaction.apply(); transaction.close(); - return new RemoteAnimationTarget[]{mStageCoordinator.getDividerBarLegacyTarget()}; + return new RemoteAnimationTarget[]{ + mStageCoordinator.getDividerBarLegacyTarget(), + mStageCoordinator.getOutlineLegacyTarget()}; } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 493870d7fd72..d7a6cfff6c6f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -201,6 +201,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSurfaceSession); mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; + mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSideStage); mRootTDAOrganizer.registerListener(displayId, this); final DeviceStateManager deviceStateManager = mContext.getSystemService(DeviceStateManager.class); @@ -250,7 +251,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, setSideStagePosition(sideStagePosition, wct); mMainStage.activate(getMainStageBounds(), wct); mSideStage.addTask(task, getSideStageBounds(), wct); - mTaskOrganizer.applyTransaction(wct); + mSyncQueue.queue(wct); + mSyncQueue.runInSync(t -> updateSurfaceBounds(null /* layout */, t)); return true; } @@ -446,15 +448,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, setSideStagePosition(sideStagePosition, true /* updateBounds */, wct); } - private void setSideStagePosition(@SplitPosition int sideStagePosition, - boolean updateBounds, @Nullable WindowContainerTransaction wct) { + private void setSideStagePosition(@SplitPosition int sideStagePosition, boolean updateBounds, + @Nullable WindowContainerTransaction wct) { if (mSideStagePosition == sideStagePosition) return; mSideStagePosition = sideStagePosition; sendOnStagePositionChanged(); if (mSideStageListener.mVisible && updateBounds) { if (wct == null) { - // onBoundsChanged builds/applies a wct with the contents of updateWindowBounds. + // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds. onLayoutChanged(mSplitLayout); } else { updateWindowBounds(mSplitLayout, wct); @@ -675,30 +677,13 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } mSyncQueue.runInSync(t -> { - final SurfaceControl sideStageLeash = mSideStage.mRootLeash; - final SurfaceControl mainStageLeash = mMainStage.mRootLeash; - - if (sideStageVisible) { - final Rect sideStageBounds = getSideStageBounds(); - t.setPosition(sideStageLeash, - sideStageBounds.left, sideStageBounds.top) - .setWindowCrop(sideStageLeash, - sideStageBounds.width(), sideStageBounds.height()); - } - - if (mainStageVisible) { - final Rect mainStageBounds = getMainStageBounds(); - t.setPosition(mainStageLeash, mainStageBounds.left, mainStageBounds.top) - .setWindowCrop(mainStageLeash, - mainStageBounds.width(), mainStageBounds.height()); - } - // Same above, we only set root tasks and divider leash visibility when both stage // change to visible or invisible to avoid flicker. if (sameVisibility) { - t.setVisibility(sideStageLeash, bothStageVisible) - .setVisibility(mainStageLeash, bothStageVisible); + t.setVisibility(mSideStage.mRootLeash, bothStageVisible) + .setVisibility(mMainStage.mRootLeash, bothStageVisible); applyDividerVisibility(t); + applyOutlineVisibility(t); } }); } @@ -720,6 +705,19 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } + private void applyOutlineVisibility(SurfaceControl.Transaction t) { + final SurfaceControl outlineLeash = mSideStage.getOutlineLeash(); + if (outlineLeash == null) { + return; + } + + if (mDividerVisible) { + t.show(outlineLeash).setLayer(outlineLeash, SPLIT_DIVIDER_LAYER); + } else { + t.hide(outlineLeash); + } + } + private void onStageHasChildrenChanged(StageListenerImpl stageListener) { final boolean hasChildren = stageListener.mHasChildren; final boolean isSideStage = stageListener == mSideStageListener; @@ -779,6 +777,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onLayoutChanging(SplitLayout layout) { mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); + mSideStage.setOutlineVisibility(false); } @Override @@ -787,6 +786,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, updateWindowBounds(layout, wct); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t)); + mSideStage.setOutlineVisibility(true); mLogger.logResize(mSplitLayout.getDividerPositionAsFraction()); } @@ -1162,6 +1162,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER); } + RemoteAnimationTarget getOutlineLegacyTarget() { + final Rect bounds = mSideStage.mRootTaskInfo.configuration.windowConfiguration.getBounds(); + // Leverage TYPE_DOCK_DIVIDER type when wrapping outline remote animation target in order to + // distinguish as a split auxiliary target in Launcher. + return new RemoteAnimationTarget(-1 /* taskId */, -1 /* mode */, + mSideStage.getOutlineLeash(), false /* isTranslucent */, null /* clipRect */, + null /* contentInsets */, Integer.MAX_VALUE /* prefixOrderIndex */, + new android.graphics.Point(0, 0) /* position */, bounds, bounds, + new WindowConfiguration(), true, null /* startLeash */, null /* startBounds */, + null /* taskInfo */, false /* allowEnterPip */, TYPE_DOCK_DIVIDER); + } + @Override public void dump(@NonNull PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 15b4ff970203..4140332f50a3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -138,8 +138,11 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { mRootTaskInfo = taskInfo; mCallbacks.onRootTaskAppeared(); sendStatusChanged(); - mSyncQueue.runInSync(t -> mDimLayer = - SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession)); + mSyncQueue.runInSync(t -> { + t.hide(mRootLeash); + mDimLayer = + SurfaceUtils.makeDimLayer(t, mRootLeash, "Dim layer", mSurfaceSession); + }); } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { final int taskId = taskInfo.taskId; mChildrenLeashes.put(taskId, leash); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 6b74b620dad7..d5acbbcf7d2c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -197,6 +197,43 @@ public class ShellTaskOrganizerTests { } @Test + public void testAddListenerForMultipleTypes() { + RunningTaskInfo taskInfo1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN); + mOrganizer.onTaskAppeared(taskInfo1, null); + RunningTaskInfo taskInfo2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW); + mOrganizer.onTaskAppeared(taskInfo2, null); + + TrackingTaskListener listener = new TrackingTaskListener(); + mOrganizer.addListenerForType(listener, + TASK_LISTENER_TYPE_MULTI_WINDOW, TASK_LISTENER_TYPE_FULLSCREEN); + + // onTaskAppeared event should be delivered once for each taskInfo. + assertTrue(listener.appeared.contains(taskInfo1)); + assertTrue(listener.appeared.contains(taskInfo2)); + assertEquals(2, listener.appeared.size()); + } + + @Test + public void testRemoveListenerForMultipleTypes() { + RunningTaskInfo taskInfo1 = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN); + mOrganizer.onTaskAppeared(taskInfo1, null); + RunningTaskInfo taskInfo2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW); + mOrganizer.onTaskAppeared(taskInfo2, null); + + TrackingTaskListener listener = new TrackingTaskListener(); + mOrganizer.addListenerForType(listener, + TASK_LISTENER_TYPE_MULTI_WINDOW, TASK_LISTENER_TYPE_FULLSCREEN); + + mOrganizer.removeListener(listener); + + // If listener is removed properly, onTaskInfoChanged event shouldn't be delivered. + mOrganizer.onTaskInfoChanged(taskInfo1); + assertTrue(listener.infoChanged.isEmpty()); + mOrganizer.onTaskInfoChanged(taskInfo2); + assertTrue(listener.infoChanged.isEmpty()); + } + + @Test public void testWindowingModeChange() { RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW); TrackingTaskListener mwListener = new TrackingTaskListener(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java index 27c626170a4b..294bc1276291 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/apppairs/TestAppPairsController.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; +import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; @@ -30,7 +31,7 @@ public class TestAppPairsController extends AppPairsController { public TestAppPairsController(ShellTaskOrganizer organizer, SyncTransactionQueue syncQueue, DisplayController displayController) { super(organizer, syncQueue, displayController, mock(ShellExecutor.class), - mock(DisplayImeController.class)); + mock(DisplayImeController.class), mock(DisplayInsetsController.class)); mPool = new TestAppPairsPool(this); setPairsPool(mPool); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java index 69ead3ac9cf9..3a2516ec9366 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SideStageTests.java @@ -29,6 +29,7 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.window.WindowContainerTransaction; +import androidx.test.annotation.UiThreadTest; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -58,6 +59,7 @@ public class SideStageTests extends ShellTestCase { private SideStage mSideStage; @Before + @UiThreadTest public void setup() { MockitoAnnotations.initMocks(this); mRootTask = new TestRunningTaskInfoBuilder().build(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index d357e778fe35..8dce454eb078 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -51,6 +51,7 @@ import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; +import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -96,6 +97,7 @@ public class SplitTransitionTests extends ShellTestCase { private ActivityManager.RunningTaskInfo mSideChild; @Before + @UiThreadTest public void setup() { MockitoAnnotations.initMocks(this); final ShellExecutor mockExecutor = mock(ShellExecutor.class); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java index 1a30f164f9a8..0916dd1f71bd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java @@ -62,6 +62,7 @@ public final class StageTaskListenerTests { @Mock private SyncTransactionQueue mSyncQueue; @Captor private ArgumentCaptor<SyncTransactionQueue.TransactionRunnable> mRunnableCaptor; private SurfaceSession mSurfaceSession = new SurfaceSession(); + private SurfaceControl mSurfaceControl; private ActivityManager.RunningTaskInfo mRootTask; private StageTaskListener mStageTaskListener; @@ -76,7 +77,8 @@ public final class StageTaskListenerTests { mSurfaceSession); mRootTask = new TestRunningTaskInfoBuilder().build(); mRootTask.parentTaskId = INVALID_TASK_ID; - mStageTaskListener.onTaskAppeared(mRootTask, new SurfaceControl()); + mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession).setName("test").build(); + mStageTaskListener.onTaskAppeared(mRootTask, mSurfaceControl); } @Test @@ -103,7 +105,7 @@ public final class StageTaskListenerTests { final ActivityManager.RunningTaskInfo childTask = new TestRunningTaskInfoBuilder().setParentTaskId(mRootTask.taskId).build(); - mStageTaskListener.onTaskAppeared(childTask, new SurfaceControl()); + mStageTaskListener.onTaskAppeared(childTask, mSurfaceControl); assertThat(mStageTaskListener.mChildrenTaskInfo.contains(childTask.taskId)).isTrue(); verify(mCallbacks).onStatusChanged(eq(mRootTask.isVisible), eq(true)); diff --git a/location/java/android/location/GpsNavigationMessage.java b/location/java/android/location/GpsNavigationMessage.java index dc1e99fd6a4f..2b978f759a13 100644 --- a/location/java/android/location/GpsNavigationMessage.java +++ b/location/java/android/location/GpsNavigationMessage.java @@ -262,12 +262,8 @@ public class GpsNavigationMessage implements Parcelable { parcel.readByteArray(data); navigationMessage.setData(data); - if (parcel.dataAvail() >= Integer.SIZE) { - int status = parcel.readInt(); - navigationMessage.setStatus((short) status); - } else { - navigationMessage.setStatus(STATUS_UNKNOWN); - } + int status = parcel.readInt(); + navigationMessage.setStatus((short) status); return navigationMessage; } diff --git a/packages/PrintSpooler/res/values-te/strings.xml b/packages/PrintSpooler/res/values-te/strings.xml index cf0e0f6b506e..50e6f3b7dac5 100644 --- a/packages/PrintSpooler/res/values-te/strings.xml +++ b/packages/PrintSpooler/res/values-te/strings.xml @@ -50,8 +50,8 @@ <string name="search" msgid="5421724265322228497">"సెర్చ్"</string> <string name="all_printers_label" msgid="3178848870161526399">"అన్ని ప్రింటర్లు"</string> <string name="add_print_service_label" msgid="5356702546188981940">"సేవను జోడించు"</string> - <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"శోధన పెట్టె చూపబడింది"</string> - <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"శోధన పెట్టె దాచబడింది"</string> + <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"సెర్చ్ బాక్స్ చూపబడింది"</string> + <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"సెర్చ్ బాక్స్ దాచబడింది"</string> <string name="print_add_printer" msgid="1088656468360653455">"ప్రింటర్ను జోడించు"</string> <string name="print_select_printer" msgid="7388760939873368698">"ప్రింటర్ను ఎంచుకోండి"</string> <string name="print_forget_printer" msgid="5035287497291910766">"ప్రింటర్ను విస్మరించు"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index 656fe6a9476a..eafa87bbbf7d 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -558,7 +558,7 @@ <string name="user_new_profile_name" msgid="2405500423304678841">"নতুন প্ৰ\'ফাইল"</string> <string name="user_info_settings_title" msgid="6351390762733279907">"ব্যৱহাৰকাৰীৰ তথ্য"</string> <string name="profile_info_settings_title" msgid="105699672534365099">"প্ৰ\'ফাইলৰ তথ্য"</string> - <string name="user_need_lock_message" msgid="4311424336209509301">"আপুনি সীমিত প্ৰ\'ফাইল এটা সৃষ্টি কৰাৰ আগেয়ে, আপোনাৰ ব্যক্তিগত ডেটা আৰু এপবিলাকক সুৰক্ষিত কৰিবলৈ স্ক্ৰীণ লক এটা নিৰ্ধাৰণ কৰিব লাগিব।"</string> + <string name="user_need_lock_message" msgid="4311424336209509301">"আপুনি সীমিত প্ৰ’ফাইল এটা সৃষ্টি কৰাৰ আগেয়ে, আপোনাৰ ব্যক্তিগত ডেটা আৰু এপ্বিলাকক সুৰক্ষিত কৰিবলৈ স্ক্ৰীন লক এটা নিৰ্ধাৰণ কৰিব লাগিব।"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"লক ছেট কৰক"</string> <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>লৈ সলনি কৰক"</string> <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰি থকা হৈছে…"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 6f8f99b03be6..545cf9524564 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -90,7 +90,7 @@ <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"కాంటాక్ట్ షేరింగ్"</string> <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"కాంటాక్ట్ షేరింగ్ కోసం ఉపయోగించండి"</string> <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ షేరింగ్"</string> - <string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన మెసేజ్లు"</string> + <string name="bluetooth_profile_map" msgid="8907204701162107271">"టెక్స్ట్ మెసేజ్లు"</string> <string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM యాక్సెస్"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ఆడియో: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> <string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ఆడియో"</string> diff --git a/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml b/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml new file mode 100644 index 000000000000..c6b87d38f7da --- /dev/null +++ b/packages/SystemUI/animation/res/anim/launch_host_dialog_enter.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- The enter animation of the host dialog is a translation of 0px that lasts 500ms so that the --> +<!-- host dialog is directly visible but the dim background still takes 500ms to fade in. --> +<translate xmlns:android="http://schemas.android.com/apk/res/android" + android:fromXDelta="0" + android:toXDelta="0" + android:duration="500" />
\ No newline at end of file diff --git a/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml b/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml new file mode 100644 index 000000000000..a0f441eaeed4 --- /dev/null +++ b/packages/SystemUI/animation/res/anim/launch_host_dialog_exit.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<alpha + xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:interpolator/decelerate_cubic" + android:duration="150" + android:fromAlpha="1.0" + android:toAlpha="0.0" />
\ No newline at end of file diff --git a/packages/SystemUI/animation/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml new file mode 100644 index 000000000000..ef60a248f79a --- /dev/null +++ b/packages/SystemUI/animation/res/values/ids.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <item type="id" name="launch_animation_running"/> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/animation/res/values/styles.xml b/packages/SystemUI/animation/res/values/styles.xml new file mode 100644 index 000000000000..ad06c9192bc3 --- /dev/null +++ b/packages/SystemUI/animation/res/values/styles.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <style name="HostDialogTheme"> + <item name="android:windowAnimationStyle">@style/Animation.HostDialog</item> + <item name="android:windowIsFloating">false</item> + <item name="android:backgroundDimEnabled">true</item> + <item name="android:navigationBarColor">@android:color/transparent</item> + </style> + + <style name="Animation.HostDialog" parent="@android:style/Animation"> + <item name="android:windowEnterAnimation">@anim/launch_host_dialog_enter</item> + <item name="android:windowExitAnimation">@anim/launch_host_dialog_exit</item> + </style> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt index 9c1e12923b43..702060338359 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt @@ -1,23 +1,31 @@ +/* + * 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.animation -import android.animation.Animator -import android.animation.AnimatorListenerAdapter -import android.animation.ValueAnimator import android.app.ActivityManager import android.app.ActivityTaskManager import android.app.PendingIntent import android.app.TaskInfo -import android.content.Context import android.graphics.Matrix -import android.graphics.PorterDuff -import android.graphics.PorterDuffXfermode import android.graphics.Rect import android.graphics.RectF -import android.graphics.drawable.GradientDrawable import android.os.Looper import android.os.RemoteException import android.util.Log -import android.util.MathUtils import android.view.IRemoteAnimationFinishedCallback import android.view.IRemoteAnimationRunner import android.view.RemoteAnimationAdapter @@ -26,7 +34,6 @@ import android.view.SyncRtSurfaceTransactionApplier import android.view.View import android.view.ViewGroup import android.view.WindowManager -import android.view.animation.AnimationUtils import android.view.animation.PathInterpolator import com.android.internal.annotations.VisibleForTesting import com.android.internal.policy.ScreenDecorationsUtils @@ -38,52 +45,23 @@ private const val TAG = "ActivityLaunchAnimator" * A class that allows activities to be started in a seamless way from a view that is transforming * nicely into the starting window. */ -class ActivityLaunchAnimator( - private val callback: Callback, - context: Context -) { +class ActivityLaunchAnimator(private val launchAnimator: LaunchAnimator) { companion object { - private const val DEBUG = false - const val ANIMATION_DURATION = 500L - private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L - private const val ANIMATION_DURATION_FADE_IN_WINDOW = 183L - private const val ANIMATION_DELAY_FADE_IN_WINDOW = ANIMATION_DURATION_FADE_OUT_CONTENT private const val ANIMATION_DURATION_NAV_FADE_IN = 266L private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L private const val ANIMATION_DELAY_NAV_FADE_IN = - ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN + LaunchAnimator.ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN private const val LAUNCH_TIMEOUT = 1000L - @JvmField val CONTENT_FADE_OUT_INTERPOLATOR = PathInterpolator(0f, 0f, 0.2f, 1f) - private val WINDOW_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0.6f, 1f) private val NAV_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0f, 1f) private val NAV_FADE_OUT_INTERPOLATOR = PathInterpolator(0.2f, 0f, 1f, 1f) - - private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC) - - /** - * Given the [linearProgress] of a launch animation, return the linear progress of the - * sub-animation starting [delay] ms after the launch animation and that lasts [duration]. - */ - @JvmStatic - fun getProgress(linearProgress: Float, delay: Long, duration: Long): Float { - return MathUtils.constrain( - (linearProgress * ANIMATION_DURATION - delay) / duration, - 0.0f, - 1.0f - ) - } } - /** The interpolator used for the width, height, Y position and corner radius. */ - private val animationInterpolator = AnimationUtils.loadInterpolator(context, - R.interpolator.launch_animation_interpolator_y) - - /** The interpolator used for the X position. */ - private val animationInterpolatorX = AnimationUtils.loadInterpolator(context, - R.interpolator.launch_animation_interpolator_x) - - private val cornerRadii = FloatArray(8) + /** + * The callback of this animator. This should be set before any call to + * [start(Pending)IntentWithAnimation]. + */ + var callback: Callback? = null /** * Start an intent and animate the opening window. The intent will be started by running @@ -119,6 +97,8 @@ class ActivityLaunchAnimator( return } + val callback = this.callback ?: throw IllegalStateException( + "ActivityLaunchAnimator.callback must be set before using this animator") val runner = Runner(controller) val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen @@ -126,9 +106,9 @@ class ActivityLaunchAnimator( // keyguard with the animation val animationAdapter = if (!hideKeyguardWithAnimation) { RemoteAnimationAdapter( - runner, - ANIMATION_DURATION, - ANIMATION_DURATION - 150 /* statusBarTransitionDelay */ + runner, + LaunchAnimator.ANIMATION_DURATION, + LaunchAnimator.ANIMATION_DURATION - 150 /* statusBarTransitionDelay */ ) } else { null @@ -150,10 +130,10 @@ class ActivityLaunchAnimator( // Only animate if the app is not already on top and will be opened, unless we are on the // keyguard. val willAnimate = - launchResult == ActivityManager.START_TASK_TO_FRONT || - launchResult == ActivityManager.START_SUCCESS || - (launchResult == ActivityManager.START_DELIVERED_TO_TOP && - hideKeyguardWithAnimation) + launchResult == ActivityManager.START_TASK_TO_FRONT || + launchResult == ActivityManager.START_SUCCESS || + (launchResult == ActivityManager.START_DELIVERED_TO_TOP && + hideKeyguardWithAnimation) Log.i(TAG, "launchResult=$launchResult willAnimate=$willAnimate " + "hideKeyguardWithAnimation=$hideKeyguardWithAnimation") @@ -234,7 +214,7 @@ class ActivityLaunchAnimator( * * Note that all callbacks (onXXX methods) are all called on the main thread. */ - interface Controller { + interface Controller : LaunchAnimator.Controller { companion object { /** * Return a [Controller] that will animate and expand [view] into the opening window. @@ -259,53 +239,12 @@ class ActivityLaunchAnimator( } /** - * The container in which the view that started the intent will be animating together with - * the opening window. - * - * This will be used to: - * - Get the associated [Context]. - * - Compute whether we are expanding fully above the current window. - * - Apply surface transactions in sync with RenderThread. - * - * This container can be changed to force this [Controller] to animate the expanding view - * inside a different location, for instance to ensure correct layering during the - * animation. - */ - var launchContainer: ViewGroup - - /** - * Return the [State] of the view that will be animated. We will animate from this state to - * the final window state. - * - * Note: This state will be mutated and passed to [onLaunchAnimationProgress] during the - * animation. - */ - fun createAnimatorState(): State - - /** * The intent was started. If [willAnimate] is false, nothing else will happen and the * animation will not be started. */ fun onIntentStarted(willAnimate: Boolean) {} /** - * The animation started. This is typically used to initialize any additional resource - * needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding - * fully above the [root view][getRootView]. - */ - fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {} - - /** The animation made progress and the expandable view [state] should be updated. */ - fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {} - - /** - * The animation ended. This will be called *if and only if* [onLaunchAnimationStart] was - * called previously. This is typically used to clean up the resources initialized when the - * animation was started. - */ - fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {} - - /** * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called * before the cancellation. @@ -313,66 +252,11 @@ class ActivityLaunchAnimator( fun onLaunchAnimationCancelled() {} } - /** The state of an expandable view during an [ActivityLaunchAnimator] animation. */ - open class State( - /** The position of the view in screen space coordinates. */ - var top: Int, - var bottom: Int, - var left: Int, - var right: Int, - - var topCornerRadius: Float = 0f, - var bottomCornerRadius: Float = 0f - ) { - private val startTop = top - private val startBottom = bottom - private val startLeft = left - private val startRight = right - private val startWidth = width - private val startHeight = height - val startCenterX = centerX - val startCenterY = centerY - - val width: Int - get() = right - left - - val height: Int - get() = bottom - top - - open val topChange: Int - get() = top - startTop - - open val bottomChange: Int - get() = bottom - startBottom - - val leftChange: Int - get() = left - startLeft - - val rightChange: Int - get() = right - startRight - - val widthRatio: Float - get() = width.toFloat() / startWidth - - val heightRatio: Float - get() = height.toFloat() / startHeight - - val centerX: Float - get() = left + width / 2f - - val centerY: Float - get() = top + height / 2f - - /** Whether the expanded view should be visible or hidden. */ - var visible: Boolean = true - } - @VisibleForTesting inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() { private val launchContainer = controller.launchContainer private val context = launchContainer.context private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer) - private var animator: ValueAnimator? = null private val matrix = Matrix() private val invertMatrix = Matrix() @@ -380,6 +264,7 @@ class ActivityLaunchAnimator( private var windowCropF = RectF() private var timedOut = false private var cancelled = false + private var animation: LaunchAnimator.Animation? = null // A timeout to cancel the remote animation if it is not started within X milliseconds after // the intent was started. @@ -429,7 +314,7 @@ class ActivityLaunchAnimator( nonApps: Array<out RemoteAnimationTarget>?, iCallback: IRemoteAnimationFinishedCallback? ) { - if (DEBUG) { + if (LaunchAnimator.DEBUG) { Log.d(TAG, "Remote animation started") } @@ -449,36 +334,20 @@ class ActivityLaunchAnimator( it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR } - // Start state. - val state = controller.createAnimatorState() - - val startTop = state.top - val startBottom = state.bottom - val startLeft = state.left - val startRight = state.right - val startXCenter = (startLeft + startRight) / 2f - val startWidth = startRight - startLeft - - val startTopCornerRadius = state.topCornerRadius - val startBottomCornerRadius = state.bottomCornerRadius - - // End state. val windowBounds = window.screenSpaceBounds - val endTop = windowBounds.top - val endBottom = windowBounds.bottom - val endLeft = windowBounds.left - val endRight = windowBounds.right - val endXCenter = (endLeft + endRight) / 2f - val endWidth = endRight - endLeft - - // TODO(b/184121838): Ensure that we are launching on the same screen. - val rootViewLocation = launchContainer.locationOnScreen - val isExpandingFullyAbove = endTop <= rootViewLocation[1] && - endBottom >= rootViewLocation[1] + launchContainer.height && - endLeft <= rootViewLocation[0] && - endRight >= rootViewLocation[0] + launchContainer.width - - // TODO(b/184121838): We should somehow get the top and bottom radius of the window. + val endState = LaunchAnimator.State( + top = windowBounds.top, + bottom = windowBounds.bottom, + left = windowBounds.left, + right = windowBounds.right + ) + val callback = this@ActivityLaunchAnimator.callback!! + val windowBackgroundColor = callback.getBackgroundColor(window.taskInfo) + + // TODO(b/184121838): We should somehow get the top and bottom radius of the window + // instead of recomputing isExpandingFullyAbove here. + val isExpandingFullyAbove = + launchAnimator.isExpandingFullyAbove(controller.launchContainer, endState) val endRadius = if (isExpandingFullyAbove) { // Most of the time, expanding fully above the root view means expanding in full // screen. @@ -488,97 +357,40 @@ class ActivityLaunchAnimator( // a radius of 0. 0f } + endState.topCornerRadius = endRadius + endState.bottomCornerRadius = endRadius - // We add an extra layer with the same color as the app splash screen background color, - // which is usually the same color of the app background. We first fade in this layer - // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the - // launch container and reveal the opening window. - val windowBackgroundColor = callback.getBackgroundColor(window.taskInfo) - val windowBackgroundLayer = GradientDrawable().apply { - setColor(windowBackgroundColor) - alpha = 0 - } - - // Update state. - val animator = ValueAnimator.ofFloat(0f, 1f) - this.animator = animator - animator.duration = ANIMATION_DURATION - animator.interpolator = Interpolators.LINEAR - - val launchContainerOverlay = launchContainer.overlay - animator.addListener(object : AnimatorListenerAdapter() { - override fun onAnimationStart(animation: Animator?, isReverse: Boolean) { - if (DEBUG) { - Log.d(TAG, "Animation started") - } - + // We animate the opening window and delegate the view expansion to [this.controller]. + val delegate = this.controller + val controller = object : LaunchAnimator.Controller by delegate { + override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { callback.setBlursDisabledForAppLaunch(true) - controller.onLaunchAnimationStart(isExpandingFullyAbove) - - // Add the drawable to the launch container overlay. Overlays always draw - // drawables after views, so we know that it will be drawn above any view added - // by the controller. - launchContainerOverlay.add(windowBackgroundLayer) + delegate.onLaunchAnimationStart(isExpandingFullyAbove) } - override fun onAnimationEnd(animation: Animator?) { - if (DEBUG) { - Log.d(TAG, "Animation ended") - } - + override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { callback.setBlursDisabledForAppLaunch(false) iCallback?.invoke() - controller.onLaunchAnimationEnd(isExpandingFullyAbove) - launchContainerOverlay.remove(windowBackgroundLayer) + delegate.onLaunchAnimationEnd(isExpandingFullyAbove) } - }) - animator.addUpdateListener { animation -> - if (cancelled) { - return@addUpdateListener + override fun onLaunchAnimationProgress( + state: LaunchAnimator.State, + progress: Float, + linearProgress: Float + ) { + applyStateToWindow(window, state) + navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) } + delegate.onLaunchAnimationProgress(state, progress, linearProgress) } - - val linearProgress = animation.animatedFraction - val progress = animationInterpolator.getInterpolation(linearProgress) - val xProgress = animationInterpolatorX.getInterpolation(linearProgress) - val xCenter = MathUtils.lerp(startXCenter, endXCenter, xProgress) - val halfWidth = lerp(startWidth, endWidth, progress) / 2 - - state.top = lerp(startTop, endTop, progress).roundToInt() - state.bottom = lerp(startBottom, endBottom, progress).roundToInt() - state.left = (xCenter - halfWidth).roundToInt() - state.right = (xCenter + halfWidth).roundToInt() - - state.topCornerRadius = MathUtils.lerp(startTopCornerRadius, endRadius, progress) - state.bottomCornerRadius = - MathUtils.lerp(startBottomCornerRadius, endRadius, progress) - - // The expanding view can/should be hidden once it is completely coverred by the - // windowBackgroundLayer. - state.visible = - getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT) < 1 - - applyStateToWindow(window, state) - applyStateToWindowBackgroundLayer(windowBackgroundLayer, state, linearProgress) - navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) } - - // If we started expanding the view, we make it 1 pixel smaller on all sides to - // avoid artefacts on the corners caused by anti-aliasing of the view background and - // the window background layer. - if (state.top != startTop && state.left != startLeft && - state.bottom != startBottom && state.right != startRight) { - state.top += 1 - state.left += 1 - state.right -= 1 - state.bottom -= 1 - } - controller.onLaunchAnimationProgress(state, progress, linearProgress) } - animator.start() + // We draw a hole when the additional layer is fading out to reveal the opening window. + animation = launchAnimator.startAnimation( + controller, endState, windowBackgroundColor, drawHole = true) } - private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) { + private fun applyStateToWindow(window: RemoteAnimationTarget, state: LaunchAnimator.State) { val screenBounds = window.screenSpaceBounds val centerX = (screenBounds.left + screenBounds.right) / 2f val centerY = (screenBounds.top + screenBounds.bottom) / 2f @@ -632,48 +444,13 @@ class ActivityLaunchAnimator( transactionApplier.scheduleApply(params) } - private fun applyStateToWindowBackgroundLayer( - drawable: GradientDrawable, - state: State, - linearProgress: Float - ) { - // Update position. - drawable.setBounds(state.left, state.top, state.right, state.bottom) - - // Update radius. - cornerRadii[0] = state.topCornerRadius - cornerRadii[1] = state.topCornerRadius - cornerRadii[2] = state.topCornerRadius - cornerRadii[3] = state.topCornerRadius - cornerRadii[4] = state.bottomCornerRadius - cornerRadii[5] = state.bottomCornerRadius - cornerRadii[6] = state.bottomCornerRadius - cornerRadii[7] = state.bottomCornerRadius - drawable.cornerRadii = cornerRadii - - // We first fade in the background layer to hide the expanding view, then fade it out - // with SRC mode to draw a hole punch in the status bar and reveal the opening window. - val fadeInProgress = getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT) - if (fadeInProgress < 1) { - val alpha = CONTENT_FADE_OUT_INTERPOLATOR.getInterpolation(fadeInProgress) - drawable.alpha = (alpha * 0xFF).roundToInt() - drawable.setXfermode(null) - } else { - val fadeOutProgress = getProgress(linearProgress, - ANIMATION_DELAY_FADE_IN_WINDOW, ANIMATION_DURATION_FADE_IN_WINDOW) - val alpha = 1 - WINDOW_FADE_IN_INTERPOLATOR.getInterpolation(fadeOutProgress) - drawable.alpha = (alpha * 0xFF).roundToInt() - drawable.setXfermode(SRC_MODE) - } - } - private fun applyStateToNavigationBar( navigationBar: RemoteAnimationTarget, - state: State, + state: LaunchAnimator.State, linearProgress: Float ) { - val fadeInProgress = getProgress(linearProgress, ANIMATION_DELAY_NAV_FADE_IN, - ANIMATION_DURATION_NAV_FADE_OUT) + val fadeInProgress = LaunchAnimator.getProgress(linearProgress, + ANIMATION_DELAY_NAV_FADE_IN, ANIMATION_DURATION_NAV_FADE_OUT) val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash) if (fadeInProgress > 0) { @@ -682,13 +459,13 @@ class ActivityLaunchAnimator( 0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat()) windowCrop.set(state.left, 0, state.right, state.height) params - .withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress)) - .withMatrix(matrix) - .withWindowCrop(windowCrop) - .withVisibility(true) + .withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress)) + .withMatrix(matrix) + .withWindowCrop(windowCrop) + .withVisibility(true) } else { - val fadeOutProgress = getProgress(linearProgress, 0, - ANIMATION_DURATION_NAV_FADE_OUT) + val fadeOutProgress = LaunchAnimator.getProgress(linearProgress, 0, + ANIMATION_DURATION_NAV_FADE_OUT) params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress)) } @@ -714,7 +491,7 @@ class ActivityLaunchAnimator( cancelled = true removeTimeout() context.mainExecutor.execute { - animator?.cancel() + animation?.cancel() controller.onLaunchAnimationCancelled() } } @@ -726,9 +503,5 @@ class ActivityLaunchAnimator( e.printStackTrace() } } - - private fun lerp(start: Int, stop: Int, amount: Float): Float { - return MathUtils.lerp(start.toFloat(), stop.toFloat(), amount) - } } } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt index d4be25382395..258ca6bdf79b 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DelegateLaunchAnimatorController.kt @@ -1,3 +1,19 @@ +/* + * 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.animation /** diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt new file mode 100644 index 000000000000..c2b36089d0a7 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -0,0 +1,541 @@ +/* + * 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.animation + +import android.app.Dialog +import android.content.Context +import android.graphics.Color +import android.os.Looper +import android.util.Log +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.view.ViewTreeObserver +import android.view.WindowManager +import android.widget.FrameLayout + +private const val TAG = "DialogLaunchAnimator" + +/** + * A class that allows dialogs to be started in a seamless way from a view that is transforming + * nicely into the starting dialog. + * + * Important: Don't forget to call [DialogLaunchAnimator.onDozeAmountChanged] when the doze amount + * changes to gracefully handle dialogs fading out when the device is dozing. + */ +class DialogLaunchAnimator( + private val context: Context, + private val launchAnimator: LaunchAnimator, + private val hostDialogProvider: HostDialogProvider +) { + private companion object { + private val TAG_LAUNCH_ANIMATION_RUNNING = R.id.launch_animation_running + } + + // TODO(b/201264644): Remove this set. + private val currentAnimations = hashSetOf<DialogLaunchAnimation>() + + /** + * Show [dialog] by expanding it from [view]. + * + * Caveats: When calling this function, the dialog content view will actually be stolen and + * attached to a different dialog (and thus a different window) which means that the actual + * dialog window will never be drawn. Moreover, unless [dialog] is a [ListenableDialog], you + * must call dismiss(), hide() and show() on the [Dialog] returned by this function to actually + * dismiss, hide or show the dialog. + */ + fun showFromView(dialog: Dialog, view: View): Dialog { + if (Looper.myLooper() != Looper.getMainLooper()) { + throw IllegalStateException( + "showFromView must be called from the main thread and dialog must be created in " + + "the main thread") + } + + // Make sure we don't run the launch animation from the same view twice at the same time. + if (view.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) { + Log.e(TAG, "Not running dialog launch animation as there is already one running") + dialog.show() + return dialog + } + + view.setTag(TAG_LAUNCH_ANIMATION_RUNNING, true) + + val launchAnimation = DialogLaunchAnimation( + context, launchAnimator, hostDialogProvider, view, + onDialogDismissed = { currentAnimations.remove(it) }, originalDialog = dialog) + val hostDialog = launchAnimation.hostDialog + currentAnimations.add(launchAnimation) + + // If the dialog is dismissed/hidden/shown, then we should actually dismiss/hide/show the + // host dialog. + if (dialog is ListenableDialog) { + dialog.addListener(object : DialogListener { + override fun onDismiss() { + dialog.removeListener(this) + hostDialog.dismiss() + } + + override fun onHide() { + if (launchAnimation.ignoreNextCallToHide) { + launchAnimation.ignoreNextCallToHide = false + return + } + + hostDialog.hide() + } + + override fun onShow() { + hostDialog.show() + + // We don't actually want to show the original dialog, so hide it. + launchAnimation.ignoreNextCallToHide = true + dialog.hide() + } + }) + } + + launchAnimation.start() + return hostDialog + } + + /** Notify the current doze amount, to ensure that dialogs fade out when dozing. */ + // TODO(b/193634619): Replace this by some mandatory constructor parameter to make sure that we + // don't forget to call this when the doze amount changes. + fun onDozeAmountChanged(amount: Float) { + currentAnimations.forEach { it.onDozeAmountChanged(amount) } + } + + /** + * Ensure that all dialogs currently shown won't animate into their touch surface when + * dismissed. + * + * This is a temporary API meant to be called right before we both dismiss a dialog and start + * an activity, which currently does not look good if we animate the dialog into the touch + * surface at the same time as the activity starts. + * + * TODO(b/193634619): Remove this function and animate dialog into opening activity instead. + */ + fun disableAllCurrentDialogsExitAnimations() { + currentAnimations.forEach { it.exitAnimationDisabled = true } + } +} + +interface HostDialogProvider { + /** + * Create a host dialog that will be used to host a launch animation. This host dialog must: + * 1. call [onCreateCallback] in its onCreate() method, e.g. right after calling + * super.onCreate(). + * 2. call [dismissOverride] instead of doing any dismissing logic. The actual dismissing + * logic should instead be done inside the lambda passed to [dismissOverride], which will + * be called after the exit animation. + * + * See SystemUIHostDialogProvider for an example of implementation. + */ + fun createHostDialog( + context: Context, + theme: Int, + onCreateCallback: () -> Unit, + dismissOverride: (() -> Unit) -> Unit + ): Dialog +} + +/** A dialog to/from which we can add/remove listeners. */ +interface ListenableDialog { + /** Add [listener] to the listeners. */ + fun addListener(listener: DialogListener) + + /** Remove [listener] from the listeners. */ + fun removeListener(listener: DialogListener) +} + +interface DialogListener { + /** Called when this dialog dismiss() is called. */ + fun onDismiss() + + /** Called when this dialog hide() is called. */ + fun onHide() + + /** Called when this dialog show() is called. */ + fun onShow() +} + +private class DialogLaunchAnimation( + private val context: Context, + private val launchAnimator: LaunchAnimator, + hostDialogProvider: HostDialogProvider, + + /** The view that triggered the dialog after being tapped. */ + private val touchSurface: View, + + /** + * A callback that will be called with this [DialogLaunchAnimation] after the dialog was + * dismissed and the exit animation is done. + */ + private val onDialogDismissed: (DialogLaunchAnimation) -> Unit, + + /** The original dialog whose content will be shown and animate in/out in [hostDialog]. */ + private val originalDialog: Dialog +) { + /** + * The fullscreen dialog to which we will add the content view [originalDialogView] of + * [originalDialog]. + */ + val hostDialog = hostDialogProvider.createHostDialog( + context, R.style.HostDialogTheme, this::onHostDialogCreated, this::onHostDialogDismissed) + + /** The root content view of [hostDialog]. */ + private val hostDialogRoot = FrameLayout(context) + + /** + * The content view of [originalDialog], which will be stolen from that dialog and added to + * [hostDialogRoot]. + */ + private var originalDialogView: View? = null + + /** + * The background color of [originalDialogView], taking into consideration the [originalDialog] + * window background color. + */ + private var originalDialogBackgroundColor = Color.BLACK + + /** + * Whether we are currently launching/showing the dialog by animating it from [touchSurface]. + */ + private var isLaunching = true + + /** Whether we are currently dismissing/hiding the dialog by animating into [touchSurface]. */ + private var isDismissing = false + + private var dismissRequested = false + private var drawHostDialog = false + var ignoreNextCallToHide = false + var exitAnimationDisabled = false + + fun start() { + // Show the host (fullscreen) dialog, to which we will add the stolen dialog view. + hostDialog.show() + + // Steal the dialog view. We do that by showing it but preventing it from drawing, then + // hiding it as soon as its content is available. + stealOriginalDialogContentView(then = this::showDialogFromView) + } + + private fun onHostDialogCreated() { + // Make the dialog fullscreen with a transparent background. + hostDialog.setContentView( + hostDialogRoot, + ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + ) + + val window = hostDialog.window + ?: throw IllegalStateException("There is no window associated to the host dialog") + window.setBackgroundDrawableResource(android.R.color.transparent) + window.setLayout( + WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.MATCH_PARENT + ) + + // Prevent the host dialog from drawing until the animation starts. + hostDialogRoot.viewTreeObserver.addOnPreDrawListener( + object : ViewTreeObserver.OnPreDrawListener { + override fun onPreDraw(): Boolean { + if (drawHostDialog) { + hostDialogRoot.viewTreeObserver.removeOnPreDrawListener(this) + return true + } + + return false + } + } + ) + } + + /** Get the content view of [originalDialog] and pass it to [then]. */ + private fun stealOriginalDialogContentView(then: (View) -> Unit) { + // The original dialog content view will be attached to android.R.id.content when the dialog + // is shown, so we show the dialog and add an observer to get the view but also prevents the + // original dialog from being drawn. + val androidContent = originalDialog.findViewById<ViewGroup>(android.R.id.content) + ?: throw IllegalStateException("Dialog does not have any android.R.id.content view") + + androidContent.viewTreeObserver.addOnPreDrawListener( + object : ViewTreeObserver.OnPreDrawListener { + override fun onPreDraw(): Boolean { + if (androidContent.childCount == 1) { + androidContent.viewTreeObserver.removeOnPreDrawListener(this) + + // Hide the animated dialog. Because of the dialog listener set up + // earlier, this would also hide the host dialog, but in this case we + // need to keep the host dialog visible. + ignoreNextCallToHide = true + originalDialog.hide() + + then(androidContent.getChildAt(0)) + return false + } + + // Never draw the original dialog content. + return false + } + }) + originalDialog.show() + } + + private fun showDialogFromView(dialogView: View) { + // Save the dialog view for later as we will need it for the close animation. + this.originalDialogView = dialogView + + // Close the dialog when clicking outside of it. + hostDialogRoot.setOnClickListener { hostDialog.dismiss() } + dialogView.isClickable = true + + // Set the background of the window dialog to the dialog itself. + // TODO(b/193634619): Support dialog windows without background. + // TODO(b/193634619): Support dialog whose background comes from the content view instead of + // the window. + val typedArray = + originalDialog.context.obtainStyledAttributes(com.android.internal.R.styleable.Window) + val backgroundRes = + typedArray.getResourceId(com.android.internal.R.styleable.Window_windowBackground, 0) + typedArray.recycle() + if (backgroundRes == 0) { + throw IllegalStateException("Dialogs with no backgrounds on window are not supported") + } + + dialogView.setBackgroundResource(backgroundRes) + originalDialogBackgroundColor = + GhostedViewLaunchAnimatorController.findGradientDrawable(dialogView.background!!) + ?.color + ?.defaultColor ?: Color.BLACK + + // Add the dialog view to the host (fullscreen) dialog and make it invisible to make sure + // it's not drawn yet. + (dialogView.parent as? ViewGroup)?.removeView(dialogView) + hostDialogRoot.addView( + dialogView, + + // We give it the size of its original dialog window. + FrameLayout.LayoutParams( + originalDialog.window.attributes.width, + originalDialog.window.attributes.height, + Gravity.CENTER + ) + ) + dialogView.visibility = View.INVISIBLE + + // Start the animation when the dialog is laid out in the center of the host dialog. + dialogView.addOnLayoutChangeListener(object : View.OnLayoutChangeListener { + override fun onLayoutChange( + view: View, + left: Int, + top: Int, + right: Int, + bottom: Int, + oldLeft: Int, + oldTop: Int, + oldRight: Int, + oldBottom: Int + ) { + dialogView.removeOnLayoutChangeListener(this) + startAnimation( + isLaunching = true, + onLaunchAnimationStart = { drawHostDialog = true }, + onLaunchAnimationEnd = { + touchSurface.setTag(R.id.launch_animation_running, null) + + // We hide the touch surface when the dialog is showing. We will make this + // view visible again when dismissing the dialog. + // TODO(b/193634619): Provide an easy way for views to check if they should + // be hidden because of a dialog launch so that they don't override this + // visibility when updating/refreshing itself. + touchSurface.visibility = View.INVISIBLE + + isLaunching = false + + // dismiss was called during the animation, dismiss again now to actually + // dismiss. + if (dismissRequested) { + hostDialog.dismiss() + } + } + ) + } + }) + } + + private fun onHostDialogDismissed(actualDismiss: () -> Unit) { + if (Looper.myLooper() != Looper.getMainLooper()) { + context.mainExecutor.execute { onHostDialogDismissed(actualDismiss) } + return + } + + // TODO(b/193634619): Support interrupting the launch animation in the middle. + if (isLaunching) { + dismissRequested = true + return + } + + if (isDismissing) { + return + } + + isDismissing = true + hideDialogIntoView { instantDismiss: Boolean -> + if (instantDismiss) { + originalDialog.hide() + hostDialog.hide() + } + + originalDialog.dismiss() + actualDismiss() + } + } + + /** + * Hide the dialog into the touch surface and call [dismissDialogs] when the animation is done + * (passing instantDismiss=true) or if it's skipped (passing instantDismiss=false) to actually + * dismiss the dialogs. + */ + private fun hideDialogIntoView(dismissDialogs: (Boolean) -> Unit) { + if (!shouldAnimateDialogIntoView()) { + Log.i(TAG, "Skipping animation of dialog into the touch surface") + + // If the view is invisible it's probably because of us, so we make it visible again. + if (touchSurface.visibility == View.INVISIBLE) { + touchSurface.visibility = View.VISIBLE + } + + dismissDialogs(false /* instantDismiss */) + onDialogDismissed(this@DialogLaunchAnimation) + return + } + + startAnimation( + isLaunching = false, + onLaunchAnimationStart = { + // Remove the dim background as soon as we start the animation. + hostDialog.window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + }, + onLaunchAnimationEnd = { + touchSurface.visibility = View.VISIBLE + originalDialogView!!.visibility = View.INVISIBLE + dismissDialogs(true /* instantDismiss */) + onDialogDismissed(this@DialogLaunchAnimation) + } + ) + } + + private fun startAnimation( + isLaunching: Boolean, + onLaunchAnimationStart: () -> Unit = {}, + onLaunchAnimationEnd: () -> Unit = {} + ) { + val dialogView = this.originalDialogView!! + + // Create 2 ghost controllers to animate both the dialog and the touch surface in the host + // dialog. + val startView = if (isLaunching) touchSurface else dialogView + val endView = if (isLaunching) dialogView else touchSurface + val startViewController = GhostedViewLaunchAnimatorController(startView) + val endViewController = GhostedViewLaunchAnimatorController(endView) + startViewController.launchContainer = hostDialogRoot + endViewController.launchContainer = hostDialogRoot + + val endState = endViewController.createAnimatorState() + val controller = object : LaunchAnimator.Controller { + override var launchContainer: ViewGroup + get() = startViewController.launchContainer + set(value) { + startViewController.launchContainer = value + endViewController.launchContainer = value + } + + override fun createAnimatorState(): LaunchAnimator.State { + return startViewController.createAnimatorState() + } + + override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { + startViewController.onLaunchAnimationStart(isExpandingFullyAbove) + endViewController.onLaunchAnimationStart(isExpandingFullyAbove) + + onLaunchAnimationStart() + } + + override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { + startViewController.onLaunchAnimationEnd(isExpandingFullyAbove) + endViewController.onLaunchAnimationEnd(isExpandingFullyAbove) + + onLaunchAnimationEnd() + } + + override fun onLaunchAnimationProgress( + state: LaunchAnimator.State, + progress: Float, + linearProgress: Float + ) { + startViewController.onLaunchAnimationProgress(state, progress, linearProgress) + + // The end view is visible only iff the starting view is not visible. + state.visible = !state.visible + endViewController.onLaunchAnimationProgress(state, progress, linearProgress) + + // If the dialog content is complex, its dimension might change during the launch + // animation. The animation end position might also change during the exit + // animation, for instance when locking the phone when the dialog is open. Therefore + // we update the end state to the new position/size. Usually the dialog dimension or + // position will change in the early frames, so changing the end state shouldn't + // really be noticeable. + endViewController.fillGhostedViewState(endState) + } + } + + launchAnimator.startAnimation(controller, endState, originalDialogBackgroundColor) + } + + private fun shouldAnimateDialogIntoView(): Boolean { + if (exitAnimationDisabled) { + return false + } + + // The touch surface should be invisible by now, if it's not then something else changed its + // visibility and we probably don't want to run the animation. + if (touchSurface.visibility != View.INVISIBLE) { + return false + } + + // If the touch surface is not attached or one of its ancestors is not visible, then we + // don't run the animation either. + if (!touchSurface.isAttachedToWindow) { + return false + } + + return (touchSurface.parent as? View)?.isShown ?: true + } + + internal fun onDozeAmountChanged(amount: Float) { + val alpha = Interpolators.ALPHA_OUT.getInterpolation(1 - amount) + val decorView = this.hostDialog.window?.decorView ?: return + if (decorView.hasOverlappingRendering() && alpha > 0.0f && + alpha < 1.0f && decorView.layerType != View.LAYER_TYPE_HARDWARE) { + decorView.setLayerType(View.LAYER_TYPE_HARDWARE, null) + } + decorView.alpha = alpha + } +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt index b4ffb3f6cf4e..f7e0d588407f 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt @@ -1,7 +1,24 @@ +/* + * 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.animation import android.graphics.Canvas import android.graphics.ColorFilter +import android.graphics.Insets import android.graphics.Matrix import android.graphics.PixelFormat import android.graphics.Rect @@ -42,6 +59,7 @@ open class GhostedViewLaunchAnimatorController( override var launchContainer = ghostedView.rootView as ViewGroup private val launchContainerOverlay: ViewGroupOverlay get() = launchContainer.overlay + private val launchContainerLocation = IntArray(2) /** The ghost view that is drawn and animated instead of the ghosted view. */ private var ghostView: GhostView? = null @@ -59,8 +77,12 @@ open class GhostedViewLaunchAnimatorController( * [backgroundView]. */ private var backgroundDrawable: WrappedDrawable? = null + private val backgroundInsets by lazy { getBackground()?.opticalInsets ?: Insets.NONE } private var startBackgroundAlpha: Int = 0xFF + private val ghostedViewLocation = IntArray(2) + private val ghostedViewState = LaunchAnimator.State() + /** * Return the background of the [ghostedView]. This background will be used to draw the * background of the background view that is expanding up to the final animation position. This @@ -103,16 +125,24 @@ open class GhostedViewLaunchAnimatorController( return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius } - override fun createAnimatorState(): ActivityLaunchAnimator.State { - val location = ghostedView.locationOnScreen - return ActivityLaunchAnimator.State( - top = location[1], - bottom = location[1] + ghostedView.height, - left = location[0], - right = location[0] + ghostedView.width, + override fun createAnimatorState(): LaunchAnimator.State { + val state = LaunchAnimator.State( topCornerRadius = getCurrentTopCornerRadius(), bottomCornerRadius = getCurrentBottomCornerRadius() ) + fillGhostedViewState(state) + return state + } + + fun fillGhostedViewState(state: LaunchAnimator.State) { + // For the animation we are interested in the area that has a non transparent background, + // so we have to take the optical insets into account. + ghostedView.getLocationOnScreen(ghostedViewLocation) + val insets = backgroundInsets + state.top = ghostedViewLocation[1] + insets.top + state.bottom = ghostedViewLocation[1] + ghostedView.height - insets.bottom + state.left = ghostedViewLocation[0] + insets.left + state.right = ghostedViewLocation[0] + ghostedView.width - insets.right } override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { @@ -144,7 +174,7 @@ open class GhostedViewLaunchAnimatorController( } override fun onLaunchAnimationProgress( - state: ActivityLaunchAnimator.State, + state: LaunchAnimator.State, progress: Float, linearProgress: Float ) { @@ -162,19 +192,47 @@ open class GhostedViewLaunchAnimatorController( return } - val scale = min(state.widthRatio, state.heightRatio) - ghostViewMatrix.setValues(initialGhostViewMatrixValues) - ghostViewMatrix.postScale(scale, scale, state.startCenterX, state.startCenterY) + // The ghost and backgrounds views were made invisible earlier. That can for instance happen + // when animating a dialog into a view. + if (ghostView.visibility == View.INVISIBLE) { + ghostView.visibility = View.VISIBLE + backgroundView.visibility = View.VISIBLE + } + + fillGhostedViewState(ghostedViewState) + val leftChange = state.left - ghostedViewState.left + val rightChange = state.right - ghostedViewState.right + val topChange = state.top - ghostedViewState.top + val bottomChange = state.bottom - ghostedViewState.bottom + + val widthRatio = state.width.toFloat() / ghostedViewState.width + val heightRatio = state.height.toFloat() / ghostedViewState.height + val scale = min(widthRatio, heightRatio) + + launchContainer.getLocationOnScreen(launchContainerLocation) + GhostView.calculateMatrix(ghostedView, launchContainer, ghostViewMatrix) + ghostViewMatrix.postScale( + scale, scale, + ghostedViewState.centerX - launchContainerLocation[0], + ghostedViewState.centerY - launchContainerLocation[1] + ) ghostViewMatrix.postTranslate( - (state.leftChange + state.rightChange) / 2f, - (state.topChange + state.bottomChange) / 2f + (leftChange + rightChange) / 2f, + (topChange + bottomChange) / 2f ) ghostView.animationMatrix = ghostViewMatrix - backgroundView.top = state.top - backgroundView.bottom = state.bottom - backgroundView.left = state.left - backgroundView.right = state.right + // We need to take into account the background insets for the background position. + val insets = backgroundInsets + val topWithInsets = state.top - insets.top + val leftWithInsets = state.left - insets.left + val rightWithInsets = state.right + insets.right + val bottomWithInsets = state.bottom + insets.bottom + + backgroundView.top = topWithInsets - launchContainerLocation[1] + backgroundView.bottom = bottomWithInsets - launchContainerLocation[1] + backgroundView.left = leftWithInsets - launchContainerLocation[0] + backgroundView.right = rightWithInsets - launchContainerLocation[0] val backgroundDrawable = backgroundDrawable!! backgroundDrawable.wrapped?.let { @@ -207,7 +265,7 @@ open class GhostedViewLaunchAnimatorController( * [drawable] is a [LayerDrawable], this will return the first layer that is a * [GradientDrawable]. */ - private fun findGradientDrawable(drawable: Drawable): GradientDrawable? { + fun findGradientDrawable(drawable: Drawable): GradientDrawable? { if (drawable is GradientDrawable) { return drawable } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java index 659b9fee8656..27658824933a 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java @@ -16,6 +16,7 @@ package com.android.systemui.animation; +import android.graphics.Path; import android.util.MathUtils; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AccelerateInterpolator; @@ -29,7 +30,97 @@ import android.view.animation.PathInterpolator; * Utility class to receive interpolators from */ public class Interpolators { - public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + + /* + * ============================================================================================ + * Emphasized interpolators. + * ============================================================================================ + */ + + /** + * The default emphasized interpolator. Used for hero / emphasized movement of content. + */ + public static final Interpolator EMPHASIZED = createEmphasizedInterpolator(); + + /** + * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that + * is disappearing e.g. when moving off screen. + */ + public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator( + 0.3f, 0f, 0.8f, 0.15f); + + /** + * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that + * is appearing e.g. when coming from off screen + */ + public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator( + 0.05f, 0.7f, 0.1f, 1f); + + + /* + * ============================================================================================ + * Standard interpolators. + * ============================================================================================ + */ + + /** + * The standard interpolator that should be used on every normal animation + */ + public static final Interpolator STANDARD = new PathInterpolator( + 0.2f, 0f, 0f, 1f); + + /** + * The standard accelerating interpolator that should be used on every regular movement of + * content that is disappearing e.g. when moving off screen. + */ + public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator( + 0.3f, 0f, 1f, 1f); + + /** + * The standard decelerating interpolator that should be used on every regular movement of + * content that is appearing e.g. when coming from off screen. + */ + public static final Interpolator STANDARD_DECELERATE = new PathInterpolator( + 0f, 0f, 0f, 1f); + + /* + * ============================================================================================ + * Legacy + * ============================================================================================ + */ + + /** + * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN. + */ + public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + + /** + * The default legacy accelerating interpolator as defined in Material 1. + * Also known as FAST_OUT_LINEAR_IN. + */ + public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f); + + /** + * The default legacy decelerating interpolator as defined in Material 1. + * Also known as LINEAR_OUT_SLOW_IN. + */ + public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f); + + /** + * Linear interpolator. Often used if the interpolator is for different properties who need + * different interpolations. + */ + public static final Interpolator LINEAR = new LinearInterpolator(); + + /* + * ============================================================================================ + * Custom interpolators + * ============================================================================================ + */ + + public static final Interpolator FAST_OUT_SLOW_IN = LEGACY; + public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE; + public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE; /** * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t @@ -37,12 +128,9 @@ public class Interpolators { */ public static final Interpolator FAST_OUT_SLOW_IN_REVERSE = new PathInterpolator(0.8f, 0f, 0.6f, 1f); - public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); - public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f); public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f); - public static final Interpolator LINEAR = new LinearInterpolator(); public static final Interpolator ACCELERATE = new AccelerateInterpolator(); public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator(); public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f); @@ -72,6 +160,12 @@ public class Interpolators { public static final Interpolator TOUCH_RESPONSE_REVERSE = new PathInterpolator(0.9f, 0f, 0.7f, 1f); + /* + * ============================================================================================ + * Functions / Utilities + * ============================================================================================ + */ + /** * Calculate the amount of overshoot using an exponential falloff function with desired * properties, where the overshoot smoothly transitions at the 1.0f boundary into the @@ -122,4 +216,14 @@ public class Interpolators { return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * oneMinusFrac * oneMinusFrac))); } } + + // Create the default emphasized interpolator + private static PathInterpolator createEmphasizedInterpolator() { + Path path = new Path(); + // Doing the same as fast_out_extra_slow_in + path.moveTo(0f, 0f); + path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f); + path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f); + return new PathInterpolator(path); + } } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt new file mode 100644 index 000000000000..3bf6c5ebd091 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt @@ -0,0 +1,355 @@ +/* + * 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.animation + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.ValueAnimator +import android.content.Context +import android.graphics.PorterDuff +import android.graphics.PorterDuffXfermode +import android.graphics.drawable.GradientDrawable +import android.util.Log +import android.util.MathUtils +import android.view.View +import android.view.ViewGroup +import android.view.animation.AnimationUtils +import android.view.animation.PathInterpolator +import kotlin.math.roundToInt + +private const val TAG = "LaunchAnimator" + +/** A base class to animate a window launch (activity or dialog) from a view . */ +class LaunchAnimator @JvmOverloads constructor( + context: Context, + private val isForTesting: Boolean = false +) { + companion object { + internal const val DEBUG = false + const val ANIMATION_DURATION = 500L + private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L + private const val ANIMATION_DURATION_FADE_IN_WINDOW = 183L + private const val ANIMATION_DELAY_FADE_IN_WINDOW = ANIMATION_DURATION_FADE_OUT_CONTENT + + private val WINDOW_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0.6f, 1f) + private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC) + + /** + * Given the [linearProgress] of a launch animation, return the linear progress of the + * sub-animation starting [delay] ms after the launch animation and that lasts [duration]. + */ + @JvmStatic + fun getProgress(linearProgress: Float, delay: Long, duration: Long): Float { + return MathUtils.constrain( + (linearProgress * ANIMATION_DURATION - delay) / duration, + 0.0f, + 1.0f + ) + } + } + + /** The interpolator used for the width, height, Y position and corner radius. */ + private val animationInterpolator = AnimationUtils.loadInterpolator(context, + R.interpolator.launch_animation_interpolator_y) + + /** The interpolator used for the X position. */ + private val animationInterpolatorX = AnimationUtils.loadInterpolator(context, + R.interpolator.launch_animation_interpolator_x) + + private val launchContainerLocation = IntArray(2) + private val cornerRadii = FloatArray(8) + + /** + * A controller that takes care of applying the animation to an expanding view. + * + * Note that all callbacks (onXXX methods) are all called on the main thread. + */ + interface Controller { + /** + * The container in which the view that started the animation will be animating together + * with the opening window. + * + * This will be used to: + * - Get the associated [Context]. + * - Compute whether we are expanding fully above the launch container. + * - Apply surface transactions in sync with RenderThread when animating an activity + * launch. + * + * This container can be changed to force this [Controller] to animate the expanding view + * inside a different location, for instance to ensure correct layering during the + * animation. + */ + var launchContainer: ViewGroup + + /** + * Return the [State] of the view that will be animated. We will animate from this state to + * the final window state. + * + * Note: This state will be mutated and passed to [onLaunchAnimationProgress] during the + * animation. + */ + fun createAnimatorState(): State + + /** + * The animation started. This is typically used to initialize any additional resource + * needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding + * fully above the [launchContainer]. + */ + fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {} + + /** The animation made progress and the expandable view [state] should be updated. */ + fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {} + + /** + * The animation ended. This will be called *if and only if* [onLaunchAnimationStart] was + * called previously. This is typically used to clean up the resources initialized when the + * animation was started. + */ + fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {} + } + + /** The state of an expandable view during a [LaunchAnimator] animation. */ + open class State( + /** The position of the view in screen space coordinates. */ + var top: Int = 0, + var bottom: Int = 0, + var left: Int = 0, + var right: Int = 0, + + var topCornerRadius: Float = 0f, + var bottomCornerRadius: Float = 0f + ) { + private val startTop = top + + val width: Int + get() = right - left + + val height: Int + get() = bottom - top + + open val topChange: Int + get() = top - startTop + + val centerX: Float + get() = left + width / 2f + + val centerY: Float + get() = top + height / 2f + + /** Whether the expanding view should be visible or hidden. */ + var visible: Boolean = true + } + + interface Animation { + /** Cancel the animation. */ + fun cancel() + } + + /** + * Start a launch animation controlled by [controller] towards [endState]. An intermediary + * layer with [windowBackgroundColor] will fade in then fade out above the expanding view, and + * should be the same background color as the opening (or closing) window. If [drawHole] is + * true, then this intermediary layer will be drawn with SRC blending mode while it fades out. + * + * TODO(b/184121838): Remove [drawHole] and instead make the StatusBar draw this hole instead. + */ + fun startAnimation( + controller: Controller, + endState: State, + windowBackgroundColor: Int, + drawHole: Boolean = false + ): Animation { + val state = controller.createAnimatorState() + + // Start state. + val startTop = state.top + val startBottom = state.bottom + val startLeft = state.left + val startRight = state.right + val startCenterX = (startLeft + startRight) / 2f + val startWidth = startRight - startLeft + val startTopCornerRadius = state.topCornerRadius + val startBottomCornerRadius = state.bottomCornerRadius + + // End state. + var endTop = endState.top + var endBottom = endState.bottom + var endLeft = endState.left + var endRight = endState.right + var endCenterX = (endLeft + endRight) / 2f + var endWidth = endRight - endLeft + val endTopCornerRadius = endState.topCornerRadius + val endBottomCornerRadius = endState.bottomCornerRadius + + fun maybeUpdateEndState() { + if (endTop != endState.top || endBottom != endState.bottom || + endLeft != endState.left || endRight != endState.right) { + endTop = endState.top + endBottom = endState.bottom + endLeft = endState.left + endRight = endState.right + endCenterX = (endLeft + endRight) / 2f + endWidth = endRight - endLeft + } + } + + val launchContainer = controller.launchContainer + val isExpandingFullyAbove = isExpandingFullyAbove(launchContainer, endState) + + // We add an extra layer with the same color as the dialog/app splash screen background + // color, which is usually the same color of the app background. We first fade in this layer + // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the + // launch container and reveal the opening window. + val windowBackgroundLayer = GradientDrawable().apply { + setColor(windowBackgroundColor) + alpha = 0 + } + + // Update state. + val animator = ValueAnimator.ofFloat(0f, 1f) + animator.duration = if (isForTesting) 0 else ANIMATION_DURATION + animator.interpolator = Interpolators.LINEAR + + val launchContainerOverlay = launchContainer.overlay + var cancelled = false + animator.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator?, isReverse: Boolean) { + if (DEBUG) { + Log.d(TAG, "Animation started") + } + controller.onLaunchAnimationStart(isExpandingFullyAbove) + + // Add the drawable to the launch container overlay. Overlays always draw + // drawables after views, so we know that it will be drawn above any view added + // by the controller. + launchContainerOverlay.add(windowBackgroundLayer) + } + + override fun onAnimationEnd(animation: Animator?) { + if (DEBUG) { + Log.d(TAG, "Animation ended") + } + controller.onLaunchAnimationEnd(isExpandingFullyAbove) + launchContainerOverlay.remove(windowBackgroundLayer) + } + }) + + animator.addUpdateListener { animation -> + if (cancelled) { + // TODO(b/184121838): Cancel the animator directly instead of just skipping the + // update. + return@addUpdateListener + } + + maybeUpdateEndState() + + // TODO(b/184121838): Use reverse interpolators to get the same path/arc as the non + // reversed animation. + val linearProgress = animation.animatedFraction + val progress = animationInterpolator.getInterpolation(linearProgress) + val xProgress = animationInterpolatorX.getInterpolation(linearProgress) + + val xCenter = MathUtils.lerp(startCenterX, endCenterX, xProgress) + val halfWidth = MathUtils.lerp(startWidth, endWidth, progress) / 2f + + state.top = MathUtils.lerp(startTop, endTop, progress).roundToInt() + state.bottom = MathUtils.lerp(startBottom, endBottom, progress).roundToInt() + state.left = (xCenter - halfWidth).roundToInt() + state.right = (xCenter + halfWidth).roundToInt() + + state.topCornerRadius = + MathUtils.lerp(startTopCornerRadius, endTopCornerRadius, progress) + state.bottomCornerRadius = + MathUtils.lerp(startBottomCornerRadius, endBottomCornerRadius, progress) + + // The expanding view can/should be hidden once it is completely covered by the opening + // window. + state.visible = getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT) < 1 + + applyStateToWindowBackgroundLayer( + windowBackgroundLayer, + state, + linearProgress, + launchContainer, + drawHole + ) + controller.onLaunchAnimationProgress(state, progress, linearProgress) + } + + animator.start() + return object : Animation { + override fun cancel() { + cancelled = true + animator.cancel() + } + } + } + + /** Return whether we are expanding fully above the [launchContainer]. */ + internal fun isExpandingFullyAbove(launchContainer: View, endState: State): Boolean { + launchContainer.getLocationOnScreen(launchContainerLocation) + return endState.top <= launchContainerLocation[1] && + endState.bottom >= launchContainerLocation[1] + launchContainer.height && + endState.left <= launchContainerLocation[0] && + endState.right >= launchContainerLocation[0] + launchContainer.width + } + + private fun applyStateToWindowBackgroundLayer( + drawable: GradientDrawable, + state: State, + linearProgress: Float, + launchContainer: View, + drawHole: Boolean + ) { + // Update position. + launchContainer.getLocationOnScreen(launchContainerLocation) + drawable.setBounds( + state.left - launchContainerLocation[0], + state.top - launchContainerLocation[1], + state.right - launchContainerLocation[0], + state.bottom - launchContainerLocation[1] + ) + + // Update radius. + cornerRadii[0] = state.topCornerRadius + cornerRadii[1] = state.topCornerRadius + cornerRadii[2] = state.topCornerRadius + cornerRadii[3] = state.topCornerRadius + cornerRadii[4] = state.bottomCornerRadius + cornerRadii[5] = state.bottomCornerRadius + cornerRadii[6] = state.bottomCornerRadius + cornerRadii[7] = state.bottomCornerRadius + drawable.cornerRadii = cornerRadii + + // We first fade in the background layer to hide the expanding view, then fade it out + // with SRC mode to draw a hole punch in the status bar and reveal the opening window. + val fadeInProgress = getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT) + if (fadeInProgress < 1) { + val alpha = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(fadeInProgress) + drawable.alpha = (alpha * 0xFF).roundToInt() + } else { + val fadeOutProgress = getProgress( + linearProgress, ANIMATION_DELAY_FADE_IN_WINDOW, ANIMATION_DURATION_FADE_IN_WINDOW) + val alpha = 1 - WINDOW_FADE_IN_INTERPOLATOR.getInterpolation(fadeOutProgress) + drawable.alpha = (alpha * 0xFF).roundToInt() + + if (drawHole) { + drawable.setXfermode(SRC_MODE) + } + } + } +} diff --git a/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml b/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml new file mode 100644 index 000000000000..08c66a24348c --- /dev/null +++ b/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> + <item android:color="?androidprv:attr/colorAccentSecondaryVariant"/> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml index dd35dd91f5d6..1eec8204a7f2 100644 --- a/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml +++ b/packages/SystemUI/res-keyguard/drawable/ic_backspace_24dp.xml @@ -20,6 +20,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:fillColor="?android:attr/colorBackground" + android:fillColor="?android:attr/textColorPrimaryInverse" android:pathData="M9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12L19,15.59L17.59,17L14,13.41L10.41,17L9,15.59zM21,6H8l-4.5,6L8,18h13V6M21,4c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H8c-0.63,0 -1.22,-0.3 -1.6,-0.8L1,12l5.4,-7.2C6.78,4.3 7.37,4 8,4H21L21,4z"/> </vector> diff --git a/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml index b844515f1088..2ad5e54eb92a 100644 --- a/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml +++ b/packages/SystemUI/res-keyguard/drawable/ic_keyboard_tab_36dp.xml @@ -19,7 +19,8 @@ android:viewportHeight="36" android:viewportWidth="36" android:width="36sp"> - <path android:fillColor="?android:attr/colorBackground" + + <path android:fillColor="?android:attr/textColorPrimaryInverse" android:pathData="M17.59,13.41L21.17,17H7v2h14.17l-3.59,3.59L19,24l6,-6l-6,-6L17.59, 13.41zM26,12v12h2V12H26z"/> </vector> diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 624ee9f51b2a..6e89fb0169ab 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -17,7 +17,7 @@ */ --> -<resources> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Keyguard PIN pad styles --> <style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView"> <item name="android:textSize">@dimen/kg_status_line_font_size</item> @@ -58,11 +58,11 @@ <item name="android:textColor">?android:attr/textColorPrimary</item> </style> <style name="NumPadKey.Delete"> - <item name="android:colorControlNormal">?android:attr/textColorSecondary</item> + <item name="android:colorControlNormal">@color/numpad_key_color_secondary</item> <item name="android:src">@drawable/ic_backspace_24dp</item> </style> <style name="NumPadKey.Enter"> - <item name="android:colorControlNormal">?android:attr/textColorSecondary</item> + <item name="android:colorControlNormal">@color/numpad_key_color_secondary</item> <item name="android:src">@drawable/ic_keyboard_tab_36dp</item> </style> <style name="Widget.TextView.NumPadKey.Klondike" diff --git a/packages/SystemUI/res/drawable/media_output_dialog_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_background.xml deleted file mode 100644 index 3ceb0f6ac06a..000000000000 --- a/packages/SystemUI/res/drawable/media_output_dialog_background.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2020 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<inset xmlns:android="http://schemas.android.com/apk/res/android"> - <shape android:shape="rectangle"> - <corners android:radius="8dp" /> - <solid android:color="?android:attr/colorBackground" /> - </shape> -</inset> diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml index 6a9254cad8f4..21c5ab04eb9a 100644 --- a/packages/SystemUI/res/layout/global_screenshot_static.xml +++ b/packages/SystemUI/res/layout/global_screenshot_static.xml @@ -130,13 +130,4 @@ app:layout_constraintStart_toStartOf="@id/global_screenshot_preview" app:layout_constraintTop_toTopOf="@id/global_screenshot_preview" android:elevation="@dimen/screenshot_preview_elevation"/> - <View - android:id="@+id/screenshot_transition_view" - android:layout_width="0dp" - android:layout_height="0dp" - android:visibility="invisible" - app:layout_constraintStart_toStartOf="@id/global_screenshot_preview" - app:layout_constraintTop_toTopOf="@id/global_screenshot_preview" - app:layout_constraintEnd_toEndOf="@id/global_screenshot_preview" - app:layout_constraintBottom_toBottomOf="@id/global_screenshot_preview"/> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 918635d666fa..c1d7308be5a8 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -19,7 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/internet_connectivity_dialog" - android:layout_width="@dimen/internet_dialog_list_max_width" + android:layout_width="@dimen/large_dialog_width" android:layout_height="@dimen/internet_dialog_list_max_height" android:background="@drawable/internet_dialog_rounded_top_corner_background" android:orientation="vertical"> diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml index d996cee4b39e..b33889469f48 100644 --- a/packages/SystemUI/res/layout/media_output_dialog.xml +++ b/packages/SystemUI/res/layout/media_output_dialog.xml @@ -18,7 +18,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/media_output_dialog" - android:layout_width="match_parent" + android:layout_width="@dimen/large_dialog_width" android:layout_height="wrap_content" android:orientation="vertical"> diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml index 566cd25e86a5..b546a9cbe90e 100644 --- a/packages/SystemUI/res/layout/media_view.xml +++ b/packages/SystemUI/res/layout/media_view.xml @@ -134,6 +134,7 @@ android:background="@drawable/qs_media_light_source" android:forceHasOverlappingRendering="false"> <LinearLayout + android:id="@+id/media_seamless_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:minHeight="@dimen/qs_seamless_height" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 4b6e58fbd1e5..18315f1dff42 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -25,12 +25,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent"> - <FrameLayout - android:id="@+id/big_clock_container" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:visibility="gone" /> - <ViewStub android:id="@+id/keyguard_qs_user_switch_stub" android:layout="@layout/keyguard_qs_user_switch" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 5cd99f29bbab..f589498c377a 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontsluit om netwerke te bekyk"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Soek tans na netwerke …"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kon nie aan netwerk koppel nie"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string> <string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 2f485ada1186..e94dc688ac7c 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"አውታረ መረቦችን ለመመልከት ይክፈቱ"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"አውታረ መረቦችን በመፈለግ ላይ…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ከአውታረ መረቡ ጋር መገናኘት አልተሳካም"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi ለአሁን በራስ-ሰር አይገናኝም"</string> <string name="see_all_networks" msgid="3773666844913168122">"ሁሉንም ይመልከቱ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"አውታረ መረቦችን ለመቀየር፣ የኢተርኔት ግንኙነት ያቋርጡ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 81a7f7c29ff2..14753dabb464 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1199,6 +1199,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"فتح القفل لعرض الشبكات"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"جارٍ البحث عن شبكات…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"تعذّر الاتصال بالشبكة."</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"لن يتم الاتصال بشبكة Wi-Fi تلقائيًا في الوقت الحالي."</string> <string name="see_all_networks" msgid="3773666844913168122">"عرض الكل"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"للتبديل بين الشبكات، يجب فصل إيثرنت."</string> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index d73fd7357c5d..a50d8c10dd3f 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটৱর্ক চাবলৈ আনলক কৰক"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটৱৰ্ক সন্ধান কৰি থকা হৈছে…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটৱৰ্কৰ সৈতে সংযোগ কৰিব পৰা নগ\'ল"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"এতিয়া ৱাই-ফাই স্বয়ংক্ৰিয়ভাৱে সংযুক্ত নহ’ব"</string> <string name="see_all_networks" msgid="3773666844913168122">"আটাইবোৰ চাওক"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটৱৰ্ক সলনি কৰিবলৈ ইথাৰনেটৰ পৰা সংযোগ বিচ্ছিন্ন কৰক"</string> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index f7746e8b6397..e0ef1eca3282 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Şəbəkələrə baxmaq üçün kilidi açın"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Şəbəkə axtarılır…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Şəbəkəyə qoşulmaq alınmadı"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hələlik avtomatik qoşulmayacaq"</string> <string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Şəbəkəni dəyişmək üçün etherneti ayırın"</string> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 72efc72a36f2..31f8014e8b6c 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1181,6 +1181,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da biste videli mreže"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traže se mreže…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje sa mrežom nije uspelo"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi trenutno ne može da se automatski poveže"</string> <string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste promenili mrežu, prekinite eternet vezu"</string> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index f7c20ab54895..b296aa63eedb 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблакіраваць для прагляду сетак"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Выконваецца пошук сетак…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не ўдалося падключыцца да сеткі"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Аўтаматычнае падключэнне да Wi-Fi адсутнічае"</string> <string name="see_all_networks" msgid="3773666844913168122">"Паказаць усе"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Каб падключыцца да сетак, выключыце Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index b4164a003a1a..84c22912a322 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отключване с цел преглед на мрежите"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Търсят се мрежи…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Свързването с мрежата не бе успешно"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Засега Wi-Fi няма да се свързва автоматично"</string> <string name="see_all_networks" msgid="3773666844913168122">"Вижте всички"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За да превключите мрежите, прекъснете връзката с Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 92da7de7286e..57e70a6772a0 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটওয়ার্ক দেখার জন্য আনলক করুন"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটওয়ার্ক সার্চ করা হচ্ছে…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটওয়ার্কে কানেক্ট করা যায়নি"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"এখন ওয়াই-ফাই নিজে থেকে কানেক্ট হবে না"</string> <string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"নেটওয়ার্ক বদলাতে ইথারনেট ডিসকানেক্ট করুন"</string> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index e913d56be38b..c8588ecd4cdd 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1181,6 +1181,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da vidite mreže"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi se trenutno ne može automatski povezati"</string> <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index be384e372993..cfe70c2a22c9 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueja per veure xarxes"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"S\'estan cercant xarxes…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No s\'ha pogut connectar a la xarxa"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Per ara la Wi‑Fi no es connectarà automàticament"</string> <string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per canviar de xarxa, desconnecta la connexió Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 5be30774348c..3d648cb03309 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sítě uvidíte po odemknutí"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhledávání sítí…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Připojení k síti se nezdařilo"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se prozatím nebude připojovat automaticky"</string> <string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pokud chcete přepnout sítě, odpojte ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 2c7ffe5154b1..eb715aa8e7ca 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås op for at se netværk"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søger efter netværk…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Der kunne ikke oprettes forbindelse til netværket"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Ingen automatisk forbindelse til Wi-Fi i øjeblikket"</string> <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Afbryd ethernetforbindelsen for at skifte netværk"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 9c39acdd56f2..b8154923bd63 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Entsperren, um Netzwerke anzuzeigen"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netzwerke werden gesucht…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Netzwerkverbindung konnte nicht hergestellt werden"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Zurzeit wird keine automatische WLAN-Verbindung hergestellt"</string> <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Trenne das Ethernetkabel, um das Netzwerk zu wechseln"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 8705ad094e86..c6cc7f0d4212 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ξεκλειδώστε για προβολή δικτύων"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Αναζήτηση δικτύων…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Αποτυχία σύνδεσης στο δίκτυο"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Δεν θα γίνεται προς το παρόν αυτόματη σύνδεση Wi-Fi."</string> <string name="see_all_networks" msgid="3773666844913168122">"Εμφάνιση όλων"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Για εναλλαγή δικτύων, αποσυνδέστε το ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index a2bcfd1a41eb..e1006fc83780 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 1cc3cd37a8e5..66b44d5ecf8b 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index a2bcfd1a41eb..e1006fc83780 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index a2bcfd1a41eb..e1006fc83780 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 71a1c2fb5f34..9af7322e8507 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi won’t auto-connect for now"</string> <string name="see_all_networks" msgid="3773666844913168122">"See all"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"To switch networks, disconnect ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 0454e73be3d8..8d53bb99f3e0 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver las redes"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Se produjo un error al establecer conexión con la red"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora, el Wi-Fi no se conectará automáticamente"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconéctate de Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 0751362138bf..c0c12fa7ddc8 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver redes"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No se ha podido conectar a la red"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por ahora no se conectará automáticamente a redes Wi-Fi"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de red, desconecta el cable Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 16920069b3db..c3cb5520db83 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Võrkude vaatamiseks avage"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Võrkude otsimine …"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Võrguühenduse loomine ebaõnnestus"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi-ühendust ei looda praegu automaatselt"</string> <string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Võrkude vahetamiseks katkestage Etherneti-ühendus"</string> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 8055cfec1994..8df329a899e3 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -845,7 +845,7 @@ <string name="keyboard_shortcut_group_applications_browser" msgid="2776211137869809251">"Arakatzailea"</string> <string name="keyboard_shortcut_group_applications_contacts" msgid="2807268086386201060">"Kontaktuak"</string> <string name="keyboard_shortcut_group_applications_email" msgid="7852376788894975192">"Posta"</string> - <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMS mezuak"</string> + <string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"SMSak"</string> <string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"Musika"</string> <string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string> <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string> @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sareak ikusteko, desblokeatu pantaila"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Sareak bilatzen…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ezin izan da konektatu sarera"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Oraingoz ez da automatikoki konektatuko wifira"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Sarea aldatzeko, deskonektatu Ethernet-a"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 74f23ac3bbd8..ae308b7ed434 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"برای مشاهده شبکهها، قفل صفحه را باز کنید"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"درحال جستجوی شبکه…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"اتصال به شبکه برقرار نشد"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"فعلاً Wi-Fi بهطور خودکار متصل نمیشود"</string> <string name="see_all_networks" msgid="3773666844913168122">"مشاهده همه"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"برای تغییر شبکه، اترنت را قطع کنید"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index f1144072f0d3..ee0cdb65a83d 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Avaa lukitus nähdäksesi verkot"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Etsitään verkkoja…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yhteyden muodostaminen verkkoon epäonnistui"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ei toistaiseksi yhdistä automaattisesti"</string> <string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Irrota Ethernet-johto, jos haluat vaihtaa verkkoa"</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 35ed848a17a3..7fcbcfb6eb0b 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouillez l\'écran pour afficher les réseaux Wi-Fi"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux en cours…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi impossible pour le moment"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, débranchez le câble Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 514c434be920..74e55fc90687 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouiller pour afficher les réseaux"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connexion automatique au Wi-Fi désactivée pour le moment"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pour changer de réseau, déconnectez l\'Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 1eba1ed4d301..3bcfcc8e6a88 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea a pantalla para ver as redes"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Produciuse un erro ao conectarse á rede"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"De momento, a wifi non se conectará automaticamente"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para cambiar de rede, desconecta a Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 2c4e6e5627fb..e713cb79f6dc 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"વાઇ-ફાઇ નેટવર્ક જોવા માટે અનલૉક કરો"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"નેટવર્ક શોધી રહ્યાં છીએ…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"નેટવર્ક સાથે કનેક્ટ કરવામાં નિષ્ફળ થયાં"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"હમણાં પૂરતું વાઇ-ફાઇ ઑટોમૅટિક રીતે કનેક્ટ થશે નહીં"</string> <string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"બીજા નેટવર્ક પર જવા માટે, ઇથરનેટ ડિસ્કનેક્ટ કરો"</string> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 3eb45ea8ee82..edd7fc6799bf 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"वाई-फ़ाई नेटवर्क देखने के लिए, स्क्रीन को अनलॉक करें"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क खोजे जा रहे हैं…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्क से कनेक्ट नहीं किया जा सका"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"फ़िलहाल, वाई-फ़ाई अपने-आप कनेक्ट नहीं होगा"</string> <string name="see_all_networks" msgid="3773666844913168122">"सभी देखें"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदलने के लिए, पहले ईथरनेट को डिसकनेक्ट करें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 97dbf591a84f..b066191b021a 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1181,6 +1181,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte za prikaz mreža"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi se zasad neće automatski povezivati"</string> <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da biste se prebacili na drugu mrežu, odspojite Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index ddff2c20cb9c..5880cf0abb02 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Zárolás feloldása a hálózatok megtekintéséhez"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Hálózatok keresése…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nem sikerült hálózathoz csatlakozni."</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A Wi-Fi-re történő csatlakozás jelenleg nem automatikus"</string> <string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Hálózatváltáshoz válassza le az ethernetet"</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 3100b9c72000..ad3cf25467d9 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ապակողպեք՝ ցանցերը դիտելու համար"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ցանցերի որոնում…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Չհաջողվեց միանալ ցանցին"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-ն ավտոմատ չի միանա"</string> <string name="see_all_networks" msgid="3773666844913168122">"Տեսնել բոլորը"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Մի ցանցից մյուսին անցնելու համար անջատեք Ethernet-ը"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 80f6ed4d4ed7..c42b143709c1 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat jaringan"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari jaringan …"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menghubungkan ke jaringan"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan otomatis terhubung untuk saat ini"</string> <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk beralih jaringan, lepaskan kabel ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 2732b71dca14..469228065c8d 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Taktu úr lás til að skoða netkerfi"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Leitar að netum…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ekki tókst að tengjast neti"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tengist ekki sjálfkrafa eins og er"</string> <string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aftengdu ethernet til að skipta um net"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 9410c99ad54c..1d96598be708 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sblocca per visualizzare le reti"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ricerca di reti in corso…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Connessione alla rete non riuscita"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Connessione automatica rete Wi-Fi non attiva al momento"</string> <string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Per cambiare rete, scollega il cavo Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index f6b74c389305..8fd2bb9abf22 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"צריך לבטל את הנעילה כדי להציג את הרשתות"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"בתהליך חיפוש רשתות…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"נכשל הניסיון להתחבר לרשת"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ה-Wi-Fi לא יתחבר באופן אוטומטי בינתיים"</string> <string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index aa6aa3c7f374..3134f73605c1 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ネットワークを表示するにはロック解除してください"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ネットワークを検索しています…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ネットワークに接続できませんでした"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi に自動接続しません"</string> <string name="see_all_networks" msgid="3773666844913168122">"すべて表示"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ネットワークを変更するにはイーサネット接続を解除してください"</string> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index ac604701827d..c4c73c5cb912 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"განბლოკვა ქსელების სანახავად"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"მიმდინარეობს ქსელების ძიება…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ქსელთან დაკავშირება ვერ ხერხდება"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ინტერნეტს დროებით ავტომატურად არ დაუკავშირდება"</string> <string name="see_all_networks" msgid="3773666844913168122">"ყველას ნახვა"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ქსელების გადასართავად, გაწყვიტეთ Ethernet-თან კავშირი"</string> </resources> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index fd2bcc7df5a2..bccc0ab7d937 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Желілерді көру үшін құлыпты ашыңыз."</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Маңайдағы желілер ізделуде…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Желіге қосылмады."</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Әзірше Wi-Fi автоматты түрде қосылмайды."</string> <string name="see_all_networks" msgid="3773666844913168122">"Барлығын көру"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Желілерді ауыстыру үшін ethernet кабелін ажыратыңыз."</string> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 035319ef682b..7d79023c1c61 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ដោះសោដើម្បីមើលបណ្ដាញ"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"កំពុងស្វែងរកបណ្ដាញ…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"មិនអាចភ្ជាប់បណ្ដាញបានទេ"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិក្នុងពេលនេះទេ"</string> <string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បីប្ដូរបណ្ដាញ សូមផ្ដាច់អ៊ីសឺរណិត"</string> </resources> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 1d8fbb3fe777..ca69a82a1295 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ಸದ್ಯದ ಮಟ್ಟಿಗೆ ವೈ-ಫೈ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗುವುದಿಲ್ಲ"</string> <string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ಬದಲಿಸಲು, ಇಥರ್ನೆಟ್ ಅನ್ನು ಡಿಸ್ಕನೆಕ್ಟ್ ಮಾಡಿ"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 751bfd8a8e32..3a8657ba30a6 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"네트워크를 보려면 잠금 해제하세요"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"네트워크 검색 중…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"네트워크에 연결하지 못했습니다."</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"지금은 Wi-Fi가 자동으로 연결되지 않습니다."</string> <string name="see_all_networks" msgid="3773666844913168122">"모두 보기"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"네트워크를 전환하려면 이더넷을 연결 해제하세요."</string> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 343457226160..9f242f34b300 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Тармактарды көрүү үчүн кулпусун ачыңыз"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Тармактар изделүүдө…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Тармакка туташпай калды"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi азырынча автоматтык түрдө туташпайт"</string> <string name="see_all_networks" msgid="3773666844913168122">"Баарын көрүү"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Башка тармактарга которулуу үчүн Ethernet кабелин ажыратыңыз"</string> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index b603ca6ac06e..afd914d738ae 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ປົດລັອກເພື່ອເບິ່ງເຄືອຂ່າຍ"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ກຳລັງຊອກຫາເຄືອຂ່າຍ…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ເຊື່ອມຕໍ່ເຄືອຂ່າຍບໍ່ສຳເລັດ"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດສຳລັບຕອນນີ້"</string> <string name="see_all_networks" msgid="3773666844913168122">"ເບິ່ງທັງໝົດ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ເພື່ອສະຫຼັບເຄືອຂ່າຍ, ໃຫ້ຕັດການເຊື່ອມຕໍ່ອີເທີເນັດກ່ອນ"</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 657c95b79534..233610f00cd0 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Atrakinkite, kad peržiūrėtumėte visus tinklus"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ieškoma tinklų…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Jungiantis prie tinklo įvyko klaida"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"„Wi-Fi“ šiuo metu nebus prijungtas automatiškai"</string> <string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Norėdami perjungti tinklus, atjunkite eternetą"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index f5927db7c26c..83e6d6e514ea 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1181,6 +1181,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lai skatītu tīklus, atbloķējiet"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Notiek tīklu meklēšana…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Neizdevās izveidot savienojumu ar tīklu"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi savienojums īslaicīgi netiks izveidots automātiski."</string> <string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Lai pārslēgtu tīklus, atvienojiet tīkla Ethernet vadu."</string> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 396fab5d1444..e00108a7b9fb 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отклучете за да се прикажат мрежите"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Се пребаруваат мрежи…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не успеа да се поврзе на мрежата"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi нема да се поврзува автоматски засега"</string> <string name="see_all_networks" msgid="3773666844913168122">"Прикажи ги сите"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"За промена на мрежата, прекинете ја врската со етернетот"</string> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 6d92e8a46b5e..49beea2dcb32 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"നെറ്റ്വർക്കുകൾ കാണാൻ അൺലോക്ക് ചെയ്യുക"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"നെറ്റ്വർക്കുകൾ തിരയുന്നു…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"നെറ്റ്വർക്കിൽ കണക്റ്റ് ചെയ്യാനായില്ല"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"വൈഫൈ ഇപ്പോൾ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string> <string name="see_all_networks" msgid="3773666844913168122">"എല്ലാം കാണുക"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"മറ്റ് നെറ്റ്വർക്കുകളിലേക്ക് മാറാൻ, ഇതർനെറ്റ് വിച്ഛേദിക്കുക"</string> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 3968d52a84f4..f6dea18f0417 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Сүлжээг харахын тулд түгжээг тайлах"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Сүлжээ хайж байна…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Сүлжээнд холбогдож чадсангүй"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi-г одоогоор автоматаар холбохгүй"</string> <string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Сүлжээг сэлгэхийн тулд этернэтийг салгана уу"</string> </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 69c829c496c8..6156cf592def 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्क पाहण्यासाठी स्क्रीन अनलॉक करा"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क शोधत आहे…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कशी कनेक्ट करता आले नाही"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"सध्या वाय-फाय ऑटो-कनेक्ट होणार नाही"</string> <string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क स्विच करण्यासाठी, इथरनेट केबल डिस्कनेक्ट करा"</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index ebe0094d3392..9dde6b667bc5 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat rangkaian"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari rangkaian…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menyambung kepada rangkaian"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi tidak akan disambungkan secara automatik buat masa ini"</string> <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Untuk menukar rangkaian, putuskan sambungan ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 42ed54c91ac4..666f9edf8e59 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ကွန်ရက်များကြည့်ရန် ဖွင့်ပါ"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ကွန်ရက်များကို ရှာဖွေနေသည်…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ကွန်ရက်သို့ ချိတ်ဆက်၍မရပါ"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi က လောလောဆယ် အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string> <string name="see_all_networks" msgid="3773666844913168122">"အားလုံးကြည့်ရန်"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ကွန်ရက်ပြောင်းရန် အီသာနက်ကို ချိတ်ဆက်မှုဖြုတ်ပါ"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 3337aa1daeef..d4eef721d76e 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås opp for å se nettverk"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søker etter nettverk …"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kunne ikke koble til nettverket"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi kobles ikke til automatisk inntil videre"</string> <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index a7113f3c0081..ce1787c26897 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्कहरू हेर्न आफ्नो स्क्रिन अनलक गर्नुहोस्"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्कहरू खोजिँदै छन्…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कमा कनेक्ट गर्न सकिएन"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"केही समयका लागि Wi-Fi स्वतः कनेक्ट हुँदैन"</string> <string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"नेटवर्क बदल्न इथरनेट डिस्कनेक्ट गर्नुहोस्"</string> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index ea9822980b07..ad1403e664df 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontgrendel het scherm om netwerken te bekijken"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netwerken zoeken…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kan geen verbinding maken met het netwerk"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi maakt momenteel niet automatisch verbinding"</string> <string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Verbreek de ethernetverbinding om van netwerk te wisselen"</string> </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 1ea599f12c20..e5c2a2b61825 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ନେଟୱାର୍କଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ଅନଲକ୍ କରନ୍ତୁ"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ନେଟୱାର୍କଗୁଡ଼ିକ ସନ୍ଧାନ କରାଯାଉଛି…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ନେଟୱାର୍କକୁ ସଂଯୋଗ କରିବାରେ ବିଫଳ ହୋଇଛି"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ବର୍ତ୍ତମାନ ପାଇଁ ୱାଇ-ଫାଇ ସ୍ୱତଃ-ସଂଯୋଗ ହେବ ନାହିଁ"</string> <string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ନେଟୱାର୍କ ସ୍ୱିଚ୍ କରିବାକୁ, ଇଥରନେଟ୍ ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 06364eaabe1f..48750cf95731 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ਨੈੱਟਵਰਕ ਖੋਜੇ ਜਾ ਰਹੇ ਹਨ…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ਫ਼ਿਲਹਾਲ ਵਾਈ-ਫਾਈ ਸਵੈ-ਕਨੈਕਟ ਨਹੀਂ ਹੋਵੇਗਾ"</string> <string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਬਦਲਣ ਲਈ, ਈਥਰਨੈੱਟ ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index ae4b5d60727b..3635876b04da 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odblokuj, by wyświetlić sieci"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Szukam sieci…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nie udało się połączyć z siecią"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nie będzie na razie włączać się automatycznie"</string> <string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Aby przełączać sieci, odłącz Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index cbd43f878e08..8f499f7fbb04 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index a8f62585dc38..b0c65d866b78 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"A procurar redes…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Não foi possível estabelecer ligação à rede"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Por agora, o Wi-Fi não irá estabelecer lig. automaticamente"</string> <string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desligue a Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index cbd43f878e08..8f499f7fbb04 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"A conexão automática ao Wi-Fi ficará indisponível"</string> <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para mudar de rede, desconecte o cabo Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 751ea3ac4270..c143d5349ad4 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1181,6 +1181,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Deblocați pentru a vedea rețelele"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Se caută rețele…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nu s-a realizat conexiunea la rețea"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Deocamdată, Wi-Fi nu se poate conecta automat"</string> <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 4452a0206c7e..752110ea59ec 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблокируйте, чтобы посмотреть сети Wi-Fi."</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Поиск сетей…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не удалось подключиться к сети"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Подключение по Wi-Fi не установится автоматически."</string> <string name="see_all_networks" msgid="3773666844913168122">"Показать все"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Чтобы переключиться между сетями, отключите кабель Ethernet."</string> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index e87aefb1db58..b3a7a8e3cf7f 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ජාල බැලීමට අගුලු හරින්න"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ජාල සඳහා සොයමින්…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"ජාලය වෙත සම්බන්ධ වීම අසාර්ථක විය"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi දැනට ස්වයං-සබැඳි නොවනු ඇත"</string> <string name="see_all_networks" msgid="3773666844913168122">"සියල්ල බලන්න"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ජාල මාරු කිරීමට, ඊතර්නෙට් විසන්ධි කරන්න"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index a1719f060ece..f45226b41ffc 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odomknutím si zobrazte siete"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhľadávajú sa siete…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nepodarilo sa pripojiť k sieti"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi‑Fi sa teraz automaticky nepripojí"</string> <string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ak chcete prepnúť siete, odpojte ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 7d86eb1f94df..ed753906d8f1 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odklenite za ogled omrežij"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iskanje omrežij …"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Vzpostavljanje povezave z omrežjem ni uspelo."</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Vmesnik Wi-Fi trenutno ne bo samodejno vzpostavil povezave."</string> <string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Če želite preklopiti omrežje, prekinite ethernetno povezavo."</string> </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index c5eb836f3d95..dc7e82564df0 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Shkyçe për të parë rrjetet"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Po kërkon për rrjete…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Lidhja me rrjetin dështoi"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi nuk do të lidhet automatikisht për momentin"</string> <string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Për të ndërruar rrjetet, shkëput Ethernet-in"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index b75535a132bf..b486589b3bd5 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1181,6 +1181,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Откључајте да бисте видели мреже"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Траже се мреже…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Повезивање са мрежом није успело"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi тренутно не може да се аутоматски повеже"</string> <string name="see_all_networks" msgid="3773666844913168122">"Погледајте све"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Да бисте променили мрежу, прекините етернет везу"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index b0ef22502cd2..5db089bccc58 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås upp för att visa nätverk"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Söker efter nätverk …"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Det gick inte att ansluta till nätverket"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Du ansluts inte till wifi automatiskt för närvarande"</string> <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Koppla bort Ethernet för att växla nätverk"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index fa1517a23802..60104f623848 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -82,7 +82,7 @@ <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string> <string name="screenshot_saved_title" msgid="8893267638659083153">"Imehifadhi picha ya skrini"</string> - <string name="screenshot_saved_text" msgid="7778833104901642442">"Gusa ili utazame picha ya skrini uliyohifadhi"</string> + <string name="screenshot_saved_text" msgid="7778833104901642442">"Gusa ili uone picha ya skrini uliyohifadhi"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"Imeshindwa kuhifadhi picha ya skrini"</string> <string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"Ni sharti ufungue kifaa kabla ya kuhifadhi picha ya skrini"</string> <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Jaribu kupiga picha ya skrini tena"</string> @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Fungua ili uangalie mitandao"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Inatafuta mitandao…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Imeshindwa kuunganisha kwenye mtandao"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi haitaunganishwa kiotomatiki kwa sasa"</string> <string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ili kubadili mitandao, tenganisha ethaneti"</string> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index d921d4958090..85f8f0957a08 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -104,6 +104,6 @@ <!-- When split shade is used, this panel should be aligned to the top --> <dimen name="qs_detail_margin_top">0dp</dimen> - <!-- Internet panel related dimensions --> - <dimen name="internet_dialog_list_max_width">624dp</dimen> + <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) --> + <dimen name="large_dialog_width">624dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 5e6e4c60dc89..8cc4c8dd5336 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"நெட்வொர்க்குகளைப் பார்க்க அன்லாக் செய்யுங்கள்"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"நெட்வொர்க்குகளைத் தேடுகிறது…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"தற்போதைக்கு வைஃபை தானாக இணைக்கப்படாது"</string> <string name="see_all_networks" msgid="3773666844913168122">"அனைத்தையும் காட்டு"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"நெட்வொர்க்குகளை மாற்ற ஈதர்நெட் இணைப்பைத் துண்டிக்கவும்"</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index f4d93ac3fcee..95b8a63fa581 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -101,7 +101,7 @@ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"స్క్రీన్ రికార్డింగ్ అవుతోంది"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్గోయింగ్ నోటిఫికేషన్"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"రికార్డింగ్ను ప్రారంభించాలా?"</string> - <string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నైనా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, ఆడియో ఉంటాయి."</string> + <string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నయినా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, ఆడియో కూడా ఉంటాయి."</string> <string name="screenrecord_audio_label" msgid="6183558856175159629">"ఆడియోను రికార్డ్ చేయి"</string> <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"పరికరం ఆడియో"</string> <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే సంగీతం, కాల్స్, రింగ్టోన్ల వంటి ధ్వనులు"</string> @@ -507,7 +507,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"బ్యాటరీ సేవర్ ఆన్లో ఉంది"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"బ్యాటరీ సేవర్ను ఆఫ్ చేయండి"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్వర్డ్లు, చెల్లింపు వివరాలు, ఫోటోలు, మెసేజ్లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్ను అందిస్తున్న సర్వీస్ యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్వర్డ్లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>తో రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string> @@ -1145,7 +1145,7 @@ <string name="status_before_loading" msgid="1500477307859631381">"కంటెంట్ త్వరలో కనిపిస్తుంది"</string> <string name="missed_call" msgid="4228016077700161689">"మిస్డ్ కాల్"</string> <string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string> - <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్లు, మిస్డ్ కాల్స్, అలాగే స్టేటస్ అప్డేట్లను చూడండి"</string> + <string name="people_tile_description" msgid="8154966188085545556">"ఇటీవలి మెసేజ్లు, మిస్స్డ్ కాల్స్, అలాగే స్టేటస్ అప్డేట్లను చూడండి"</string> <string name="people_tile_title" msgid="6589377493334871272">"సంభాషణ"</string> <string name="paused_by_dnd" msgid="7856941866433556428">"అంతరాయం కలిగించవద్దు ద్వారా పాజ్ చేయబడింది"</string> <string name="new_notification_text_content_description" msgid="2915029960094389291">"<xliff:g id="NAME">%1$s</xliff:g> మెసేజ్ను పంపారు: <xliff:g id="NOTIFICATION">%2$s</xliff:g>"</string> @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"నెట్వర్క్లను చూడటానికి అన్లాక్ చేయండి"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"నెట్వర్క్ల కోసం సెర్చ్ చేస్తోంది…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"నెట్వర్క్కు కనెక్ట్ చేయడం విఫలమైంది"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ప్రస్తుతానికి Wi-Fi ఆటోమేటిక్గా కనెక్ట్ అవ్వదు"</string> <string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"నెట్వర్క్లను మార్చడానికి, ఈథర్నెట్ను డిస్కనెక్ట్ చేయండి"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index d0603a9ea149..91a24403f4d0 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ปลดล็อกเพื่อดูเครือข่าย"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"กำลังค้นหาเครือข่าย…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"เชื่อมต่อเครือข่ายไม่สำเร็จ"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi จะไม่เชื่อมต่ออัตโนมัติในตอนนี้"</string> <string name="see_all_networks" msgid="3773666844913168122">"ดูทั้งหมด"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ตัดการเชื่อมต่ออีเทอร์เน็ตเพื่อสลับเครือข่าย"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index bb1cbe8d8ee9..dcde0fc67584 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"I-unlock para tingnan ang mga network"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Naghahanap ng mga network…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Hind nakakonekta sa network"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Hindi awtomatikong kokonekta ang Wi-Fi sa ngayon"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Para lumipat ng network, idiskonekta ang ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 15b702c384ee..367d0bf3e372 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ağları görmek için kilidi açın"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ağlar aranıyor…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ağa bağlanılamadı"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Şu anda kablosuz ağa otomatik olarak bağlanılamıyor"</string> <string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ağ değiştirmek için ethernet bağlantısını kesin"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index dc30e0beaafb..e692a36985b1 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1187,6 +1187,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Розблокувати, щоб переглянути мережі"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Пошук мереж…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Не вдалося підключитися до мережі"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Пристрій не підключатиметься до Wi-Fi автоматично"</string> <string name="see_all_networks" msgid="3773666844913168122">"Показати все"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Щоб вибрати іншу мережу, від’єднайте кабель Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 667a9577ef3e..44b91ad7419e 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"نیٹ ورکس کو دیکھنے کے لیے غیر مقفل کریں"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"نیٹ ورکس تلاش کیے جا رہے ہیں…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"نیٹ ورک سے منسلک ہونے میں ناکام ہو گیا"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ابھی Wi-Fi خود کار طور پر منسلک نہیں ہوگا"</string> <string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"نیٹ ورکس پر سوئچ کرنے کیلئے، ایتھرنیٹ غیر منسلک کریں"</string> </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index b02ef403bfeb..f0afb6cb704b 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Tarmoqlarni koʻrish uchun qulfdan chiqaring"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Tarmoqlar qidirilmoqda…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Tarmoqqa ulanmadi"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi hozir avtomatik ulanmaydi"</string> <string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Boshqa tarmoqqa almashish uchun Ethernet tarmogʻini uzing"</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index d046494e2134..b0f1dcf31133 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Mở khóa để xem mạng"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Đang tìm mạng…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Không kết nối được với mạng"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Tạm thời, Wi-Fi sẽ không tự động kết nối"</string> <string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Để chuyển mạng, hãy rút cáp Ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index c7747fac198e..7caae5df46e5 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"解锁即可查看网络"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜索网络…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"未能连接到网络"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WLAN 暂时无法自动连接"</string> <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切换网络,请断开以太网连接"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index e7ffeeae336e..4a8567d7d29b 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖即可查看網絡"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網絡…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連接網絡"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前系統不會自動連線至 Wi-Fi"</string> <string name="see_all_networks" msgid="3773666844913168122">"顯示全部"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網絡,請中斷以太網連線"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index b49cd2b1e7cc..b444d4223b7f 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖螢幕即可查看網路"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"正在搜尋網路…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"無法連上網路"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"目前不會自動連上 Wi-Fi"</string> <string name="see_all_networks" msgid="3773666844913168122">"查看全部"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"如要切換網路,請中斷乙太網路連線"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index d4fb489807cb..79884764562a 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1175,6 +1175,7 @@ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Vula ukuze ubuke amanethiwekhi"</string> <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iseshela amanethiwekhi…"</string> <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yehlulekile ukuxhuma kunethiwekhi"</string> + <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"I-Wi-Fi ngeke ixhume ngokuzenzakalelayo okwamanje"</string> <string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string> <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ukuze ushintshe amanethiwekhi, nqamula i-ethernet"</string> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 08778bf14c66..03c6fddb145c 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -70,7 +70,7 @@ <color name="keyguard_shadow_color">#B2000000</color> <!-- Color for the images in keyguard number pad buttons --> - <color name="keyguard_keypad_image_color">@android:color/background_light</color> + <color name="keyguard_keypad_image_color">?android:attr/textColorPrimaryInverse</color> <!-- Color for rounded background for activated user in keyguard user switcher --> <color name="kg_user_switcher_activated_background_color">#26000000</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 5e495f0cd1a6..c3ac19a46ee6 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -191,6 +191,15 @@ low powered state yet. --> <bool name="doze_single_tap_uses_prox">true</bool> + <!-- Doze: whether the single tap sensor uses the proximity sensor in the given posture. + See doze_single_tap_uses_prox for usage. --> + <integer-array name="doze_single_tap_uses_prox_posture_mapping"> + <item>1</item> <!-- UNKNOWN --> + <item>1</item> <!-- CLOSED --> + <item>1</item> <!-- HALF_OPENED --> + <item>1</item> <!-- OPENED --> + </integer-array> + <!-- Doze: whether the long press sensor uses the proximity sensor. If both this parameter and doze_selectively_register_prox are true, registration for the sensor will be delayed when the device first enters dozing but the device has not entered its @@ -211,6 +220,16 @@ always-on display) --> <string name="doze_brightness_sensor_type" translatable="false"></string> + <!-- Name of a sensor per posture state that provides a low-power estimate of the desired + display brightness, suitable to listen to while the device is asleep (e.g. during + always-on display) --> + <string-array name="doze_brightness_sensor_name_posture_mapping" translatable="false"> + <item></item> <!-- UNKNOWN --> + <item></item> <!-- CLOSED --> + <item></item> <!-- HALF_OPENED --> + <item></item> <!-- OPENED --> + </string-array> + <!-- Override value to use for proximity sensor. --> <string name="proximity_sensor_type" translatable="false"></string> @@ -706,4 +725,8 @@ <item>@drawable/rounded_corner_bottom</item> <item>@drawable/rounded_corner_bottom_secondary</item> </array> + + <!-- Flag to enable privacy dot views, it shall be true for normal case --> + <bool name="config_enablePrivacyDot">true</bool> + </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 70149267e3dd..9f257466ff28 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1559,6 +1559,13 @@ <!-- Location on the screen of the center of the fingerprint sensor. For devices with under display fingerprint sensors, this directly corresponds to the fingerprint sensor's location. For devices with sensors on the back of the device, this corresponds to the location on the + screen directly in front of the sensor. + By default, this is set to @null to use the horizontal center of the screen. --> + <dimen name="physical_fingerprint_sensor_center_screen_location_x">@null</dimen> + + <!-- Location on the screen of the center of the fingerprint sensor. For devices with under + display fingerprint sensors, this directly corresponds to the fingerprint sensor's location. + For devices with sensors on the back of the device, this corresponds to the location on the screen directly in front of the sensor. --> <dimen name="physical_fingerprint_sensor_center_screen_location_y">610px</dimen> @@ -1596,7 +1603,9 @@ <!-- Internet panel related dimensions --> <dimen name="internet_dialog_list_margin">12dp</dimen> <dimen name="internet_dialog_list_max_height">646dp</dimen> - <dimen name="internet_dialog_list_max_width">@dimen/match_parent</dimen> + + <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) --> + <dimen name="large_dialog_width">@dimen/match_parent</dimen> <!-- Signal icon in internet dialog --> <dimen name="signal_strength_icon_size">24dp</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 93d60cce2915..6594216e4290 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -331,9 +331,6 @@ <style name="Animation.ShutdownUi" parent="@android:style/Animation.Toast"> </style> - <style name="Animation.MediaOutputDialog" parent="@android:style/Animation.InputMethod"> - </style> - <!-- Standard animations for hiding and showing the status bar. --> <style name="Animation.StatusBar"> </style> @@ -436,10 +433,6 @@ <item name="android:windowCloseOnTouchOutside">true</item> </style> - <style name="Theme.SystemUI.Dialog.MediaOutput"> - <item name="android:windowBackground">@drawable/media_output_dialog_background</item> - </style> - <style name="QSBorderlessButton"> <item name="android:padding">12dp</item> <item name="android:background">@drawable/qs_btn_borderless_rect</item> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 8f14cd858f1e..f81f0b9ca2c3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -11,6 +11,7 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver.OnPreDrawListener; import android.widget.FrameLayout; import android.widget.RelativeLayout; @@ -93,6 +94,7 @@ public class KeyguardClockSwitch extends RelativeLayout { private int[] mColorPalette; private int mClockSwitchYAmount; + @VisibleForTesting boolean mChildrenAreLaidOut = false; public KeyguardClockSwitch(Context context, AttributeSet attrs) { super(context, attrs); @@ -284,11 +286,31 @@ public class KeyguardClockSwitch extends RelativeLayout { if (mDisplayedClockSize != null && clockSize == mDisplayedClockSize) { return false; } - animateClockChange(clockSize == LARGE); - mDisplayedClockSize = clockSize; + + // let's make sure clock is changed only after all views were laid out so we can + // translate them properly + if (mChildrenAreLaidOut) { + animateClockChange(clockSize == LARGE); + mDisplayedClockSize = clockSize; + } else { + getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { + @Override + public boolean onPreDraw() { + switchToClock(clockSize); + getViewTreeObserver().removeOnPreDrawListener(this); + return true; + } + }); + } return true; } + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + mChildrenAreLaidOut = true; + } + public Paint getPaint() { return mClockView.getPaint(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 92d1bc4173d8..5969e9290c9c 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -90,6 +90,7 @@ import androidx.annotation.Nullable; import androidx.lifecycle.Observer; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; @@ -321,6 +322,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private boolean mIsDreaming; private final DevicePolicyManager mDevicePolicyManager; private final BroadcastDispatcher mBroadcastDispatcher; + private final InteractionJankMonitor mInteractionJankMonitor; private boolean mLogoutEnabled; // cached value to avoid IPCs private boolean mIsUdfpsEnrolled; @@ -1770,6 +1772,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab AuthController authController, TelephonyListenerManager telephonyListenerManager, FeatureFlags featureFlags, + InteractionJankMonitor interactionJankMonitor, @Nullable Vibrator vibrator) { mContext = context; mSubscriptionManager = SubscriptionManager.from(context); @@ -1778,6 +1781,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged); mBackgroundExecutor = backgroundExecutor; mBroadcastDispatcher = broadcastDispatcher; + mInteractionJankMonitor = interactionJankMonitor; mRingerModeTracker = ringerModeTracker; mStatusBarStateController = statusBarStateController; mStatusBarStateController.addCallback(mStatusBarStateControllerListener); @@ -2637,7 +2641,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab /** * Handle {@link #MSG_USER_SWITCH_COMPLETE} */ - private void handleUserSwitchComplete(int userId) { + @VisibleForTesting + void handleUserSwitchComplete(int userId) { Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -2645,6 +2650,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab cb.onUserSwitchComplete(userId); } } + mInteractionJankMonitor.end(InteractionJankMonitor.CUJ_USER_SWITCH); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java index c659bf786a45..f4ce643a085c 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java @@ -18,6 +18,7 @@ package com.android.keyguard; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; +import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.graphics.drawable.VectorDrawable; @@ -26,8 +27,6 @@ import android.view.MotionEvent; import androidx.annotation.Nullable; -import com.android.systemui.R; - /** * Similar to the {@link NumPadKey}, but displays an image. */ @@ -92,7 +91,10 @@ public class NumPadButton extends AlphaOptimizedImageButton { public void reloadColors() { if (mAnimator != null) mAnimator.reloadColors(getContext()); - int imageColor = getContext().getColor(R.color.keyguard_keypad_image_color); + int[] customAttrs = {android.R.attr.textColorPrimaryInverse}; + TypedArray a = getContext().obtainStyledAttributes(customAttrs); + int imageColor = a.getColor(0, 0); + a.recycle(); ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor)); } } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 19d029bfd161..23a3f8d58f71 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -160,6 +160,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { private Handler mHandler; private boolean mPendingRotationChange; private boolean mIsRoundedCornerMultipleRadius; + private boolean mIsPrivacyDotEnabled; private int mStatusBarHeightPortrait; private int mStatusBarHeightLandscape; private Drawable mRoundedCornerDrawable; @@ -253,6 +254,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { mRotation = mContext.getDisplay().getRotation(); mDisplayUniqueId = mContext.getDisplay().getUniqueId(); mIsRoundedCornerMultipleRadius = isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId); + mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot); mWindowManager = mContext.getSystemService(WindowManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class); updateRoundedCornerDrawable(); @@ -312,24 +314,24 @@ public class ScreenDecorations extends SystemUI implements Tunable { } private void setupDecorations() { - if (hasRoundedCorners() || shouldDrawCutout()) { + if (hasRoundedCorners() || shouldDrawCutout() || mIsPrivacyDotEnabled) { updateStatusBarHeight(); final DisplayCutout cutout = getCutout(); - final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll(); - int rotatedPos; for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { - rotatedPos = getBoundPositionFromRotation(i, mRotation); - if ((bounds != null && !bounds[rotatedPos].isEmpty()) - || shouldShowRoundedCorner(i)) { - createOverlay(i); + if (shouldShowCutout(i, cutout) || shouldShowRoundedCorner(i, cutout) + || shouldShowPrivacyDot(i, cutout)) { + createOverlay(i, cutout); } else { removeOverlay(i); } } - // Overlays have been created, send the dots to the controller - //TODO: need a better way to do this - mDotViewController.initialize( - mTopLeftDot, mTopRightDot, mBottomLeftDot, mBottomRightDot); + + if (mIsPrivacyDotEnabled) { + // Overlays have been created, send the dots to the controller + //TODO: need a better way to do this + mDotViewController.initialize( + mTopLeftDot, mTopRightDot, mBottomLeftDot, mBottomRightDot); + } } else { removeAllOverlays(); } @@ -416,7 +418,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { mOverlays[pos] = null; } - private void createOverlay(@BoundsPosition int pos) { + private void createOverlay(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { if (mOverlays == null) { mOverlays = new View[BOUNDS_POSITION_LENGTH]; } @@ -437,7 +439,7 @@ public class ScreenDecorations extends SystemUI implements Tunable { mOverlays[pos].setAlpha(0); mOverlays[pos].setForceDarkAllowed(false); - updateView(pos); + updateView(pos, cutout); mWindowManager.addView(mOverlays[pos], getWindowLayoutParams(pos)); @@ -461,34 +463,19 @@ public class ScreenDecorations extends SystemUI implements Tunable { * Allow overrides for top/bottom positions */ private View overlayForPosition(@BoundsPosition int pos) { - switch (pos) { - case BOUNDS_POSITION_TOP: - case BOUNDS_POSITION_LEFT: - View top = LayoutInflater.from(mContext) - .inflate(R.layout.rounded_corners_top, null); - mTopLeftDot = top.findViewById(R.id.privacy_dot_left_container); - mTopRightDot = top.findViewById(R.id.privacy_dot_right_container); - return top; - case BOUNDS_POSITION_BOTTOM: - case BOUNDS_POSITION_RIGHT: - View bottom = LayoutInflater.from(mContext) - .inflate(R.layout.rounded_corners_bottom, null); - mBottomLeftDot = bottom.findViewById(R.id.privacy_dot_left_container); - mBottomRightDot = bottom.findViewById(R.id.privacy_dot_right_container); - return bottom; - default: - throw new IllegalArgumentException("Unknown bounds position"); - } + final int layoutId = (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP) + ? R.layout.rounded_corners_top : R.layout.rounded_corners_bottom; + return LayoutInflater.from(mContext).inflate(layoutId, null); } - private void updateView(@BoundsPosition int pos) { + private void updateView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { if (mOverlays == null || mOverlays[pos] == null) { return; } // update rounded corner view rotation - updateRoundedCornerView(pos, R.id.left); - updateRoundedCornerView(pos, R.id.right); + updateRoundedCornerView(pos, R.id.left, cutout); + updateRoundedCornerView(pos, R.id.right, cutout); updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom); updateRoundedCornerImageView(); @@ -496,6 +483,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (mCutoutViews != null && mCutoutViews[pos] != null) { mCutoutViews[pos].setRotation(mRotation); } + + updatePrivacyDotView(pos, cutout); } @VisibleForTesting @@ -671,11 +660,12 @@ public class ScreenDecorations extends SystemUI implements Tunable { if (mOverlays != null) { updateLayoutParams(); + final DisplayCutout cutout = getCutout(); for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) { if (mOverlays[i] == null) { continue; } - updateView(i); + updateView(i, cutout); } } } @@ -807,13 +797,14 @@ public class ScreenDecorations extends SystemUI implements Tunable { return drawable; } - private void updateRoundedCornerView(@BoundsPosition int pos, int id) { + private void updateRoundedCornerView(@BoundsPosition int pos, int id, + @Nullable DisplayCutout cutout) { final View rounded = mOverlays[pos].findViewById(id); if (rounded == null) { return; } rounded.setVisibility(View.GONE); - if (shouldShowRoundedCorner(pos)) { + if (shouldShowRoundedCorner(pos, cutout)) { final int gravity = getRoundedCornerGravity(pos, id == R.id.left); ((FrameLayout.LayoutParams) rounded.getLayoutParams()).gravity = gravity; setRoundedCornerOrientation(rounded, gravity); @@ -821,6 +812,26 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } + private void updatePrivacyDotView(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { + final ViewGroup viewGroup = (ViewGroup) mOverlays[pos]; + + final View left = viewGroup.findViewById(R.id.privacy_dot_left_container); + final View right = viewGroup.findViewById(R.id.privacy_dot_right_container); + if (shouldShowPrivacyDot(pos, cutout)) { + // TODO (b/201481944) Privacy Dots pos and var are wrong with long side cutout enable + if (pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_TOP) { + mTopLeftDot = left; + mTopRightDot = right; + } else { + mBottomLeftDot = left; + mBottomRightDot = right; + } + } else { + viewGroup.removeView(left); + viewGroup.removeView(right); + } + } + private int getRoundedCornerGravity(@BoundsPosition int pos, boolean isStart) { final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); switch (rotatedPos) { @@ -872,12 +883,8 @@ public class ScreenDecorations extends SystemUI implements Tunable { || mIsRoundedCornerMultipleRadius; } - private boolean shouldShowRoundedCorner(@BoundsPosition int pos) { - if (!hasRoundedCorners()) { - return false; - } - - DisplayCutout cutout = getCutout(); + private boolean isDefaultShownOverlayPos(@BoundsPosition int pos, + @Nullable DisplayCutout cutout) { // for cutout is null or cutout with only waterfall. final boolean emptyBoundsOrWaterfall = cutout == null || cutout.isBoundsEmpty(); // Shows rounded corner on left and right overlays only when there is no top or bottom @@ -892,6 +899,21 @@ public class ScreenDecorations extends SystemUI implements Tunable { } } + private boolean shouldShowRoundedCorner(@BoundsPosition int pos, + @Nullable DisplayCutout cutout) { + return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout); + } + + private boolean shouldShowPrivacyDot(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { + return mIsPrivacyDotEnabled && isDefaultShownOverlayPos(pos, cutout); + } + + private boolean shouldShowCutout(@BoundsPosition int pos, @Nullable DisplayCutout cutout) { + final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll(); + final int rotatedPos = getBoundPositionFromRotation(pos, mRotation); + return (bounds != null && !bounds[rotatedPos].isEmpty()); + } + private boolean shouldDrawCutout() { return shouldDrawCutout(mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java index c32c1a2f3e53..48f6431aec69 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java @@ -16,7 +16,6 @@ package com.android.systemui.biometrics; -import android.annotation.NonNull; import android.content.Context; import android.graphics.drawable.Animatable2; import android.graphics.drawable.AnimatedVectorDrawable; @@ -30,6 +29,7 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; @@ -163,6 +163,18 @@ public class AuthBiometricFaceView extends AuthBiometricView { } @Nullable @VisibleForTesting IconController mFaceIconController; + @NonNull private final OnAttachStateChangeListener mOnAttachStateChangeListener = + new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + + } + + @Override + public void onViewDetachedFromWindow(View v) { + mFaceIconController.deactivate(); + } + }; public AuthBiometricFaceView(Context context) { this(context, null); @@ -181,6 +193,8 @@ public class AuthBiometricFaceView extends AuthBiometricView { protected void onFinishInflate() { super.onFinishInflate(); mFaceIconController = new IconController(mContext, mIconView, mIndicatorView); + + addOnAttachStateChangeListener(mOnAttachStateChangeListener); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 71445a7c2cfe..f4b446b50c9e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.PointF; import android.hardware.biometrics.BiometricAuthenticator.Modality; import android.hardware.biometrics.BiometricConstants; @@ -97,7 +98,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<SidefpsController> mSidefpsControllerFactory; @Nullable private final PointF mFaceAuthSensorLocation; - @Nullable private final PointF mFingerprintLocation; + @Nullable private PointF mFingerprintLocation; private final Set<Callback> mCallbacks = new HashSet<>(); // TODO: These should just be saved from onSaveState @@ -481,9 +482,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, (float) faceAuthLocation[1]); } - mFingerprintLocation = new PointF(DisplayUtils.getWidth(mContext) / 2, - mContext.getResources().getDimensionPixelSize( - com.android.systemui.R.dimen.physical_fingerprint_sensor_center_screen_location_y)); + updateFingerprintLocation(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); @@ -491,6 +490,21 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, context.registerReceiver(mBroadcastReceiver, filter); } + private void updateFingerprintLocation() { + int xLocation = DisplayUtils.getWidth(mContext) / 2; + try { + xLocation = mContext.getResources().getDimensionPixelSize( + com.android.systemui.R.dimen + .physical_fingerprint_sensor_center_screen_location_x); + } catch (Resources.NotFoundException e) { + } + int yLocation = mContext.getResources().getDimensionPixelSize( + com.android.systemui.R.dimen.physical_fingerprint_sensor_center_screen_location_y); + mFingerprintLocation = new PointF( + xLocation, + yLocation); + } + @SuppressWarnings("deprecation") @Override public void start() { @@ -767,6 +781,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + updateFingerprintLocation(); // Save the state of the current dialog (buttons showing, etc) if (mCurrentDialog != null) { @@ -796,6 +811,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } private void onOrientationChanged() { + updateFingerprintLocation(); if (mCurrentDialog != null) { mCurrentDialog.onOrientationChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index ba64195ea78b..eb6b193d85a3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.res.Configuration import android.graphics.PointF import android.hardware.biometrics.BiometricSourceType +import android.util.DisplayMetrics import android.util.Log import androidx.annotation.VisibleForTesting import com.android.keyguard.KeyguardUpdateMonitor @@ -45,6 +46,7 @@ import java.io.PrintWriter import javax.inject.Inject import javax.inject.Provider import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.util.leak.RotationUtils private const val WAKE_AND_UNLOCK_FADE_DURATION = 180L @@ -182,7 +184,7 @@ class AuthRippleController @Inject constructor( } fun updateSensorLocation() { - fingerprintSensorLocation = authController.fingerprintSensorLocation + updateFingerprintLocation() faceSensorLocation = authController.faceAuthSensorLocation fingerprintSensorLocation?.let { circleReveal = CircleReveal( @@ -197,6 +199,35 @@ class AuthRippleController @Inject constructor( } } + private fun updateFingerprintLocation() { + val displayMetrics = DisplayMetrics() + sysuiContext.display?.getRealMetrics(displayMetrics) + val width = displayMetrics.widthPixels + val height = displayMetrics.heightPixels + + authController.fingerprintSensorLocation?.let { + fingerprintSensorLocation = when (RotationUtils.getRotation(sysuiContext)) { + RotationUtils.ROTATION_LANDSCAPE -> { + val normalizedYPos: Float = it.y / width + val normalizedXPos: Float = it.x / height + PointF(width * normalizedYPos, height * (1 - normalizedXPos)) + } + RotationUtils.ROTATION_UPSIDE_DOWN -> { + PointF(width - it.x, height - it.y) + } + RotationUtils.ROTATION_SEASCAPE -> { + val normalizedYPos: Float = it.y / width + val normalizedXPos: Float = it.x / height + PointF(width * (1 - normalizedYPos), height * normalizedXPos) + } + else -> { + // ROTATION_NONE + PointF(it.x, it.y) + } + } + } + } + private fun updateRippleColor() { mView.setColor( Utils.getColorAttr(sysuiContext, android.R.attr.colorAccent).defaultColor) @@ -314,10 +345,12 @@ class AuthRippleController @Inject constructor( } } "fingerprint" -> { + updateSensorLocation() pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation") showRipple(BiometricSourceType.FINGERPRINT) } "face" -> { + updateSensorLocation() pw.println("face ripple sensorLocation=$faceSensorLocation") showRipple(BiometricSourceType.FACE) } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index 4d1608fb445d..d74df37401d0 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -74,6 +74,7 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.app.IBatteryStats; import com.android.internal.appwidget.IAppWidgetService; +import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.LatencyTracker; import com.android.systemui.dagger.qualifiers.DisplayId; @@ -220,6 +221,12 @@ public class FrameworkServicesModule { @Provides @Singleton + static InteractionJankMonitor provideInteractionJankMonitor() { + return InteractionJankMonitor.getInstance(); + } + + @Provides + @Singleton static InputMethodManager provideInputMethodManager(Context context) { return context.getSystemService(InputMethodManager.class); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 55e6154b829d..3cefce83393a 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -47,6 +47,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.biometrics.AuthController; import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.settings.SecureSettings; @@ -82,6 +83,9 @@ public class DozeSensors { private boolean mListeningTouchScreenSensors; private boolean mListeningProxSensors; + @DevicePostureController.DevicePostureInt + private int mDevicePosture; + // whether to only register sensors that use prox when the display state is dozing or off private boolean mSelectivelyRegisterProxSensors; @@ -106,7 +110,8 @@ public class DozeSensors { DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog, ProximitySensor proximitySensor, SecureSettings secureSettings, - AuthController authController) { + AuthController authController, + int devicePosture) { mContext = context; mSensorManager = sensorManager; mConfig = config; @@ -120,6 +125,7 @@ public class DozeSensors { mListeningProxSensors = !mSelectivelyRegisterProxSensors; mScreenOffUdfpsEnabled = config.screenOffUdfpsEnabled(KeyguardUpdateMonitor.getCurrentUser()); + mDevicePosture = devicePosture; boolean udfpsEnrolled = authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()); @@ -142,7 +148,7 @@ public class DozeSensors { false /* requires prox */, dozeLog), new TriggerSensor( - findSensorWithType(config.doubleTapSensorType()), + findSensor(config.doubleTapSensorType()), Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, true /* configured */, DozeLog.REASON_SENSOR_DOUBLE_TAP, @@ -150,7 +156,7 @@ public class DozeSensors { true /* touchscreen */, dozeLog), new TriggerSensor( - findSensorWithType(config.tapSensorType()), + findSensor(config.tapSensorType(mDevicePosture)), Settings.Secure.DOZE_TAP_SCREEN_GESTURE, true /* settingDef */, true /* configured */, @@ -158,10 +164,10 @@ public class DozeSensors { false /* reports touch coordinates */, true /* touchscreen */, false /* ignoresSetting */, - dozeParameters.singleTapUsesProx() /* requiresProx */, + dozeParameters.singleTapUsesProx(mDevicePosture) /* requiresProx */, dozeLog), new TriggerSensor( - findSensorWithType(config.longPressSensorType()), + findSensor(config.longPressSensorType()), Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, false /* settingDef */, true /* configured */, @@ -172,7 +178,7 @@ public class DozeSensors { dozeParameters.longPressUsesProx() /* requiresProx */, dozeLog), new TriggerSensor( - findSensorWithType(config.udfpsLongPressSensorType()), + findSensor(config.udfpsLongPressSensorType()), "doze_pulse_on_auth", true /* settingDef */, udfpsEnrolled && (alwaysOn || mScreenOffUdfpsEnabled), @@ -200,7 +206,7 @@ public class DozeSensors { mConfig.getWakeLockScreenDebounce(), dozeLog), new TriggerSensor( - findSensorWithType(config.quickPickupSensorType()), + findSensor(config.quickPickupSensorType()), Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, true /* setting default */, config.quickPickupSensorEnabled(KeyguardUpdateMonitor.getCurrentUser()) @@ -238,21 +244,29 @@ public class DozeSensors { mDebounceFrom = SystemClock.uptimeMillis(); } - private Sensor findSensorWithType(String type) { - return findSensorWithType(mSensorManager, type); + private Sensor findSensor(String type) { + return findSensor(mSensorManager, type, null); } /** - * Utility method to find a {@link Sensor} for the supplied string type. + * Utility method to find a {@link Sensor} for the supplied string type and string name. + * + * Return the first sensor in the list that matches the specified inputs. Ignores type or name + * if the input is null or empty. + * + * @param type sensorType + * @parm name sensorName, to differentiate between sensors with the same type */ - public static Sensor findSensorWithType(SensorManager sensorManager, String type) { - if (TextUtils.isEmpty(type)) { - return null; - } - List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL); - for (Sensor s : sensorList) { - if (type.equals(s.getStringType())) { - return s; + public static Sensor findSensor(SensorManager sensorManager, String type, String name) { + final boolean isNameSpecified = !TextUtils.isEmpty(name); + final boolean isTypeSpecified = !TextUtils.isEmpty(type); + if (isNameSpecified || isTypeSpecified) { + final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL); + for (Sensor sensor : sensors) { + if ((!isNameSpecified || name.equals(sensor.getName())) + && (!isTypeSpecified || type.equals(sensor.getStringType()))) { + return sensor; + } } } return null; @@ -370,6 +384,8 @@ public class DozeSensors { /** Dump current state */ public void dump(PrintWriter pw) { pw.println("mListening=" + mListening); + pw.println("mDevicePosture=" + + DevicePostureController.devicePostureToString(mDevicePosture)); pw.println("mListeningTouchScreenSensors=" + mListeningTouchScreenSensors); pw.println("mSelectivelyRegisterProxSensors=" + mSelectivelyRegisterProxSensors); pw.println("mListeningProxSensors=" + mListeningProxSensors); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 756adca724e9..1e7f0d9dc630 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -41,6 +41,7 @@ import com.android.systemui.dock.DockManager; import com.android.systemui.doze.DozeMachine.State; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.Assert; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -95,6 +96,9 @@ public class DozeTriggers implements DozeMachine.Part { private final DelayableExecutor mMainExecutor; private final KeyguardStateController mKeyguardStateController; private final UiEventLogger mUiEventLogger; + private final DevicePostureController mDevicePostureController; + + private @DevicePostureController.DevicePostureInt int mDevicePosture; private long mNotificationPulseTime; private boolean mPulsePending; @@ -182,7 +186,8 @@ public class DozeTriggers implements DozeMachine.Part { SecureSettings secureSettings, AuthController authController, @Main DelayableExecutor mainExecutor, UiEventLogger uiEventLogger, - KeyguardStateController keyguardStateController) { + KeyguardStateController keyguardStateController, + DevicePostureController devicePostureController) { mContext = context; mDozeHost = dozeHost; mConfig = config; @@ -190,9 +195,11 @@ public class DozeTriggers implements DozeMachine.Part { mSensorManager = sensorManager; mWakeLock = wakeLock; mAllowPulseTriggers = true; + mDevicePostureController = devicePostureController; + mDevicePosture = devicePostureController.getDevicePosture(); mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor, - secureSettings, authController); + secureSettings, authController, mDevicePosture); mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; mProxCheck = proxCheck; diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java index 9c6e02a7924e..571b666e4573 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java +++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java @@ -38,6 +38,7 @@ import com.android.systemui.doze.DozeTriggers; import com.android.systemui.doze.DozeUi; import com.android.systemui.doze.DozeWallpaperState; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.WakeLock; @@ -94,8 +95,15 @@ public abstract class DozeModule { @Provides @BrightnessSensor static Optional<Sensor> providesBrightnessSensor( - AsyncSensorManager sensorManager, Context context) { - return Optional.ofNullable(DozeSensors.findSensorWithType(sensorManager, - context.getString(R.string.doze_brightness_sensor_type))); + AsyncSensorManager sensorManager, + Context context, + DozeParameters dozeParameters, + DevicePostureController devicePostureController) { + return Optional.ofNullable( + DozeSensors.findSensor( + sensorManager, + context.getString(R.string.doze_brightness_sensor_type), + dozeParameters.brightnessName(devicePostureController.getDevicePosture()) + )); } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index e7445f920ffe..424f80177d9c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -364,9 +364,9 @@ public class MediaControlPanel { seamlessView.setVisibility(View.VISIBLE); setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */); setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */); - seamlessView.setOnClickListener(v -> { - mMediaOutputDialogFactory.create(data.getPackageName(), true); - }); + seamlessView.setOnClickListener( + v -> mMediaOutputDialogFactory.create(data.getPackageName(), true, + mPlayerViewHolder.getSeamlessButton())); ImageView iconView = mPlayerViewHolder.getSeamlessIcon(); TextView deviceName = mPlayerViewHolder.getSeamlessText(); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index eacdab6e537d..06a1eeac425d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -889,7 +889,7 @@ class MediaDataManager( dismissIntent = target .baseAction .extras - .getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY) as Intent + .getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY) as Intent? } packageName(target)?.let { return SmartspaceMediaData(target.smartspaceTargetId, isActive, true, it, diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt index 35603b6ef6cc..f32dad632721 100644 --- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt @@ -43,6 +43,7 @@ class PlayerViewHolder private constructor(itemView: View) { val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless) val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image) val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text) + val seamlessButton = itemView.requireViewById<View>(R.id.media_seamless_button) // Seek bar val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar) diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java index 391dff634dab..d1b6548132a6 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java @@ -45,11 +45,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { private static final String TAG = "MediaOutputAdapter"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private final MediaOutputDialog mMediaOutputDialog; private ViewGroup mConnectedItem; private boolean mIncludeDynamicGroup; - public MediaOutputAdapter(MediaOutputController controller) { + public MediaOutputAdapter(MediaOutputController controller, + MediaOutputDialog mediaOutputDialog) { super(controller); + mMediaOutputDialog = mediaOutputDialog; } @Override @@ -136,7 +139,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { mDivider.setTransitionAlpha(1); mAddIcon.setVisibility(View.VISIBLE); mAddIcon.setTransitionAlpha(1); - mAddIcon.setOnClickListener(v -> onEndItemClick()); + mAddIcon.setOnClickListener(this::onEndItemClick); } else { // Init non-active device layout mDivider.setVisibility(View.GONE); @@ -197,7 +200,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { mDivider.setTransitionAlpha(1); mAddIcon.setVisibility(View.VISIBLE); mAddIcon.setTransitionAlpha(1); - mAddIcon.setOnClickListener(v -> onEndItemClick()); + mAddIcon.setOnClickListener(this::onEndItemClick); } else { mDivider.setVisibility(View.GONE); mAddIcon.setVisibility(View.GONE); @@ -232,8 +235,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter { } } - private void onEndItemClick() { - mController.launchMediaOutputGroupDialog(); + private void onEndItemClick(View view) { + mController.launchMediaOutputGroupDialog(mMediaOutputDialog.getDialogView()); } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java index cdcdf9a1d4de..85d0802012ac 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java @@ -82,7 +82,7 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements }; public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) { - super(context, R.style.Theme_SystemUI_Dialog_MediaOutput); + super(context); mContext = context; mMediaOutputController = mediaOutputController; mLayoutManager = new LinearLayoutManager(mContext); @@ -97,15 +97,15 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements mDialogView = LayoutInflater.from(mContext).inflate(R.layout.media_output_dialog, null); final Window window = getWindow(); final WindowManager.LayoutParams lp = window.getAttributes(); - lp.gravity = Gravity.BOTTOM; + lp.gravity = Gravity.CENTER; // Config insets to make sure the layout is above the navigation bar lp.setFitInsetsTypes(statusBars() | navigationBars()); lp.setFitInsetsSides(WindowInsets.Side.all()); lp.setFitInsetsIgnoringVisibility(true); window.setAttributes(lp); window.setContentView(mDialogView); - window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - window.setWindowAnimations(R.style.Animation_MediaOutputDialog); + window.setLayout(mContext.getResources().getDimensionPixelSize(R.dimen.large_dialog_width), + ViewGroup.LayoutParams.WRAP_CONTENT); mHeaderTitle = mDialogView.requireViewById(R.id.header_title); mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle); @@ -229,4 +229,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements void onHeaderIconClick() { } + + View getDialogView() { + return mDialogView; + } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index b2def7a8596a..437a0c85a6e0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -32,6 +32,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.util.Log; +import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -48,6 +49,7 @@ import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaOutputConstants; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.R; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -73,6 +75,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { private final MediaSessionManager mMediaSessionManager; private final ShadeController mShadeController; private final ActivityStarter mActivityStarter; + private final DialogLaunchAnimator mDialogLaunchAnimator; private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>(); private final boolean mAboveStatusbar; private final NotificationEntryManager mNotificationEntryManager; @@ -82,6 +85,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { private MediaController mMediaController; @VisibleForTesting Callback mCallback; + Callback mPreviousCallback; @VisibleForTesting LocalMediaManager mLocalMediaManager; @@ -92,7 +96,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { public MediaOutputController(@NonNull Context context, String packageName, boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager lbm, ShadeController shadeController, ActivityStarter starter, - NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger) { + NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger, + DialogLaunchAnimator dialogLaunchAnimator) { mContext = context; mPackageName = packageName; mMediaSessionManager = mediaSessionManager; @@ -104,6 +109,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName); mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName); mUiEventLogger = uiEventLogger; + mDialogLaunchAnimator = dialogLaunchAnimator; } void start(@NonNull Callback cb) { @@ -129,7 +135,19 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { } return; } + + if (mPreviousCallback != null) { + Log.w(TAG, + "Callback started when mPreviousCallback is not null, which is unexpected"); + mPreviousCallback.dismissDialog(); + } + + // If we start the output group dialog when the output dialog is shown, we need to keep a + // reference to the output dialog to set it back as the callback once we dismiss the output + // group dialog. + mPreviousCallback = mCallback; mCallback = cb; + mLocalMediaManager.unregisterCallback(this); mLocalMediaManager.stopScan(); mLocalMediaManager.registerCallback(this); @@ -145,6 +163,15 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mLocalMediaManager.stopScan(); } mMediaDevices.clear(); + + // If there was a previous callback, i.e. we just dismissed the output group dialog and are + // now back on the output dialog, then we reset the callback to its previous value. + mCallback = null; + Callback previous = mPreviousCallback; + mPreviousCallback = null; + if (previous != null) { + start(previous); + } } @Override @@ -436,6 +463,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { } void launchBluetoothPairing() { + // Dismissing a dialog into its touch surface and starting an activity at the same time + // looks bad, so let's make sure the dialog just fades out quickly. + mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations(); + mCallback.dismissDialog(); final ActivityStarter.OnDismissAction postKeyguardAction = () -> { mContext.sendBroadcast(new Intent() @@ -447,14 +478,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction, null, true); } - void launchMediaOutputDialog() { - mCallback.dismissDialog(); - new MediaOutputDialog(mContext, mAboveStatusbar, this, mUiEventLogger); - } - - void launchMediaOutputGroupDialog() { - mCallback.dismissDialog(); - new MediaOutputGroupDialog(mContext, mAboveStatusbar, this); + void launchMediaOutputGroupDialog(View mediaOutputDialog) { + // We show the output group dialog from the output dialog. + MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar, this); + mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog); } boolean isActiveRemoteDevice(@NonNull MediaDevice device) { diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java index 53029bd04ef6..eca8ac90427b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java @@ -40,11 +40,10 @@ public class MediaOutputDialog extends MediaOutputBaseDialog { mediaOutputController, UiEventLogger uiEventLogger) { super(context, mediaOutputController); mUiEventLogger = uiEventLogger; - mAdapter = new MediaOutputAdapter(mMediaOutputController); + mAdapter = new MediaOutputAdapter(mMediaOutputController, this); if (!aboveStatusbar) { getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } - show(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt index 0f340a5cedaa..b91901de5af3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt @@ -18,8 +18,10 @@ package com.android.systemui.media.dialog import android.content.Context import android.media.session.MediaSessionManager +import android.view.View import com.android.internal.logging.UiEventLogger import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.phone.ShadeController @@ -35,19 +37,29 @@ class MediaOutputDialogFactory @Inject constructor( private val shadeController: ShadeController, private val starter: ActivityStarter, private val notificationEntryManager: NotificationEntryManager, - private val uiEventLogger: UiEventLogger + private val uiEventLogger: UiEventLogger, + private val dialogLaunchAnimator: DialogLaunchAnimator ) { companion object { var mediaOutputDialog: MediaOutputDialog? = null } /** Creates a [MediaOutputDialog] for the given package. */ - fun create(packageName: String, aboveStatusBar: Boolean) { + fun create(packageName: String, aboveStatusBar: Boolean, view: View? = null) { + // Dismiss the previous dialog, if any. mediaOutputDialog?.dismiss() - mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar, - mediaSessionManager, lbm, shadeController, starter, notificationEntryManager, - uiEventLogger).run { - MediaOutputDialog(context, aboveStatusBar, this, uiEventLogger) + + val controller = MediaOutputController(context, packageName, aboveStatusBar, + mediaSessionManager, lbm, shadeController, starter, notificationEntryManager, + uiEventLogger, dialogLaunchAnimator) + val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger) + mediaOutputDialog = dialog + + // Show the dialog. + if (view != null) { + dialogLaunchAnimator.showFromView(dialog, view) + } else { + dialog.show() } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java index 407930492fbe..1300400f3b66 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java @@ -38,7 +38,6 @@ public class MediaOutputGroupDialog extends MediaOutputBaseDialog { if (!aboveStatusbar) { getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); } - show(); } @Override @@ -83,6 +82,8 @@ public class MediaOutputGroupDialog extends MediaOutputBaseDialog { @Override void onHeaderIconClick() { - mMediaOutputController.launchMediaOutputDialog(); + // Given that we launched the media output group dialog from the media output dialog, + // dismissing this dialog will show the media output dialog again. + dismiss(); } } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index 71d2a73c73f6..fa6169210609 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -20,6 +20,7 @@ import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; @@ -34,9 +35,13 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S import android.app.StatusBarManager; import android.app.StatusBarManager.WindowVisibleState; +import android.content.ComponentCallbacks; import android.content.Context; +import android.content.res.Configuration; +import android.hardware.display.DisplayManager; import android.inputmethodservice.InputMethodService; import android.os.IBinder; +import android.view.Display; import android.view.InsetsVisibilities; import android.view.View; import android.view.WindowInsetsController.Behavior; @@ -55,7 +60,8 @@ import javax.inject.Singleton; @Singleton public class TaskbarDelegate implements CommandQueue.Callbacks, - OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener { + OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener, + ComponentCallbacks { private final EdgeBackGestureHandler mEdgeBackGestureHandler; @@ -71,11 +77,16 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, private int mDisabledFlags; private @WindowVisibleState int mTaskBarWindowState = WINDOW_STATE_SHOWING; private @Behavior int mBehavior; + private final Context mContext; + private final DisplayManager mDisplayManager; + private Context mWindowContext; @Inject public TaskbarDelegate(Context context) { mEdgeBackGestureHandler = Dependency.get(EdgeBackGestureHandler.Factory.class) .create(context); + mContext = context; + mDisplayManager = mContext.getSystemService(DisplayManager.class); } public void setOverviewProxyService(CommandQueue commandQueue, @@ -97,6 +108,10 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, mNavigationModeController.removeListener(this); mNavigationBarA11yHelper.removeA11yEventListener(mNavA11yEventListener); mEdgeBackGestureHandler.onNavBarDetached(); + if (mWindowContext != null) { + mWindowContext.unregisterComponentCallbacks(this); + mWindowContext = null; + } } public void init(int displayId) { @@ -107,6 +122,10 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, mNavigationModeController.addListener(this)); mNavigationBarA11yHelper.registerA11yEventListener(mNavA11yEventListener); mEdgeBackGestureHandler.onNavBarAttached(); + // Initialize component callback + Display display = mDisplayManager.getDisplay(displayId); + mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null); + mWindowContext.registerComponentCallbacks(this); // Set initial state for any listeners updateSysuiFlags(); } @@ -193,4 +212,12 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, private boolean allowSystemGestureIgnoringBarVisibility() { return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; } + + @Override + public void onConfigurationChanged(Configuration configuration) { + mEdgeBackGestureHandler.onConfigurationChanged(configuration); + } + + @Override + public void onLowMemory() {} } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index bf1a98fa39e6..c6da3420ffe9 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -101,8 +101,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker private static final int MAX_NUM_LOGGED_PREDICTIONS = 10; private static final int MAX_NUM_LOGGED_GESTURES = 10; - // Temporary log until b/176302696 is resolved - static final boolean DEBUG_MISSING_GESTURE = false; + // Temporary log until b/201642126 is resolved + static final boolean DEBUG_MISSING_GESTURE = true; static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture"; private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION = diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index dc54e1b52f2e..11430d93106a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -206,7 +206,7 @@ public class InternetDialog extends SystemUIDialog implements window.setContentView(mDialogView); //Only fix the width for large screen or tablet. window.setLayout(mContext.getResources().getDimensionPixelSize( - R.dimen.internet_dialog_list_max_width), ViewGroup.LayoutParams.WRAP_CONTENT); + R.dimen.large_dialog_width), ViewGroup.LayoutParams.WRAP_CONTENT); window.setWindowAnimations(R.style.Animation_InternetDialog); window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); window.addFlags(FLAG_LAYOUT_NO_LIMITS); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java index 31d51f1d1a60..a42b34cf23d0 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java @@ -326,18 +326,11 @@ public class LongScreenshotActivity extends Activity { | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); mTransitionView.setImageBitmap(mOutputBitmap); + mTransitionView.setVisibility(View.VISIBLE); mTransitionView.setTransitionName( ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME); // TODO: listen for transition completing instead of finishing onStop mTransitionStarted = true; - int[] locationOnScreen = new int[2]; - mTransitionView.getLocationOnScreen(locationOnScreen); - int[] locationInWindow = new int[2]; - mTransitionView.getLocationInWindow(locationInWindow); - int deltaX = locationOnScreen[0] - locationInWindow[0]; - int deltaY = locationOnScreen[1] - locationInWindow[1]; - mTransitionView.setX(mTransitionView.getX() - deltaX); - mTransitionView.setY(mTransitionView.getY() - deltaY); startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView, ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle()); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 8def475c192c..5b4db1449b34 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -940,12 +940,10 @@ public class ScreenshotController { */ private Supplier<ActionTransition> getActionTransitionSupplier() { return () -> { - View preview = mScreenshotView.getTransitionView(); - preview.setX(preview.getX() - mScreenshotView.getStaticLeftMargin()); Pair<ActivityOptions, ExitTransitionCoordinator> transition = ActivityOptions.startSharedElementAnimation( mWindow, new ScreenshotExitTransitionCallbacksSupplier(true).get(), - null, Pair.create(mScreenshotView.getTransitionView(), + null, Pair.create(mScreenshotView.getScreenshotPreview(), ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)); transition.second.startExit(); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index dfb39e300450..7222b0313fb4 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -137,13 +137,11 @@ public class ScreenshotView extends FrameLayout implements private int mNavMode; private boolean mOrientationPortrait; private boolean mDirectionLTR; - private int mStaticLeftMargin; private ScreenshotSelectorView mScreenshotSelectorView; private ImageView mScrollingScrim; private View mScreenshotStatic; private ImageView mScreenshotPreview; - private View mTransitionView; private View mScreenshotPreviewBorder; private ImageView mScrollablePreview; private ImageView mScreenshotFlash; @@ -341,7 +339,6 @@ public class ScreenshotView extends FrameLayout implements mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim)); mScreenshotStatic = requireNonNull(findViewById(R.id.global_screenshot_static)); mScreenshotPreview = requireNonNull(findViewById(R.id.global_screenshot_preview)); - mTransitionView = requireNonNull(findViewById(R.id.screenshot_transition_view)); mScreenshotPreviewBorder = requireNonNull( findViewById(R.id.global_screenshot_preview_border)); mScreenshotPreview.setClipToOutline(true); @@ -387,12 +384,8 @@ public class ScreenshotView extends FrameLayout implements requestFocus(); } - View getTransitionView() { - return mTransitionView; - } - - int getStaticLeftMargin() { - return mStaticLeftMargin; + View getScreenshotPreview() { + return mScreenshotPreview; } /** @@ -442,7 +435,6 @@ public class ScreenshotView extends FrameLayout implements Math.max(navBarInsets.bottom, waterfall.bottom)); } } - mStaticLeftMargin = p.leftMargin; mScreenshotStatic.setLayoutParams(p); mScreenshotStatic.requestLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt new file mode 100644 index 000000000000..c50365f1bf38 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt @@ -0,0 +1,74 @@ +package com.android.systemui.sensorprivacy + +import android.content.Context +import android.content.DialogInterface +import android.content.res.Resources +import android.text.Html +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.widget.ImageView +import com.android.internal.widget.DialogTitle +import com.android.systemui.R +import com.android.systemui.statusbar.phone.SystemUIDialog + +class SensorUseDialog( + context: Context, + val sensor: Int, + val clickListener: DialogInterface.OnClickListener +) : SystemUIDialog(context) { + + // TODO move to onCreate (b/200815309) + init { + window!!.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) + window!!.addSystemFlags( + WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) + + val layoutInflater = LayoutInflater.from(context) + val customTitleView = layoutInflater.inflate(R.layout.sensor_use_started_title, null) + customTitleView.requireViewById<DialogTitle>(R.id.sensor_use_started_title_message) + .setText(when (sensor) { + SensorUseStartedActivity.MICROPHONE -> + R.string.sensor_privacy_start_use_mic_dialog_title + SensorUseStartedActivity.CAMERA -> + R.string.sensor_privacy_start_use_camera_dialog_title + SensorUseStartedActivity.ALL_SENSORS -> + R.string.sensor_privacy_start_use_mic_camera_dialog_title + else -> Resources.ID_NULL + }) + customTitleView.requireViewById<ImageView>(R.id.sensor_use_microphone_icon).visibility = + if (sensor == SensorUseStartedActivity.MICROPHONE || + sensor == SensorUseStartedActivity.ALL_SENSORS) { + View.VISIBLE + } else { + View.GONE + } + customTitleView.requireViewById<ImageView>(R.id.sensor_use_camera_icon).visibility = + if (sensor == SensorUseStartedActivity.CAMERA || + sensor == SensorUseStartedActivity.ALL_SENSORS) { + View.VISIBLE + } else { + View.GONE + } + + setCustomTitle(customTitleView) + setMessage(Html.fromHtml(context.getString(when (sensor) { + SensorUseStartedActivity.MICROPHONE -> + R.string.sensor_privacy_start_use_mic_dialog_content + SensorUseStartedActivity.CAMERA -> + R.string.sensor_privacy_start_use_camera_dialog_content + SensorUseStartedActivity.ALL_SENSORS -> + R.string.sensor_privacy_start_use_mic_camera_dialog_content + else -> Resources.ID_NULL + }), 0)) + + setButton(BUTTON_POSITIVE, + context.getString(com.android.internal.R.string + .sensor_privacy_start_use_dialog_turn_on_button), clickListener) + setButton(BUTTON_NEGATIVE, + context.getString(com.android.internal.R.string + .cancel), clickListener) + + setCancelable(false) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt index f0fb5ebf9e1d..b0071d92481d 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt @@ -16,33 +16,28 @@ package com.android.systemui.sensorprivacy +import android.app.Activity +import android.app.AlertDialog import android.content.DialogInterface +import android.content.DialogInterface.BUTTON_NEGATIVE +import android.content.DialogInterface.BUTTON_POSITIVE import android.content.Intent import android.content.Intent.EXTRA_PACKAGE_NAME -import android.content.pm.PackageManager -import android.content.res.Resources import android.hardware.SensorPrivacyManager import android.hardware.SensorPrivacyManager.EXTRA_ALL_SENSORS import android.hardware.SensorPrivacyManager.EXTRA_SENSOR import android.hardware.SensorPrivacyManager.Sources.DIALOG import android.os.Bundle import android.os.Handler -import android.text.Html -import android.view.View.GONE -import android.view.View.VISIBLE -import android.widget.ImageView -import com.android.internal.app.AlertActivity -import com.android.internal.widget.DialogTitle -import com.android.systemui.R +import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION +import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__CANCEL +import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__ENABLE +import com.android.internal.util.FrameworkStatsLog.write import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.phone.KeyguardDismissUtil import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController import com.android.systemui.statusbar.policy.KeyguardStateController import javax.inject.Inject -import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION -import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__ENABLE -import com.android.internal.util.FrameworkStatsLog.PRIVACY_TOGGLE_DIALOG_INTERACTION__ACTION__CANCEL -import com.android.internal.util.FrameworkStatsLog.write /** * Dialog to be shown on top of apps that are attempting to use a sensor (e.g. microphone) which is @@ -55,7 +50,7 @@ class SensorUseStartedActivity @Inject constructor( private val keyguardStateController: KeyguardStateController, private val keyguardDismissUtil: KeyguardDismissUtil, @Background private val bgHandler: Handler -) : AlertActivity(), DialogInterface.OnClickListener { +) : Activity(), DialogInterface.OnClickListener { companion object { private val LOG_TAG = SensorUseStartedActivity::class.java.simpleName @@ -63,9 +58,9 @@ class SensorUseStartedActivity @Inject constructor( private const val SUPPRESS_REMINDERS_REMOVAL_DELAY_MILLIS = 2000L private const val UNLOCK_DELAY_MILLIS = 200L - private const val CAMERA = SensorPrivacyManager.Sensors.CAMERA - private const val MICROPHONE = SensorPrivacyManager.Sensors.MICROPHONE - private const val ALL_SENSORS = Integer.MAX_VALUE + internal const val CAMERA = SensorPrivacyManager.Sensors.CAMERA + internal const val MICROPHONE = SensorPrivacyManager.Sensors.MICROPHONE + internal const val ALL_SENSORS = Integer.MAX_VALUE } private var sensor = -1 @@ -74,6 +69,8 @@ class SensorUseStartedActivity @Inject constructor( private lateinit var sensorPrivacyListener: IndividualSensorPrivacyController.Callback + private var mDialog: AlertDialog? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -91,7 +88,7 @@ class SensorUseStartedActivity @Inject constructor( IndividualSensorPrivacyController.Callback { _, _ -> if (!sensorPrivacyController.isSensorBlocked(MICROPHONE) && !sensorPrivacyController.isSensorBlocked(CAMERA)) { - dismiss() + finish() } } @@ -109,71 +106,22 @@ class SensorUseStartedActivity @Inject constructor( } } sensorPrivacyListener = - IndividualSensorPrivacyController.Callback { - whichSensor: Int, isBlocked: Boolean -> + IndividualSensorPrivacyController.Callback { whichSensor: Int, + isBlocked: Boolean -> if (whichSensor == sensor && !isBlocked) { - dismiss() + finish() } } sensorPrivacyController.addCallback(sensorPrivacyListener) - sensorPrivacyController.addCallback { _, isBlocked -> - if (!isBlocked) { - dismiss() - } - } - } - - mAlertParams.apply { - try { - mCustomTitleView = mInflater.inflate(R.layout.sensor_use_started_title, null) - mCustomTitleView.findViewById<DialogTitle>(R.id.sensor_use_started_title_message)!! - .setText(when (sensor) { - MICROPHONE -> - R.string.sensor_privacy_start_use_mic_dialog_title - CAMERA -> - R.string.sensor_privacy_start_use_camera_dialog_title - ALL_SENSORS -> - R.string.sensor_privacy_start_use_mic_camera_dialog_title - else -> Resources.ID_NULL - }) - - mCustomTitleView.findViewById<ImageView>(R.id.sensor_use_microphone_icon)!! - .visibility = if (sensor == MICROPHONE || sensor == ALL_SENSORS) { - VISIBLE - } else { - GONE - } - mCustomTitleView.findViewById<ImageView>(R.id.sensor_use_camera_icon)!! - .visibility = if (sensor == CAMERA || sensor == ALL_SENSORS) { - VISIBLE - } else { - GONE - } - - mMessage = Html.fromHtml(getString(when (sensor) { - MICROPHONE -> - R.string.sensor_privacy_start_use_mic_dialog_content - CAMERA -> - R.string.sensor_privacy_start_use_camera_dialog_content - ALL_SENSORS -> - R.string.sensor_privacy_start_use_mic_camera_dialog_content - else -> Resources.ID_NULL - }, packageManager.getApplicationInfo(sensorUsePackageName, 0) - .loadLabel(packageManager)), 0) - } catch (e: PackageManager.NameNotFoundException) { + if (!sensorPrivacyController.isSensorBlocked(sensor)) { finish() return } - - mPositiveButtonText = getString( - com.android.internal.R.string.sensor_privacy_start_use_dialog_turn_on_button) - mNegativeButtonText = getString(android.R.string.cancel) - mPositiveButtonListener = this@SensorUseStartedActivity - mNegativeButtonListener = this@SensorUseStartedActivity } - setupAlert() + mDialog = SensorUseDialog(this, sensor, this) + mDialog!!.show() } override fun onStart() { @@ -212,7 +160,7 @@ class SensorUseStartedActivity @Inject constructor( } } - dismiss() + finish() } override fun onStop() { @@ -229,6 +177,7 @@ class SensorUseStartedActivity @Inject constructor( override fun onDestroy() { super.onDestroy() + mDialog?.dismiss() sensorPrivacyController.removeCallback(sensorPrivacyListener) } @@ -263,4 +212,4 @@ class SensorUseStartedActivity @Inject constructor( .suppressSensorPrivacyReminders(sensor, suppressed) } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java index 8cd3632b65ba..cc5cf4b63f99 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java @@ -24,6 +24,7 @@ import android.hardware.SensorPrivacyManager; import android.os.Bundle; import android.util.Log; import android.view.View; +import android.view.WindowManager; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; @@ -57,6 +58,8 @@ public class TvUnblockSensorActivity extends TvBottomSheetActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getWindow().addSystemFlags( + WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); boolean allSensors = getIntent().getBooleanExtra(SensorPrivacyManager.EXTRA_ALL_SENSORS, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java index 94f186f00778..6730afaafdef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java @@ -22,6 +22,9 @@ import android.content.Context; import android.os.Handler; import com.android.internal.statusbar.IStatusBarService; +import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.animation.DialogLaunchAnimator; +import com.android.systemui.animation.LaunchAnimator; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; @@ -62,6 +65,7 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl; import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback; +import com.android.systemui.statusbar.phone.SystemUIHostDialogProvider; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController; import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLogger; import com.android.systemui.statusbar.policy.RemoteInputUriController; @@ -248,11 +252,12 @@ public interface StatusBarDependenciesModule { ActivityStarter activityStarter, @Main Executor mainExecutor, IActivityManager iActivityManager, - OngoingCallLogger logger) { + OngoingCallLogger logger, + DumpManager dumpManager) { OngoingCallController ongoingCallController = new OngoingCallController( notifCollection, featureFlags, systemClock, activityStarter, mainExecutor, - iActivityManager, logger); + iActivityManager, logger, dumpManager); ongoingCallController.init(); return ongoingCallController; } @@ -261,4 +266,29 @@ public interface StatusBarDependenciesModule { @Binds QSCarrierGroupController.SlotIndexResolver provideSlotIndexResolver( QSCarrierGroupController.SubscriptionManagerSlotIndexResolver impl); + + /** + */ + @Provides + @SysUISingleton + static LaunchAnimator provideLaunchAnimator(Context context) { + return new LaunchAnimator(context); + } + + /** + */ + @Provides + @SysUISingleton + static ActivityLaunchAnimator provideActivityLaunchAnimator(LaunchAnimator launchAnimator) { + return new ActivityLaunchAnimator(launchAnimator); + } + + /** + */ + @Provides + @SysUISingleton + static DialogLaunchAnimator provideDialogLaunchAnimator(Context context, + LaunchAnimator launchAnimator) { + return new DialogLaunchAnimator(context, launchAnimator, new SystemUIHostDialogProvider()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt index a76389b1bbc8..bdade2c6c2c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -86,6 +86,7 @@ class LockscreenSmartspaceController @Inject constructor( var stateChangeListener = object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { smartspaceViews.add(v as SmartspaceView) + connectSession() updateTextColorFromWallpaper() statusBarStateListener.onDozeAmountChanged(0f, statusBarStateController.dozeAmount) @@ -93,6 +94,10 @@ class LockscreenSmartspaceController @Inject constructor( override fun onViewDetachedFromWindow(v: View) { smartspaceViews.remove(v as SmartspaceView) + + if (smartspaceViews.isEmpty()) { + disconnect() + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt index f19cf5d8d9c7..64a73054c434 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt @@ -2,8 +2,8 @@ package com.android.systemui.statusbar.notification import android.util.MathUtils import com.android.internal.annotations.VisibleForTesting -import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.animation.Interpolators +import com.android.systemui.animation.LaunchAnimator import kotlin.math.min /** Parameters for the notifications expand animations. */ @@ -15,7 +15,7 @@ class ExpandAnimationParameters( topCornerRadius: Float = 0f, bottomCornerRadius: Float = 0f -) : ActivityLaunchAnimator.State(top, bottom, left, right, topCornerRadius, bottomCornerRadius) { +) : LaunchAnimator.State(top, bottom, left, right, topCornerRadius, bottomCornerRadius) { @VisibleForTesting constructor() : this( top = 0, bottom = 0, left = 0, right = 0, topCornerRadius = 0f, bottomCornerRadius = 0f @@ -55,6 +55,6 @@ class ExpandAnimationParameters( } fun getProgress(delay: Long, duration: Long): Float { - return ActivityLaunchAnimator.getProgress(linearProgress, delay, duration) + return LaunchAnimator.getProgress(linearProgress, delay, duration) } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index a9ad0005973f..60f44a0d4fca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -305,9 +305,6 @@ public class NotificationEntryManager implements NotificationEntry entry = mPendingNotifications.get(key); entry.abortTask(); mPendingNotifications.remove(key); - for (NotifCollectionListener listener : mNotifCollectionListeners) { - listener.onEntryCleanUp(entry); - } mLogger.logInflationAborted(key, "pending", reason); } NotificationEntry addedEntry = getActiveNotificationUnfiltered(key); @@ -477,6 +474,18 @@ public class NotificationEntryManager implements if (!lifetimeExtended) { // At this point, we are guaranteed the notification will be removed abortExistingInflation(key, "removeNotification"); + // Fix for b/201097913: NotifCollectionListener#onEntryRemoved specifies that + // #onEntryRemoved should be called when a notification is cancelled, + // regardless of whether the notification was pending or active. + // Note that mNotificationEntryListeners are NOT notified of #onEntryRemoved + // because for that interface, #onEntryRemoved should only be called for + // active entries, NOT pending ones. + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryRemoved(pendingEntry, REASON_UNKNOWN); + } + for (NotifCollectionListener listener : mNotifCollectionListeners) { + listener.onEntryCleanUp(pendingEntry); + } mAllNotifications.remove(pendingEntry); mLeakDetector.trackGarbage(pendingEntry); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt index 1bbef2562d21..22c3eda03b1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt @@ -3,6 +3,7 @@ package com.android.systemui.statusbar.notification import android.view.ViewGroup import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.animation.LaunchAnimator import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.HeadsUpManagerPhone @@ -54,7 +55,7 @@ class NotificationLaunchAnimatorController( // Do nothing. Notifications are always animated inside their rootView. } - override fun createAnimatorState(): ActivityLaunchAnimator.State { + override fun createAnimatorState(): LaunchAnimator.State { // If the notification panel is collapsed, the clip may be larger than the height. val height = max(0, notification.actualHeight - notification.clipBottomAmount) val location = notification.locationOnScreen @@ -72,12 +73,12 @@ class NotificationLaunchAnimatorController( notification.currentBackgroundRadiusTop } val params = ExpandAnimationParameters( - top = windowTop, - bottom = location[1] + height, - left = location[0], - right = location[0] + notification.width, - topCornerRadius = topCornerRadius, - bottomCornerRadius = notification.currentBackgroundRadiusBottom + top = windowTop, + bottom = location[1] + height, + left = location[0], + right = location[0] + notification.width, + topCornerRadius = topCornerRadius, + bottomCornerRadius = notification.currentBackgroundRadiusBottom ) params.startTranslationZ = notification.translationZ @@ -86,8 +87,8 @@ class NotificationLaunchAnimatorController( params.startClipTopAmount = notification.clipTopAmount if (notification.isChildInGroup) { params.startNotificationTop += notification.notificationParent.translationY - val parentRoundedClip = Math.max(clipStartLocation - - notification.notificationParent.locationOnScreen[1], 0) + val parentRoundedClip = Math.max( + clipStartLocation - notification.notificationParent.locationOnScreen[1], 0) params.parentStartRoundedTopClipping = parentRoundedClip val parentClip = notification.notificationParent.clipTopAmount @@ -157,7 +158,7 @@ class NotificationLaunchAnimatorController( } override fun onLaunchAnimationProgress( - state: ActivityLaunchAnimator.State, + state: LaunchAnimator.State, progress: Float, linearProgress: Float ) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index a8c62fe2984c..5bf982b908cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -22,6 +22,7 @@ import android.os.PowerManager; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; +import android.util.Log; import android.util.MathUtils; import androidx.annotation.NonNull; @@ -35,6 +36,7 @@ import com.android.systemui.doze.DozeScreenState; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.tuner.TunerService; import java.io.FileDescriptor; @@ -256,9 +258,20 @@ public class DozeParameters implements } /** + * Whether the single tap sensor uses the proximity sensor for this device posture. + */ + public boolean singleTapUsesProx(@DevicePostureController.DevicePostureInt int devicePosture) { + return getPostureSpecificBool( + mResources.getIntArray(R.array.doze_single_tap_uses_prox_posture_mapping), + singleTapUsesProx(), + devicePosture + ); + } + + /** * Whether the single tap sensor uses the proximity sensor. */ - public boolean singleTapUsesProx() { + private boolean singleTapUsesProx() { return mResources.getBoolean(R.bool.doze_single_tap_uses_prox); } @@ -270,6 +283,17 @@ public class DozeParameters implements } /** + * Sensor to use for brightness changes. + */ + public String brightnessName(@DevicePostureController.DevicePostureInt int posture) { + return AmbientDisplayConfiguration.getSensorFromPostureMapping( + mResources.getStringArray(R.array.doze_brightness_sensor_name_posture_mapping), + null /* defaultValue */, + posture + ); + } + + /** * Callback to listen for DozeParameter changes. */ public void addCallback(Callback callback) { @@ -308,6 +332,20 @@ public class DozeParameters implements pw.println(getSelectivelyRegisterSensorsUsingProx()); } + private boolean getPostureSpecificBool( + int[] postureMapping, + boolean defaultSensorBool, + int posture) { + boolean bool = defaultSensorBool; + if (posture < postureMapping.length) { + bool = postureMapping[posture] != 0; + } else { + Log.e("DozeParameters", "Unsupported doze posture " + posture); + } + + return bool; + } + interface Callback { /** * Invoked when the value of getAlwaysOn may have changed. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 5f44a7d5d870..fe154d232a88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -72,6 +72,7 @@ public class KeyguardStatusBarView extends RelativeLayout { private boolean mKeyguardUserSwitcherEnabled; private final UserManager mUserManager; + private boolean mIsPrivacyDotEnabled; private int mSystemIconsSwitcherHiddenExpandedMargin; private int mStatusBarPaddingEnd; private int mMinDotWidth; @@ -112,7 +113,7 @@ public class KeyguardStatusBarView extends RelativeLayout { mCutoutSpace = findViewById(R.id.cutout_space_view); mStatusIconArea = findViewById(R.id.status_icon_area); mStatusIconContainer = findViewById(R.id.statusIcons); - + mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot); loadDimens(); } @@ -270,9 +271,10 @@ public class KeyguardStatusBarView extends RelativeLayout { mDisplayCutout, cornerCutoutMargins, mRoundedCornerPadding); // consider privacy dot space - final int minLeft = isLayoutRtl() ? Math.max(mMinDotWidth, mPadding.first) : mPadding.first; - final int minRight = isLayoutRtl() ? mPadding.second : - Math.max(mMinDotWidth, mPadding.second); + final int minLeft = (isLayoutRtl() && mIsPrivacyDotEnabled) + ? Math.max(mMinDotWidth, mPadding.first) : mPadding.first; + final int minRight = (!isLayoutRtl() && mIsPrivacyDotEnabled) + ? Math.max(mMinDotWidth, mPadding.second) : mPadding.second; setPadding(minLeft, waterfallTop, minRight, 0); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index 893aa6d6bc45..5feb4053f833 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -101,8 +101,8 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat @Override public void onOverlayChanged() { - KeyguardStatusBarViewController.this.onThemeChanged(); mView.onOverlayChanged(); + KeyguardStatusBarViewController.this.onThemeChanged(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 9018cef72f7d..4862d1617837 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -103,8 +103,8 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherComponent; import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.Interpolators; +import com.android.systemui.animation.LaunchAnimator; import com.android.systemui.biometrics.AuthController; import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; @@ -212,7 +212,7 @@ public class NotificationPanelViewController extends PanelViewController { */ private static final int FLING_HIDE = 2; private static final long ANIMATION_DELAY_ICON_FADE_IN = - ActivityLaunchAnimator.ANIMATION_DURATION - CollapsedStatusBarFragment.FADE_IN_DURATION + LaunchAnimator.ANIMATION_DURATION - CollapsedStatusBarFragment.FADE_IN_DURATION - CollapsedStatusBarFragment.FADE_IN_DELAY - 48; private final DozeParameters mDozeParameters; @@ -305,7 +305,6 @@ public class NotificationPanelViewController extends PanelViewController { private KeyguardUserSwitcherController mKeyguardUserSwitcherController; private KeyguardStatusBarView mKeyguardStatusBar; private KeyguardStatusBarViewController mKeyguardStatusBarViewController; - private ViewGroup mBigClockContainer; @VisibleForTesting QS mQs; private FrameLayout mQsFrame; private KeyguardStatusViewController mKeyguardStatusViewController; @@ -334,6 +333,7 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mKeyguardUserSwitcherEnabled; private boolean mDozing; private boolean mDozingOnDown; + private boolean mBouncerShowing; private int mBarState; private float mInitialHeightOnTouch; private float mInitialTouchX; @@ -404,7 +404,7 @@ public class NotificationPanelViewController extends PanelViewController { private Runnable mHeadsUpExistenceChangedRunnable = () -> { setHeadsUpAnimatingAway(false); - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); }; // TODO (b/162832756): once migrated to the new pipeline, delete legacy group manager private NotificationGroupManagerLegacy mGroupManager; @@ -801,7 +801,6 @@ public class NotificationPanelViewController extends PanelViewController { private void onFinishInflate() { loadDimens(); mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header); - mBigClockContainer = mView.findViewById(R.id.big_clock_container); FrameLayout userAvatarContainer = null; KeyguardUserSwitcherView keyguardUserSwitcherView = null; @@ -1084,7 +1083,6 @@ public class NotificationPanelViewController extends PanelViewController { R.layout.keyguard_user_switcher /* layoutId */, showKeyguardUserSwitcher /* enabled */); - mBigClockContainer.removeAllViews(); updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView, keyguardUserSwitcherView); @@ -1256,8 +1254,10 @@ public class NotificationPanelViewController extends PanelViewController { boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled(); final boolean hasVisibleNotifications = mNotificationStackScrollLayoutController .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia(); + boolean splitShadeWithActiveMedia = + mShouldUseSplitNotificationShade && mMediaDataManager.hasActiveMedia(); if ((hasVisibleNotifications && !mShouldUseSplitNotificationShade) - || (mShouldUseSplitNotificationShade && mMediaDataManager.hasActiveMedia())) { + || (splitShadeWithActiveMedia && !mDozing)) { mKeyguardStatusViewController.displayClock(SMALL); } else { mKeyguardStatusViewController.displayClock(LARGE); @@ -1319,7 +1319,8 @@ public class NotificationPanelViewController extends PanelViewController { private void updateKeyguardStatusViewAlignment(boolean animate) { boolean hasVisibleNotifications = mNotificationStackScrollLayoutController .getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia(); - boolean shouldBeCentered = !mShouldUseSplitNotificationShade || !hasVisibleNotifications; + boolean shouldBeCentered = + !mShouldUseSplitNotificationShade || !hasVisibleNotifications || mDozing; if (mStatusViewCentered != shouldBeCentered) { mStatusViewCentered = shouldBeCentered; ConstraintSet constraintSet = new ConstraintSet(); @@ -2180,7 +2181,6 @@ public class NotificationPanelViewController extends PanelViewController { if (mBarState == StatusBarState.SHADE_LOCKED || mBarState == KEYGUARD) { updateKeyguardBottomAreaAlpha(); positionClockAndNotifications(); - updateBigClockAlpha(); } if (mAccessibilityManager.isEnabled()) { @@ -2953,20 +2953,6 @@ public class NotificationPanelViewController extends PanelViewController { mLockIconViewController.setAlpha(alpha); } - /** - * Custom clock fades away when user drags up to unlock or pulls down quick settings. - * - * Updates alpha of custom clock to match the alpha of the KeyguardBottomArea. See - * {@link #updateKeyguardBottomAreaAlpha}. - */ - private void updateBigClockAlpha() { - float expansionAlpha = MathUtils.map( - isUnlockHintRunning() ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f, - getExpandedFraction()); - float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction()); - mBigClockContainer.setAlpha(alpha); - } - @Override protected void onExpandingStarted() { super.onExpandingStarted(); @@ -3228,11 +3214,19 @@ public class NotificationPanelViewController extends PanelViewController { public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { mHeadsUpAnimatingAway = headsUpAnimatingAway; mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway); - updateHeadsUpVisibility(); + updateVisibility(); } - private void updateHeadsUpVisibility() { - ((PhoneStatusBarView) mBar).setHeadsUpVisible(mHeadsUpAnimatingAway || mHeadsUpPinnedMode); + /** Set whether the bouncer is showing. */ + public void setBouncerShowing(boolean bouncerShowing) { + mBouncerShowing = bouncerShowing; + updateVisibility(); + } + + @Override + protected boolean shouldPanelBeVisible() { + boolean headsUpVisible = mHeadsUpAnimatingAway || mHeadsUpPinnedMode; + return headsUpVisible || isExpanded() || mBouncerShowing; } @Override @@ -3316,7 +3310,6 @@ public class NotificationPanelViewController extends PanelViewController { } mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight); updateKeyguardBottomAreaAlpha(); - updateBigClockAlpha(); updateStatusBarIcons(); } @@ -3594,7 +3587,7 @@ public class NotificationPanelViewController extends PanelViewController { } public void applyLaunchAnimationProgress(float linearProgress) { - boolean hideIcons = ActivityLaunchAnimator.getProgress(linearProgress, + boolean hideIcons = LaunchAnimator.getProgress(linearProgress, ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f; if (hideIcons != mHideIconsDuringLaunchAnimation) { mHideIconsDuringLaunchAnimation = hideIcons; @@ -3642,6 +3635,11 @@ public class NotificationPanelViewController extends PanelViewController { } } + /** */ + public void setImportantForAccessibility(int mode) { + mView.setImportantForAccessibility(mode); + } + /** * Do not let the user drag the shade up and down for the current touch session. * This is necessary to avoid shade expansion while/after the bouncer is dismissed. @@ -4216,7 +4214,7 @@ public class NotificationPanelViewController extends PanelViewController { } updateGestureExclusionRect(); mHeadsUpPinnedMode = inPinnedMode; - updateHeadsUpVisibility(); + updateVisibility(); mKeyguardStatusBarViewController.updateForHeadsUp(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index e775e96de749..247ede91eeb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -33,8 +33,6 @@ public abstract class PanelBar extends FrameLayout { private static final boolean SPEW = false; private static final String PANEL_BAR_SUPER_PARCELABLE = "panel_bar_super_parcelable"; private static final String STATE = "state"; - private boolean mBouncerShowing; - private boolean mExpanded; protected float mPanelFraction; public static final void LOG(String fmt, Object... args) { @@ -99,33 +97,6 @@ public abstract class PanelBar extends FrameLayout { pv.setBar(this); } - public void setBouncerShowing(boolean showing) { - mBouncerShowing = showing; - int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS - : IMPORTANT_FOR_ACCESSIBILITY_AUTO; - - setImportantForAccessibility(important); - updateVisibility(); - - if (mPanel != null) mPanel.getView().setImportantForAccessibility(important); - } - - public float getExpansionFraction() { - return mPanelFraction; - } - - public boolean isExpanded() { - return mExpanded; - } - - protected void updateVisibility() { - mPanel.getView().setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE); - } - - protected boolean shouldPanelBeVisible() { - return mExpanded || mBouncerShowing; - } - public boolean panelEnabled() { return true; } @@ -183,9 +154,7 @@ public abstract class PanelBar extends FrameLayout { boolean fullyClosed = true; boolean fullyOpened = false; if (SPEW) LOG("panelExpansionChanged: start state=%d, f=%.1f", mState, frac); - mExpanded = expanded; mPanelFraction = frac; - updateVisibility(); // adjust any other panels that may be partially visible if (expanded) { if (mState == STATE_CLOSED) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 51cae8c4af7f..b2155154d652 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.phone; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; + import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE; import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK; import static com.android.systemui.classifier.Classifier.GENERIC; @@ -315,7 +318,7 @@ public abstract class PanelViewController { } private void startOpening(MotionEvent event) { - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); maybeVibrateOnOpening(); //TODO: keyguard opens QS a different way; log that too? @@ -447,7 +450,7 @@ public abstract class PanelViewController { protected void onTrackingStopped(boolean expand) { mTracking = false; mBar.onTrackingStopped(expand); - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); } protected void onTrackingStarted() { @@ -455,7 +458,7 @@ public abstract class PanelViewController { mTracking = true; mBar.onTrackingStarted(); notifyExpandingStarted(); - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); } /** @@ -685,7 +688,7 @@ public abstract class PanelViewController { } else { cancelJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); } - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); } protected abstract boolean shouldUseDismissingAnimation(); @@ -760,7 +763,7 @@ public abstract class PanelViewController { mExpandedFraction = Math.min(1f, maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight); onHeightUpdated(mExpandedHeight); - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); } /** @@ -878,7 +881,7 @@ public abstract class PanelViewController { if (mExpanding) { notifyExpandingFinished(); } - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); // Wait for window manager to pickup the change, so we know the maximum height of the panel // then. @@ -916,7 +919,7 @@ public abstract class PanelViewController { } if (mInstantExpanding) { mInstantExpanding = false; - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); } } @@ -1022,7 +1025,7 @@ public abstract class PanelViewController { public void onAnimationEnd(Animator animation) { setAnimator(null); onAnimationFinished.run(); - notifyBarPanelExpansionChanged(); + updatePanelExpansionAndVisibility(); } }); animator.start(); @@ -1059,19 +1062,39 @@ public abstract class PanelViewController { return animator; } - protected void notifyBarPanelExpansionChanged() { + /** Update the visibility of {@link PanelView} if necessary. */ + public void updateVisibility() { + mView.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE); + } + + /** Returns true if {@link PanelView} should be visible. */ + abstract boolean shouldPanelBeVisible(); + + /** + * Updates the panel expansion and {@link PanelView} visibility if necessary. + * + * TODO(b/200063118): Could public calls to this method be replaced with calls to + * {@link #updateVisibility()}? That would allow us to make this method private. + */ + public void updatePanelExpansionAndVisibility() { if (mBar != null) { - mBar.panelExpansionChanged( - mExpandedFraction, - mExpandedFraction > 0f || mInstantExpanding - || isPanelVisibleBecauseOfHeadsUp() || mTracking - || mHeightAnimator != null && !mIsSpringBackAnimation); + mBar.panelExpansionChanged(mExpandedFraction, isExpanded()); } + updateVisibility(); for (int i = 0; i < mExpansionListeners.size(); i++) { mExpansionListeners.get(i).onPanelExpansionChanged(mExpandedFraction, mTracking); } } + public boolean isExpanded() { + return mExpandedFraction > 0f + || mInstantExpanding + || isPanelVisibleBecauseOfHeadsUp() + || mTracking + || mHeightAnimator != null + && !mIsSpringBackAnimation; + } + public void addExpansionListener(PanelExpansionListener panelExpansionListener) { mExpansionListeners.add(panelExpansionListener); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index af556a26e3af..9ab6cdd3053b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -402,16 +402,6 @@ public class PhoneStatusBarView extends PanelBar { getPaddingBottom()); } - public void setHeadsUpVisible(boolean headsUpVisible) { - mHeadsUpVisible = headsUpVisible; - updateVisibility(); - } - - @Override - protected boolean shouldPanelBeVisible() { - return mHeadsUpVisible || super.shouldPanelBeVisible(); - } - /** An interface that will provide whether panel is enabled. */ interface PanelEnabledProvider { /** Returns true if the panel is enabled and false otherwise. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index 28040fd8d8a1..4c0332a75df1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -61,6 +61,10 @@ class PhoneStatusBarViewController( } } + fun setImportantForAccessibility(mode: Int) { + mView.importantForAccessibility = mode + } + private class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider { override fun getViewCenter(view: View, outPoint: Point) = when (view.id) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 4213902b7cf1..a564637aa510 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -1230,6 +1230,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump pw.println(mDefaultScrimAlpha); pw.print(" mExpansionFraction="); pw.println(mPanelExpansion); + pw.print(" mExpansionAffectsAlpha="); + pw.println(mExpansionAffectsAlpha); pw.print(" mState.getMaxLightRevealScrimAlpha="); pw.println(mState.getMaxLightRevealScrimAlpha()); 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 ee7725f670b0..3bdc08be63e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -26,6 +26,8 @@ import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; +import static androidx.core.view.ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO; +import static androidx.core.view.ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; import static androidx.lifecycle.Lifecycle.State.RESUMED; import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; @@ -135,6 +137,7 @@ import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.DelegateLaunchAnimatorController; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.battery.BatteryMeterViewController; import com.android.systemui.biometrics.AuthRippleController; @@ -669,7 +672,8 @@ public class StatusBar extends SystemUI implements private final SysuiStatusBarStateController mStatusBarStateController; private HeadsUpAppearanceController mHeadsUpAppearanceController; - private ActivityLaunchAnimator mActivityLaunchAnimator; + private final ActivityLaunchAnimator mActivityLaunchAnimator; + private final DialogLaunchAnimator mDialogLaunchAnimator; private NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider; protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; @@ -792,7 +796,9 @@ public class StatusBar extends SystemUI implements UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, Optional<StartingSurface> startingSurfaceOptional, TunerService tunerService, - DumpManager dumpManager) { + DumpManager dumpManager, + ActivityLaunchAnimator activityLaunchAnimator, + DialogLaunchAnimator dialogLaunchAnimator) { super(context); mNotificationsController = notificationsController; mLightBarController = lightBarController; @@ -900,6 +906,8 @@ public class StatusBar extends SystemUI implements }); mActivityIntentHelper = new ActivityIntentHelper(mContext); + mActivityLaunchAnimator = activityLaunchAnimator; + mDialogLaunchAnimator = dialogLaunchAnimator; // TODO(b/190746471): Find a better home for this. DateTimeView.setReceiverHandler(timeTickHandler); @@ -1139,6 +1147,8 @@ public class StatusBar extends SystemUI implements mNotificationPanelViewController.addExpansionListener( this::dispatchPanelExpansionForKeyguardDismiss); + mUserSwitcherController.init(mNotificationShadeWindowView); + // Allow plugins to reference DarkIconDispatcher and StatusBarStateController mPluginDependencyProvider.allowPluginDependency(DarkIconDispatcher.class); mPluginDependencyProvider.allowPluginDependency(StatusBarStateController.class); @@ -1180,22 +1190,13 @@ public class StatusBar extends SystemUI implements ); mBatteryMeterViewController.init(); - // CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of - // mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false. - // PhoneStatusBarView's new instance will set to be gone in - // PanelBar.updateVisibility after calling mStatusBarView.setBouncerShowing - // that will trigger PanelBar.updateVisibility. If there is a heads up showing, - // it needs to notify PhoneStatusBarView's new instance to update the correct - // status by calling mNotificationPanel.notifyBarPanelExpansionChanged(). - if (mHeadsUpManager.hasPinnedHeadsUp()) { - mNotificationPanelViewController.notifyBarPanelExpansionChanged(); - } - mStatusBarView.setBouncerShowing(mBouncerShowing); - if (oldStatusBarView != null) { - float fraction = oldStatusBarView.getExpansionFraction(); - boolean expanded = oldStatusBarView.isExpanded(); - mStatusBarView.panelExpansionChanged(fraction, expanded); - } + // Ensure we re-propagate panel expansion values to the panel controller and + // any listeners it may have, such as PanelBar. This will also ensure we + // re-display the notification panel if necessary (for example, if + // a heads-up notification was being displayed and should continue being + // displayed). + mNotificationPanelViewController.updatePanelExpansionAndVisibility(); + setBouncerShowingForStatusBarComponents(mBouncerShowing); HeadsUpAppearanceController oldController = mHeadsUpAppearanceController; if (mHeadsUpAppearanceController != null) { @@ -1467,7 +1468,7 @@ public class StatusBar extends SystemUI implements private void setUpPresenter() { // Set up the initial notification state. - mActivityLaunchAnimator = new ActivityLaunchAnimator(mKeyguardHandler, mContext); + mActivityLaunchAnimator.setCallback(mKeyguardHandler); mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider( mNotificationShadeWindowViewController, mStackScrollerController.getNotificationListContainer(), @@ -2549,7 +2550,8 @@ public class StatusBar extends SystemUI implements animationController != null && !willLaunchResolverActivity && shouldAnimateLaunch( true /* isActivityIntent */); ActivityLaunchAnimator.Controller animController = - animate ? wrapAnimationController(animationController, dismissShade) : null; + animationController != null ? wrapAnimationController(animationController, + dismissShade) : null; // If we animate, we will dismiss the shade only once the animation is done. This is taken // care of by the StatusBarLaunchAnimationController. @@ -3522,7 +3524,7 @@ public class StatusBar extends SystemUI implements mBouncerShowing = bouncerShowing; mKeyguardBypassController.setBouncerShowing(bouncerShowing); mPulseExpansionHandler.setBouncerShowing(bouncerShowing); - if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing); + setBouncerShowingForStatusBarComponents(bouncerShowing); updateHideIconsForBouncer(true /* animate */); mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */); updateScrimController(); @@ -3532,6 +3534,23 @@ public class StatusBar extends SystemUI implements } /** + * Propagate the bouncer state to status bar components. + * + * Separate from {@link #setBouncerShowing} because we sometimes re-create the status bar and + * should update only the status bar components. + */ + private void setBouncerShowingForStatusBarComponents(boolean bouncerShowing) { + int importance = bouncerShowing + ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + : IMPORTANT_FOR_ACCESSIBILITY_AUTO; + if (mPhoneStatusBarViewController != null) { + mPhoneStatusBarViewController.setImportantForAccessibility(importance); + } + mNotificationPanelViewController.setImportantForAccessibility(importance); + mNotificationPanelViewController.setBouncerShowing(bouncerShowing); + } + + /** * Collapses the notification shade if it is tracking or expanded. */ public void collapseShade() { @@ -3775,8 +3794,11 @@ public class StatusBar extends SystemUI implements || mKeyguardStateController.isKeyguardFadingAway(); // Do not animate the scrim expansion when triggered by the fingerprint sensor. - mScrimController.setExpansionAffectsAlpha( - !mBiometricUnlockController.isBiometricUnlock()); + boolean onKeyguardOrHidingIt = mKeyguardStateController.isShowing() + || mKeyguardStateController.isKeyguardFadingAway() + || mKeyguardStateController.isKeyguardGoingAway(); + mScrimController.setExpansionAffectsAlpha(!(mBiometricUnlockController.isBiometricUnlock() + && onKeyguardOrHidingIt)); boolean launchingAffordanceWithPreview = mNotificationPanelViewController.isLaunchingAffordanceWithPreview(); @@ -4200,10 +4222,9 @@ public class StatusBar extends SystemUI implements } private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) { - if (mStatusBarView != null) { - expansionChangedListener.onExpansionChanged(mStatusBarView.getExpansionFraction(), - mStatusBarView.isExpanded()); - } + expansionChangedListener.onExpansionChanged( + mNotificationPanelViewController.getExpandedFraction(), + mNotificationPanelViewController.isExpanded()); } public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) { @@ -4426,6 +4447,8 @@ public class StatusBar extends SystemUI implements && !mBiometricUnlockController.isWakeAndUnlock()) { mLightRevealScrim.setRevealAmount(1f - linear); } + + mDialogLaunchAnimator.onDozeAmountChanged(linear); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt index 515094bd6ec0..61552f065bc4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt @@ -70,6 +70,9 @@ class StatusBarContentInsetsProvider @Inject constructor( // (e.g. network displays) private val insetsCache = LruCache<CacheKey, Rect>(MAX_CACHE_SIZE) private val listeners = mutableSetOf<StatusBarContentInsetsChangedListener>() + private val isPrivacyDotEnabled: Boolean by lazy(LazyThreadSafetyMode.PUBLICATION) { + context.resources.getBoolean(R.bool.config_enablePrivacyDot) + } init { configurationController.addCallback(this) @@ -152,8 +155,9 @@ class StatusBarContentInsetsProvider @Inject constructor( val isRtl = rotatedResources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL val roundedCornerPadding = rotatedResources .getDimensionPixelSize(R.dimen.rounded_corner_content_padding) - val minDotWidth = rotatedResources - .getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding) + val minDotWidth = if (isPrivacyDotEnabled) + rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_min_padding) + else 0 val minLeft: Int val minRight: Int diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 77254435b688..5bc97a5b316d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -53,6 +53,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.FaceAuthScreenBrightnessController; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.QuickStepContract; @@ -94,7 +95,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb // with the appear animations of the PIN/pattern/password views. private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320; - private static final long WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS = 200; + // The duration to fade the nav bar content in/out when the device starts to sleep + private static final long NAV_BAR_CONTENT_FADE_DURATION = 125; // Duration of the Keyguard dismissal animation in case the user is currently locked. This is to // make everything a bit slower to bridge a gap until the user is unlocked and home screen has @@ -197,10 +199,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastGesturalNav; private boolean mLastIsDocked; private boolean mLastPulsing; - private boolean mLastAnimatedToSleep; private int mLastBiometricMode; private boolean mQsExpanded; - private boolean mAnimatedToSleep; private OnDismissAction mAfterKeyguardGoneAction; private Runnable mKeyguardGoneCancelAction; @@ -325,20 +325,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mDockManager.addListener(mDockEventListener); mIsDocked = mDockManager.isDocked(); } - mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() { - @Override - public void onFinishedWakingUp() { - mAnimatedToSleep = false; - updateStates(); - } - - @Override - public void onFinishedGoingToSleep() { - mAnimatedToSleep = - mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying(); - updateStates(); - } - }); } @Override @@ -571,12 +557,26 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void onStartedWakingUp() { mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() .setAnimationsDisabled(false); + View currentView = getCurrentNavBarView(); + if (currentView != null) { + currentView.animate() + .alpha(1f) + .setDuration(NAV_BAR_CONTENT_FADE_DURATION) + .start(); + } } @Override public void onStartedGoingToSleep() { mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() .setAnimationsDisabled(true); + View currentView = getCurrentNavBarView(); + if (currentView != null) { + currentView.animate() + .alpha(0f) + .setDuration(NAV_BAR_CONTENT_FADE_DURATION) + .start(); + } } @Override @@ -1013,10 +1013,28 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastBiometricMode = mBiometricUnlockController.getMode(); mLastGesturalNav = mGesturalNav; mLastIsDocked = mIsDocked; - mLastAnimatedToSleep = mAnimatedToSleep; mStatusBar.onKeyguardViewManagerStatesUpdated(); } + /** + * Updates the visibility of the nav bar content views. + */ + private void updateNavigationBarContentVisibility(boolean navBarContentVisible) { + final NavigationBarView navBarView = mStatusBar.getNavigationBarView(); + if (navBarView != null && navBarView.getCurrentView() != null) { + final View currentView = navBarView.getCurrentView(); + currentView.setVisibility(navBarContentVisible ? View.VISIBLE : View.INVISIBLE); + } + } + + private View getCurrentNavBarView() { + final NavigationBarView navBarView = mStatusBar.getNavigationBarView(); + return navBarView != null ? navBarView.getCurrentView() : null; + } + + /** + * Updates the visibility of the nav bar window (which will cause insets changes). + */ protected void updateNavigationBarVisibility(boolean navBarVisible) { if (mStatusBar.getNavigationBarView() != null) { if (navBarVisible) { @@ -1044,7 +1062,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING; boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked) && mGesturalNav; - return (!mAnimatedToSleep && !keyguardShowing && !hideWhileDozing || mBouncer.isShowing() + return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing() || mRemoteInputActive || keyguardWithGestureNav || mGlobalActionsVisible); } @@ -1057,7 +1075,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING; boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing || mLastPulsing && !mLastIsDocked) && mLastGesturalNav; - return (!mLastAnimatedToSleep && !keyguardShowing && !hideWhileDozing || mLastBouncerShowing + return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav || mLastGlobalActionsVisible); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt index 14e513a0556d..32aae6c05df6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt @@ -1,6 +1,7 @@ package com.android.systemui.statusbar.phone import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.animation.LaunchAnimator /** * A [ActivityLaunchAnimator.Controller] that takes care of collapsing the status bar at the right @@ -22,7 +23,7 @@ class StatusBarLaunchAnimatorController( delegate.onLaunchAnimationStart(isExpandingFullyAbove) statusBar.notificationPanelViewController.setIsLaunchAnimationRunning(true) if (!isExpandingFullyAbove) { - statusBar.collapsePanelWithDuration(ActivityLaunchAnimator.ANIMATION_DURATION.toInt()) + statusBar.collapsePanelWithDuration(LaunchAnimator.ANIMATION_DURATION.toInt()) } } @@ -33,7 +34,7 @@ class StatusBarLaunchAnimatorController( } override fun onLaunchAnimationProgress( - state: ActivityLaunchAnimator.State, + state: LaunchAnimator.State, progress: Float, linearProgress: Float ) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 1e98c75f2616..9415d5082d10 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -30,19 +30,24 @@ import android.view.WindowManager.LayoutParams; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.animation.DialogListener; +import com.android.systemui.animation.ListenableDialog; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.policy.KeyguardStateController; +import java.util.LinkedHashSet; +import java.util.Set; + /** * Base class for dialogs that should appear over panels and keyguard. * The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast, * and dismisses itself when it receives the broadcast. */ -public class SystemUIDialog extends AlertDialog { - +public class SystemUIDialog extends AlertDialog implements ListenableDialog { private final Context mContext; private final DismissReceiver mDismissReceiver; + private final Set<DialogListener> mDialogListeners = new LinkedHashSet<>(); public SystemUIDialog(Context context) { this(context, R.style.Theme_SystemUI_Dialog); @@ -72,6 +77,43 @@ public class SystemUIDialog extends AlertDialog { mDismissReceiver.unregister(); } + @Override + public void addListener(DialogListener listener) { + mDialogListeners.add(listener); + } + + @Override + public void removeListener(DialogListener listener) { + mDialogListeners.remove(listener); + } + + @Override + public void dismiss() { + super.dismiss(); + + for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) { + listener.onDismiss(); + } + } + + @Override + public void hide() { + super.hide(); + + for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) { + listener.onHide(); + } + } + + @Override + public void show() { + super.show(); + + for (DialogListener listener : new LinkedHashSet<>(mDialogListeners)) { + listener.onShow(); + } + } + public void setShowForAllUsers(boolean show) { setShowForAllUsers(this, show); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt new file mode 100644 index 000000000000..6a49a6da0d62 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIHostDialogProvider.kt @@ -0,0 +1,36 @@ +package com.android.systemui.statusbar.phone + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.android.systemui.animation.HostDialogProvider + +/** An implementation of [HostDialogProvider] to be used when animating SysUI dialogs. */ +class SystemUIHostDialogProvider : HostDialogProvider { + override fun createHostDialog( + context: Context, + theme: Int, + onCreateCallback: () -> Unit, + dismissOverride: (() -> Unit) -> Unit + ): Dialog { + return SystemUIHostDialog(context, theme, onCreateCallback, dismissOverride) + } + + private class SystemUIHostDialog( + context: Context, + theme: Int, + private val onCreateCallback: () -> Unit, + private val dismissOverride: (() -> Unit) -> Unit + ) : SystemUIDialog(context, theme) { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + onCreateCallback() + } + + override fun dismiss() { + dismissOverride { + super.dismiss() + } + } + } +}
\ No newline at end of file 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 13eb75a4d508..0d43b9323a39 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 @@ -28,6 +28,8 @@ import com.android.internal.logging.MetricsLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.InitController; +import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollector; @@ -235,7 +237,9 @@ public interface StatusBarPhoneModule { UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, Optional<StartingSurface> startingSurfaceOptional, TunerService tunerService, - DumpManager dumpManager) { + DumpManager dumpManager, + ActivityLaunchAnimator activityLaunchAnimator, + DialogLaunchAnimator dialogLaunchAnimator) { return new StatusBar( context, notificationsController, @@ -333,6 +337,8 @@ public interface StatusBarPhoneModule { unlockedScreenOffAnimationController, startingSurfaceOptional, tunerService, - dumpManager); + dumpManager, + activityLaunchAnimator, + dialogLaunchAnimator); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt index eeff010e0bdf..ab6ee89627ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt @@ -26,10 +26,12 @@ import android.util.Log import android.view.View import androidx.annotation.VisibleForTesting import com.android.internal.jank.InteractionJankMonitor +import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.ActivityStarter import com.android.systemui.flags.FeatureFlags import com.android.systemui.statusbar.notification.collection.NotificationEntry @@ -37,6 +39,8 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Co import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import com.android.systemui.statusbar.policy.CallbackController import com.android.systemui.util.time.SystemClock +import java.io.FileDescriptor +import java.io.PrintWriter import java.util.concurrent.Executor import javax.inject.Inject @@ -51,13 +55,14 @@ class OngoingCallController @Inject constructor( private val activityStarter: ActivityStarter, @Main private val mainExecutor: Executor, private val iActivityManager: IActivityManager, - private val logger: OngoingCallLogger -) : CallbackController<OngoingCallListener> { + private val logger: OngoingCallLogger, + private val dumpManager: DumpManager, +) : CallbackController<OngoingCallListener>, Dumpable { /** Non-null if there's an active call notification. */ private var callNotificationInfo: CallNotificationInfo? = null /** True if the application managing the call is visible to the user. */ - private var isCallAppVisible: Boolean = true + private var isCallAppVisible: Boolean = false private var chipView: View? = null private var uidObserver: IUidObserver.Stub? = null @@ -103,16 +108,7 @@ class OngoingCallController @Inject constructor( } } - // Fix for b/199600334 - override fun onEntryCleanUp(entry: NotificationEntry) { - removeChipIfNeeded(entry) - } - override fun onEntryRemoved(entry: NotificationEntry, reason: Int) { - removeChipIfNeeded(entry) - } - - private fun removeChipIfNeeded(entry: NotificationEntry) { if (entry.sbn.key == callNotificationInfo?.key) { removeChip() } @@ -120,6 +116,7 @@ class OngoingCallController @Inject constructor( } fun init() { + dumpManager.registerDumpable(this) if (featureFlags.isOngoingCallStatusBarChipEnabled) { notifCollection.addCollectionListener(notifListener) } @@ -299,6 +296,11 @@ class OngoingCallController @Inject constructor( */ fun hasValidStartTime(): Boolean = callStartTime > 0 } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.println("Active call notification: $callNotificationInfo") + pw.println("Call app visible: $isCallAppVisible") + } } private fun isCallNotification(entry: NotificationEntry): Boolean { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java index fbfa5e5ea109..85968753d54f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureController.java @@ -50,6 +50,26 @@ public interface DevicePostureController extends CallbackController<Callback> { /** Return the current device posture. */ @DevicePostureInt int getDevicePosture(); + /** + * String representation of DevicePostureInt. + */ + static String devicePostureToString(@DevicePostureInt int posture) { + switch (posture) { + case DEVICE_POSTURE_CLOSED: + return "DEVICE_POSTURE_CLOSED"; + case DEVICE_POSTURE_HALF_OPENED: + return "DEVICE_POSTURE_HALF_OPENED"; + case DEVICE_POSTURE_OPENED: + return "DEVICE_POSTURE_OPENED"; + case DEVICE_POSTURE_FLIPPED: + return "DEVICE_POSTURE_FLIPPED"; + case DEVICE_POSTURE_UNKNOWN: + return "DEVICE_POSTURE_UNKNOWN"; + default: + return "UNSUPPORTED POSTURE posture=" + posture; + } + } + /** Callback to be notified about device posture changes. */ interface Callback { /** Called when the posture changes. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 22f08ada5fc4..dadc01664b4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -25,6 +25,7 @@ import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.Dialog; +import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; @@ -55,6 +56,7 @@ import android.view.WindowManagerGlobal; import android.widget.BaseAdapter; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.RestrictedLockUtilsInternal; @@ -75,6 +77,7 @@ import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.qs.tiles.UserDetailView; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.telephony.TelephonyListenerManager; import com.android.systemui.user.CreateUserActivity; @@ -107,6 +110,7 @@ public class UserSwitcherController implements Dumpable { private static final int PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000; private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; + private static final long MULTI_USER_JOURNEY_TIMEOUT = 20000l; protected final Context mContext; protected final UserTracker mUserTracker; @@ -123,6 +127,7 @@ public class UserSwitcherController implements Dumpable { private final BroadcastDispatcher mBroadcastDispatcher; private final TelephonyListenerManager mTelephonyListenerManager; private final IActivityTaskManager mActivityTaskManager; + private final InteractionJankMonitor mInteractionJankMonitor; private ArrayList<UserRecord> mUsers = new ArrayList<>(); @VisibleForTesting @@ -141,15 +146,18 @@ public class UserSwitcherController implements Dumpable { private Intent mSecondaryUserServiceIntent; private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2); private final UiEventLogger mUiEventLogger; + private final IActivityManager mActivityManager; public final DetailAdapter mUserDetailAdapter; private final Executor mBgExecutor; private final boolean mGuestUserAutoCreated; private final AtomicBoolean mGuestIsResetting; private final AtomicBoolean mGuestCreationScheduled; private FalsingManager mFalsingManager; + private NotificationShadeWindowView mRootView; @Inject public UserSwitcherController(Context context, + IActivityManager activityManager, UserManager userManager, UserTracker userTracker, KeyguardStateController keyguardStateController, @@ -165,14 +173,17 @@ public class UserSwitcherController implements Dumpable { UserDetailAdapter userDetailAdapter, SecureSettings secureSettings, @Background Executor bgExecutor, + InteractionJankMonitor interactionJankMonitor, DumpManager dumpManager) { mContext = context; + mActivityManager = activityManager; mUserTracker = userTracker; mBroadcastDispatcher = broadcastDispatcher; mTelephonyListenerManager = telephonyListenerManager; mActivityTaskManager = activityTaskManager; mUiEventLogger = uiEventLogger; mFalsingManager = falsingManager; + mInteractionJankMonitor = interactionJankMonitor; mGuestResumeSessionReceiver = new GuestResumeSessionReceiver( this, mUserTracker, mUiEventLogger, secureSettings); mUserDetailAdapter = userDetailAdapter; @@ -485,8 +496,11 @@ public class UserSwitcherController implements Dumpable { protected void switchToUserId(int id) { try { + mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder + .withView(InteractionJankMonitor.CUJ_USER_SWITCH, mRootView) + .setTimeout(MULTI_USER_JOURNEY_TIMEOUT)); pauseRefreshUsers(); - ActivityManager.getService().switchUser(id); + mActivityManager.switchUser(id); } catch (RemoteException e) { Log.e(TAG, "Couldn't switch user.", e); } @@ -793,6 +807,10 @@ public class UserSwitcherController implements Dumpable { return guest.id; } + public void init(NotificationShadeWindowView notificationShadeWindowView) { + mRootView = notificationShadeWindowView; + } + public static abstract class BaseUserAdapter extends BaseAdapter { final UserSwitcherController mController; diff --git a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt index a9810458fe90..2c01a7003a16 100644 --- a/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt +++ b/packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt @@ -40,8 +40,8 @@ class WallpaperController @Inject constructor(private val wallpaperManager: Wall this.wallpaperInfo = wallpaperInfo } - private val shouldUseDefaultDeviceStateChangeTransition: Boolean - get() = wallpaperInfo?.shouldUseDefaultDeviceStateChangeTransition() + private val shouldUseDefaultDisplayStateChangeTransition: Boolean + get() = wallpaperInfo?.shouldUseDefaultDisplayStateChangeTransition() ?: true fun setNotificationShadeZoom(zoomOut: Float) { @@ -50,7 +50,7 @@ class WallpaperController @Inject constructor(private val wallpaperManager: Wall } fun setUnfoldTransitionZoom(zoomOut: Float) { - if (shouldUseDefaultDeviceStateChangeTransition) { + if (shouldUseDefaultDisplayStateChangeTransition) { unfoldTransitionZoomOut = zoomOut updateZoom() } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 83c2a9b1be33..a7c5ad2e3716 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -126,9 +126,10 @@ public class WMShellModule { static AppPairsController provideAppPairs(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor, - DisplayImeController displayImeController) { + DisplayImeController displayImeController, + DisplayInsetsController displayInsetsController) { return new AppPairsController(shellTaskOrganizer, syncQueue, displayController, - mainExecutor, displayImeController); + mainExecutor, displayImeController, displayInsetsController); } // diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index ce02b8339422..e4336fe07dbb 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -97,6 +97,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { mLargeClockFrame = mKeyguardClockSwitch.findViewById(R.id.lockscreen_clock_view_large); mLargeClockView = mKeyguardClockSwitch.findViewById(R.id.animatable_clock_view_large); mBigClock = new TextClock(getContext()); + mKeyguardClockSwitch.mChildrenAreLaidOut = true; MockitoAnnotations.initMocks(this); } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index d3557d4b1809..0772b2098565 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -78,6 +78,7 @@ import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; import com.android.dx.mockito.inline.extended.ExtendedMockito; +import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; @@ -171,6 +172,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { @Mock private FeatureFlags mFeatureFlags; @Mock + private InteractionJankMonitor mInteractionJankMonitor; + @Mock private Vibrator mVibrator; @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor; @@ -737,6 +740,16 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void testMultiUserJankMonitor_whenUserSwitches() throws Exception { + final IRemoteCallback reply = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) {} // do nothing + }; + mKeyguardUpdateMonitor.handleUserSwitchComplete(10 /* user */); + verify(mInteractionJankMonitor).end(eq(InteractionJankMonitor.CUJ_USER_SWITCH)); + } + + @Test public void testGetUserCanSkipBouncer_whenTrust() { int user = KeyguardUpdateMonitor.getCurrentUser(); mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */); @@ -1051,7 +1064,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mRingerModeTracker, mBackgroundExecutor, mStatusBarStateController, mLockPatternUtils, mAuthController, mTelephonyListenerManager, mFeatureFlags, - mVibrator); + mInteractionJankMonitor, mVibrator); setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index 4c7f959e7b8e..c6df1c15e0b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -28,11 +28,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -151,27 +153,155 @@ public class ScreenDecorationsTest extends SysuiTestCase { reset(mTunerService); } + + private void verifyRoundedCornerViewsVisibility( + @DisplayCutout.BoundsPosition final int overlayId, + @View.Visibility final int visibility) { + final View overlay = mScreenDecorations.mOverlays[overlayId]; + final View left = overlay.findViewById(R.id.left); + final View right = overlay.findViewById(R.id.right); + assertNotNull(left); + assertNotNull(right); + assertThat(left.getVisibility()).isEqualTo(visibility); + assertThat(right.getVisibility()).isEqualTo(visibility); + } + + private void verifyTopDotViewsNullable(final boolean isAssertNull) { + if (isAssertNull) { + assertNull(mScreenDecorations.mTopLeftDot); + assertNull(mScreenDecorations.mTopRightDot); + } else { + assertNotNull(mScreenDecorations.mTopLeftDot); + assertNotNull(mScreenDecorations.mTopRightDot); + } + } + + private void verifyBottomDotViewsNullable(final boolean isAssertNull) { + if (isAssertNull) { + assertNull(mScreenDecorations.mBottomLeftDot); + assertNull(mScreenDecorations.mBottomRightDot); + } else { + assertNotNull(mScreenDecorations.mBottomLeftDot); + assertNotNull(mScreenDecorations.mBottomRightDot); + } + } + + private void verifyDotViewsNullable(final boolean isAssertNull) { + verifyTopDotViewsNullable(isAssertNull); + verifyBottomDotViewsNullable(isAssertNull); + } + + private void verifyTopDotViewsVisibility(@View.Visibility final int visibility) { + verifyTopDotViewsNullable(false); + assertThat(mScreenDecorations.mTopLeftDot.getVisibility()).isEqualTo(visibility); + assertThat(mScreenDecorations.mTopRightDot.getVisibility()).isEqualTo(visibility); + } + + private void verifyBottomDotViewsVisibility(@View.Visibility final int visibility) { + verifyBottomDotViewsNullable(false); + assertThat(mScreenDecorations.mBottomLeftDot.getVisibility()).isEqualTo(visibility); + assertThat(mScreenDecorations.mBottomRightDot.getVisibility()).isEqualTo(visibility); + } + + private void verifyDotViewsVisibility(@View.Visibility final int visibility) { + verifyTopDotViewsVisibility(visibility); + verifyBottomDotViewsVisibility(visibility); + } + + private void verifyOverlaysExistAndAdded(final boolean left, final boolean top, + final boolean right, final boolean bottom) { + if (left || top || right || bottom) { + assertNotNull(mScreenDecorations.mOverlays); + } else { + verify(mWindowManager, never()).addView(any(), any()); + return; + } + + if (left) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); + } + + if (top) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); + } + + if (right) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + } + + if (bottom) { + assertNotNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); + verify(mWindowManager, times(1)) + .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); + } else { + assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); + } + } + @Test - public void testNoRounding_NoCutout() { + public void testNoRounding_NoCutout_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, false /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); // No views added. - verify(mWindowManager, never()).addView(any(), any()); + verifyOverlaysExistAndAdded(false, false, false, false); // No Tuners tuned. verify(mTunerService, never()).addTunable(any(), any()); + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + } + + @Test + public void testNoRounding_NoCutout_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + + // Top and bottom windows are created for privacy dot. + // Left and right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall not exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // One tunable. + verify(mTunerService, times(1)).addTunable(any(), any()); + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); } @Test - public void testRounding_NoCutout() { + public void testRounding_NoCutout_NoPrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, false /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); @@ -179,17 +309,49 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top and bottom windows are created for rounded corners. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); + // Left and right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall not exist + verifyDotViewsNullable(true); + + // One tunable. + verify(mTunerService, times(1)).addTunable(any(), any()); + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + } + + @Test + public void testRounding_NoCutout_PrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top and bottom windows are created for rounded corners. // Left and right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); // One tunable. verify(mTunerService, times(1)).addTunable(any(), any()); + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); } @Test @@ -197,7 +359,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { final Point testRadiusPoint = new Point(1, 1); setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); @@ -213,7 +375,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { final int testTopRadius = 1; final int testBottomRadius = 5; setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */, - false /* multipleRadius */, false /* fillCutout */); + false /* multipleRadius */, false /* fillCutout */, true /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); @@ -242,7 +404,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { final int testTopRadius = 1; final int testBottomRadius = 5; setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */, - false /* multipleRadius */, false /* fillCutout */); + false /* multipleRadius */, false /* fillCutout */, true /* privacyDot */); // left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -278,29 +440,67 @@ public class ScreenDecorationsTest extends SysuiTestCase { } @Test - public void testRoundingMultipleRadius_NoCutout() { + public void testRoundingMultipleRadius_NoCutout_NoPrivacyDot() { final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight()); setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 9999 /* roundedPadding */, true /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, false /* privacyDot */); // no cutout doReturn(null).when(mScreenDecorations).getCutout(); mScreenDecorations.start(); // Top and bottom windows are created for rounded corners. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); + // Left and right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall not exist + verifyDotViewsNullable(true); + // One tunable. + verify(mTunerService, times(1)).addTunable(any(), any()); + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + + // Size of corner view should exactly match max(width, height) of R.drawable.rounded + assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize); + assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize); + assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize); + } + + @Test + public void testRoundingMultipleRadius_NoCutout_PrivacyDot() { + final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); + final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight()); + setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 9999 /* roundedPadding */, true /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // no cutout + doReturn(null).when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top and bottom windows are created for rounded corners. // Left and right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); // One tunable. verify(mTunerService, times(1)).addTunable(any(), any()); + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); // Size of corner view should exactly match max(width, height) of R.drawable.rounded assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize); @@ -309,10 +509,10 @@ public class ScreenDecorationsTest extends SysuiTestCase { } @Test - public void testNoRounding_CutoutShortEdge() { + public void testNoRounding_CutoutShortEdge_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // top cutout final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -321,21 +521,53 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top window is created for top cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - // Bottom window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - // Left window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + // Bottom, left, or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, false); + + // Privacy dots shall not exist because of no privacy + verifyDotViewsNullable(true); + + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); + } + + @Test + public void testNoRounding_CutoutShortEdge_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, true /* privacyDot */); + + // top cutout + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top window is created for top cutout. + // Bottom window is created for privacy dot. + // Left or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Top rounded corner views shall exist because of cutout + // but be gone because of no rounded corner + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + // Bottom rounded corner views shall exist because of privacy dot + // but be gone because of no rounded corner + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); } @Test - public void testNoRounding_CutoutLongEdge() { + public void testNoRounding_CutoutLongEdge_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -344,21 +576,50 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Left window is created for left cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); - // Bottom window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - // Top window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); - // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + // Bottom, top, or right window should be null. + verifyOverlaysExistAndAdded(true, false, false, false); + + // Left rounded corner views shall exist because of cutout + // but be gone because of no rounded corner + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_LEFT, View.GONE); + + // Top privacy dots shall not exist because of no privacy + verifyDotViewsNullable(true); + + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); } @Test - public void testRounding_CutoutShortEdge() { + public void testNoRounding_CutoutLongEdge_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, true /* privacyDot */); + + // left cutout + final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Left window is created for left cutout. + // Right window is created for privacy. + // Bottom, or top window should be null. + verifyOverlaysExistAndAdded(true, false, true, false); + + // Privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); + } + + @Test + public void testRounding_CutoutShortEdge_NoPrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // top cutout final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -367,22 +628,55 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top window is created for rounded corner and top cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); // Bottom window is created for rounded corner. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); - // Left window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + // Left, or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Top privacy dots shall not exist because of no privacy dot + verifyDotViewsNullable(true); + + // No dot controller init + verify(mDotViewController, never()).initialize(any(), any(), any(), any()); } @Test - public void testRounding_CutoutLongEdge() { + public void testRounding_CutoutShortEdge_PrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, true /* privacyDot */); + + // top cutout + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top window is created for rounded corner and top cutout. + // Bottom window is created for rounded corner. + // Left, or right window should be null. + verifyOverlaysExistAndAdded(false, true, false, true); + + // Rounded corner views shall exist + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.VISIBLE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.VISIBLE); + + // Top privacy dots shall exist but invisible + verifyDotViewsVisibility(View.INVISIBLE); + + // Dot controller init + verify(mDotViewController, times(1)).initialize( + isA(View.class), isA(View.class), isA(View.class), isA(View.class)); + } + + @Test + public void testRounding_CutoutLongEdge_NoPrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, false /* privacyDot */); // left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -391,22 +685,53 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Left window is created for rounded corner and left cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); // Right window is created for rounded corner. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]), any()); - // Top window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); - // Bottom window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); + // Top, or bottom window should be null. + verifyOverlaysExistAndAdded(true, false, true, false); + } + + @Test + public void testRounding_CutoutLongEdge_PrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, true /* privacyDot */); + + // left cutout + final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Left window is created for rounded corner, left cutout, and privacy. + // Right window is created for rounded corner and privacy dot. + // Top, or bottom window should be null. + verifyOverlaysExistAndAdded(true, false, true, false); + } + + @Test + public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() { + setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 20 /* roundedPadding */, false /* multipleRadius */, + true /* fillCutout */, false /* privacyDot */); + + // top and left cutout + final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Top window is created for rounded corner and top cutout. + // Bottom window is created for rounded corner. + // Left window is created for left cutout. + // Right window should be null. + verifyOverlaysExistAndAdded(true, true, false, true); } @Test - public void testRounding_CutoutShortAndLongEdge() { + public void testRounding_CutoutShortAndLongEdge_PrivacyDot() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 20 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, true /* privacyDot */); // top and left cutout final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null}; @@ -415,23 +740,17 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.start(); // Top window is created for rounded corner and top cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); // Bottom window is created for rounded corner. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any()); // Left window is created for left cutout. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); // Right window should be null. - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(true, true, false, true); } @Test - public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout() { + public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - true /* fillCutout */); + true /* fillCutout */, false /* privacyDot */); // Set to short edge cutout(top). final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -439,11 +758,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { .when(mScreenDecorations).getCutout(); mScreenDecorations.start(); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); + verifyOverlaysExistAndAdded(false, true, false, false); // Switch to long edge cutout(left). final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null}; @@ -451,18 +766,37 @@ public class ScreenDecorationsTest extends SysuiTestCase { .when(mScreenDecorations).getCutout(); mScreenDecorations.onConfigurationChanged(new Configuration()); - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any()); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]); + verifyOverlaysExistAndAdded(true, false, false, false); } @Test - public void testDelayedCutout() { + public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() { setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + true /* fillCutout */, true /* privacyDot */); + + // Set to short edge cutout(top). + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + verifyOverlaysExistAndAdded(false, true, false, true); + + // Switch to long edge cutout(left). + final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.onConfigurationChanged(new Configuration()); + verifyOverlaysExistAndAdded(true, false, true, false); + } + + @Test + public void testDelayedCutout_NoPrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, false /* privacyDot */); // top cutout final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; @@ -478,11 +812,38 @@ public class ScreenDecorationsTest extends SysuiTestCase { mScreenDecorations.onConfigurationChanged(new Configuration()); // Only top windows should be added. - verify(mWindowManager, times(1)) - .addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any()); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]); - assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]); + verifyOverlaysExistAndAdded(false, true, false, false); + } + + @Test + public void testDelayedCutout_PrivacyDot() { + setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, + 0 /* roundedPadding */, false /* multipleRadius */, + false /* fillCutout */, true /* privacyDot */); + + // top cutout + final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null}; + doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds)) + .when(mScreenDecorations).getCutout(); + + mScreenDecorations.start(); + // Both top and bottom windows should be added because of privacy dot, + // but their visibility shall be gone because of no rounding. + verifyOverlaysExistAndAdded(false, true, false, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); + + when(mContext.getResources().getBoolean( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout)) + .thenReturn(true); + mScreenDecorations.onConfigurationChanged(new Configuration()); + + assertNotNull(mScreenDecorations.mOverlays); + // Both top and bottom windows should be added because of privacy dot, + // but their visibility shall be gone because of no rounding. + verifyOverlaysExistAndAdded(false, true, false, true); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_TOP, View.GONE); + verifyRoundedCornerViewsVisibility(BOUNDS_POSITION_BOTTOM, View.GONE); } @Test @@ -496,7 +857,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testUpdateRoundedCorners() { setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); mScreenDecorations.start(); assertEquals(mScreenDecorations.mRoundedDefault, new Point(20, 20)); @@ -511,7 +872,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnlyRoundedCornerRadiusTop() { setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); mScreenDecorations.start(); assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault); @@ -523,7 +884,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { public void testOnlyRoundedCornerRadiusBottom() { setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */, 0 /* roundedPadding */, false /* multipleRadius */, - false /* fillCutout */); + false /* fillCutout */, true /* privacyDot */); mScreenDecorations.start(); assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault); @@ -531,7 +892,6 @@ public class ScreenDecorationsTest extends SysuiTestCase { assertEquals(new Point(20, 20), mScreenDecorations.mRoundedDefaultBottom); } - @Test public void testBoundingRectsToRegion() throws Exception { Rect rect = new Rect(1, 2, 3, 4); @@ -588,7 +948,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { } private void setupResources(int radius, int radiusTop, int radiusBottom, int roundedPadding, - boolean multipleRadius, boolean fillCutout) { + boolean multipleRadius, boolean fillCutout, boolean privacyDot) { mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.array.config_displayUniqueIdArray, new String[]{}); @@ -625,6 +985,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { R.bool.config_roundedCornerMultipleRadius, multipleRadius); mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout); + mContext.getOrCreateTestableResources().addOverride( + R.bool.config_enablePrivacyDot, privacyDot); } private DisplayCutout getDisplayCutoutForRotation(Insets safeInsets, Rect[] cutoutBounds) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt index cc35a8f9e1b5..d819fa2adc38 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt @@ -46,6 +46,7 @@ import org.mockito.junit.MockitoJUnit @RunWithLooper class ActivityLaunchAnimatorTest : SysuiTestCase() { private val launchContainer = LinearLayout(mContext) + private val launchAnimator = LaunchAnimator(mContext, isForTesting = true) @Mock lateinit var callback: ActivityLaunchAnimator.Callback @Spy private val controller = TestLaunchAnimatorController(launchContainer) @Mock lateinit var iCallback: IRemoteAnimationFinishedCallback @@ -56,7 +57,8 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { @Before fun setup() { - activityLaunchAnimator = ActivityLaunchAnimator(callback, mContext) + activityLaunchAnimator = ActivityLaunchAnimator(launchAnimator) + activityLaunchAnimator.callback = callback } private fun startIntentWithAnimation( @@ -120,7 +122,8 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { @Test fun animatesIfActivityIsAlreadyOpenAndIsOnKeyguard() { `when`(callback.isOnKeyguard()).thenReturn(true) - val animator = ActivityLaunchAnimator(callback, context) + val animator = ActivityLaunchAnimator(launchAnimator) + animator.callback = callback val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java) var animationAdapter: RemoteAnimationAdapter? = null @@ -208,7 +211,7 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() { private class TestLaunchAnimatorController( override var launchContainer: ViewGroup ) : ActivityLaunchAnimator.Controller { - override fun createAnimatorState() = ActivityLaunchAnimator.State( + override fun createAnimatorState() = LaunchAnimator.State( top = 100, bottom = 200, left = 300, @@ -232,7 +235,7 @@ private class TestLaunchAnimatorController( } override fun onLaunchAnimationProgress( - state: ActivityLaunchAnimator.State, + state: LaunchAnimator.State, progress: Float, linearProgress: Float ) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt new file mode 100644 index 000000000000..5bcf828afe9f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt @@ -0,0 +1,186 @@ +package com.android.systemui.animation + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.testing.ViewUtils +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.LinearLayout +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import junit.framework.Assert.assertEquals +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class DialogLaunchAnimatorTest : SysuiTestCase() { + private val launchAnimator = LaunchAnimator(context, isForTesting = true) + private val hostDialogprovider = TestHostDialogProvider() + private val dialogLaunchAnimator = + DialogLaunchAnimator(context, launchAnimator, hostDialogprovider) + + @Test + fun testShowDialogFromView() { + // Show the dialog. showFromView() must be called on the main thread with a dialog created + // on the main thread too. + val (dialog, hostDialog) = runOnMainThreadAndWaitForIdleSync { + val touchSurfaceRoot = LinearLayout(context) + val touchSurface = View(context) + touchSurfaceRoot.addView(touchSurface) + + // We need to attach the root to the window manager otherwise the exit animation will + // be skipped + ViewUtils.attachView(touchSurfaceRoot) + + val dialog = TestDialog(context) + val hostDialog = + dialogLaunchAnimator.showFromView(dialog, touchSurface) as TestHostDialog + dialog to hostDialog + } + + // Only the host dialog is actually showing. + assertTrue(hostDialog.isShowing) + assertFalse(dialog.isShowing) + + // The dialog onStart() method was called but not onStop(). + assertTrue(dialog.onStartCalled) + assertFalse(dialog.onStopCalled) + + // The dialog content has been stolen and is shown inside the host dialog. + val hostDialogContent = hostDialog.findViewById<ViewGroup>(android.R.id.content) + assertEquals(0, dialog.findViewById<ViewGroup>(android.R.id.content).childCount) + assertEquals(1, hostDialogContent.childCount) + + val hostDialogRoot = hostDialogContent.getChildAt(0) as ViewGroup + assertEquals(1, hostDialogRoot.childCount) + assertEquals(dialog.contentView, hostDialogRoot.getChildAt(0)) + + // If we are dozing, the host dialog window also fades out. + runOnMainThreadAndWaitForIdleSync { dialogLaunchAnimator.onDozeAmountChanged(0.5f) } + assertTrue(hostDialog.window!!.decorView.alpha < 1f) + + // Hiding/showing/dismissing the dialog should hide/show/dismiss the host dialog given that + // it's a ListenableDialog. + runOnMainThreadAndWaitForIdleSync { dialog.hide() } + assertFalse(hostDialog.isShowing) + assertFalse(dialog.isShowing) + + runOnMainThreadAndWaitForIdleSync { dialog.show() } + assertTrue(hostDialog.isShowing) + assertFalse(dialog.isShowing) + + assertFalse(dialog.onStopCalled) + runOnMainThreadAndWaitForIdleSync { dialog.dismiss() } + assertFalse(hostDialog.isShowing) + assertFalse(dialog.isShowing) + assertTrue(hostDialog.wasDismissed) + assertTrue(dialog.onStopCalled) + } + + private fun <T : Any> runOnMainThreadAndWaitForIdleSync(f: () -> T): T { + lateinit var result: T + context.mainExecutor.execute { + result = f() + } + waitForIdleSync() + return result + } + + private class TestHostDialogProvider : HostDialogProvider { + override fun createHostDialog( + context: Context, + theme: Int, + onCreateCallback: () -> Unit, + dismissOverride: (() -> Unit) -> Unit + ): Dialog = TestHostDialog(context, onCreateCallback, dismissOverride) + } + + private class TestHostDialog( + context: Context, + private val onCreateCallback: () -> Unit, + private val dismissOverride: (() -> Unit) -> Unit + ) : Dialog(context) { + var wasDismissed = false + + init { + // We need to set the window type for dialogs shown by SysUI, otherwise WM will throw. + window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + onCreateCallback() + } + + override fun dismiss() { + dismissOverride { + super.dismiss() + wasDismissed = true + } + } + } + + private class TestDialog(context: Context) : Dialog(context), ListenableDialog { + private val listeners = hashSetOf<DialogListener>() + val contentView = View(context) + var onStartCalled = false + var onStopCalled = false + + init { + // We need to set the window type for dialogs shown by SysUI, otherwise WM will throw. + window.setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(contentView) + } + + override fun onStart() { + super.onStart() + onStartCalled = true + } + + override fun onStop() { + super.onStart() + onStopCalled = true + } + + override fun addListener(listener: DialogListener) { + listeners.add(listener) + } + + override fun removeListener(listener: DialogListener) { + listeners.remove(listener) + } + + override fun dismiss() { + super.dismiss() + notifyListeners { onDismiss() } + } + + override fun hide() { + super.hide() + notifyListeners { onHide() } + } + + override fun show() { + super.show() + notifyListeners { onShow() } + } + + private fun notifyListeners(notify: DialogListener.() -> Unit) { + for (listener in HashSet(listeners)) { + listener.notify() + } + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt index 8cba25dc1b92..58e0cb259bb2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt @@ -32,7 +32,7 @@ class GhostedViewLaunchAnimatorControllerTest : SysuiTestCase() { fun animatingOrphanViewDoesNotCrash() { val ghostedView = LinearLayout(mContext) val controller = GhostedViewLaunchAnimatorController(ghostedView) - val state = ActivityLaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0) + val state = LaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0) controller.onIntentStarted(willAnimate = true) controller.onLaunchAnimationStart(isExpandingFullyAbove = true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt index f2f0029708ed..2c4808a4b84f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -21,11 +21,12 @@ import android.hardware.biometrics.BiometricSourceType import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase -import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.CommandRegistry @@ -34,6 +35,8 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.StatusBar import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.util.leak.RotationUtils +import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before @@ -48,12 +51,15 @@ import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations - +import org.mockito.MockitoSession +import org.mockito.quality.Strictness import javax.inject.Provider @SmallTest @RunWith(AndroidTestingRunner::class) class AuthRippleControllerTest : SysuiTestCase() { + private lateinit var staticMockSession: MockitoSession + private lateinit var controller: AuthRippleController @Mock private lateinit var statusBar: StatusBar @Mock private lateinit var rippleView: AuthRippleView @@ -74,6 +80,12 @@ class AuthRippleControllerTest : SysuiTestCase() { @Before fun setUp() { MockitoAnnotations.initMocks(this) + staticMockSession = mockitoSession() + .mockStatic(RotationUtils::class.java) + .strictness(Strictness.LENIENT) + .startMocking() + + `when`(RotationUtils.getRotation(context)).thenReturn(RotationUtils.ROTATION_NONE) `when`(udfpsControllerProvider.get()).thenReturn(udfpsController) controller = AuthRippleController( @@ -96,6 +108,11 @@ class AuthRippleControllerTest : SysuiTestCase() { `when`(statusBar.lightRevealScrim).thenReturn(lightRevealScrim) } + @After + fun tearDown() { + staticMockSession.finishMocking() + } + @Test fun testFingerprintTrigger_Ripple() { // GIVEN fp exists, keyguard is visible, user doesn't need strong auth diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index d6226aa53f67..866791cc24cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -40,7 +40,7 @@ public class DozeConfigurationUtil { when(params.doubleTapReportsTouchCoordinates()).thenReturn(false); when(params.getDisplayNeedsBlanking()).thenReturn(false); when(params.getSelectivelyRegisterSensorsUsingProx()).thenReturn(false); - when(params.singleTapUsesProx()).thenReturn(true); + when(params.singleTapUsesProx(anyInt())).thenReturn(true); when(params.longPressUsesProx()).thenReturn(true); when(params.getQuickPickupAodDuration()).thenReturn(500); @@ -61,14 +61,13 @@ public class DozeConfigurationUtil { when(config.getWakeLockScreenDebounce()).thenReturn(0L); when(config.doubleTapSensorType()).thenReturn(null); - when(config.tapSensorType()).thenReturn(null); when(config.longPressSensorType()).thenReturn(null); when(config.udfpsLongPressSensorType()).thenReturn(null); when(config.quickPickupSensorType()).thenReturn(null); when(config.tapGestureEnabled(anyInt())).thenReturn(true); when(config.tapSensorAvailable()).thenReturn(true); - when(config.tapSensorType()).thenReturn(FakeSensorManager.TAP_SENSOR_TYPE); + when(config.tapSensorType(anyInt())).thenReturn(FakeSensorManager.TAP_SENSOR_TYPE); when(config.dozePickupSensorAvailable()).thenReturn(false); when(config.wakeScreenGestureAvailable()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index 5c4c27ccc4ca..42e34c81a790 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -19,6 +19,7 @@ package com.android.systemui.doze; import static com.android.systemui.doze.DozeLog.REASON_SENSOR_TAP; import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -47,6 +48,7 @@ import com.android.systemui.biometrics.AuthController; import com.android.systemui.doze.DozeSensors.TriggerSensor; import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.settings.FakeSettings; @@ -58,6 +60,11 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; @RunWith(AndroidTestingRunner.class) @@ -85,6 +92,8 @@ public class DozeSensorsTest extends SysuiTestCase { private AuthController mAuthController; @Mock private ProximitySensor mProximitySensor; + private @DevicePostureController.DevicePostureInt int mDevicePosture = + DevicePostureController.DEVICE_POSTURE_UNKNOWN; private FakeSettings mFakeSettings = new FakeSettings(); private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener; private TestableLooper mTestableLooper; @@ -101,6 +110,7 @@ public class DozeSensorsTest extends SysuiTestCase { ((Runnable) invocation.getArgument(0)).run(); return null; }).when(mWakeLock).wrap(any(Runnable.class)); + mDevicePosture = DevicePostureController.DEVICE_POSTURE_UNKNOWN; mDozeSensors = new TestableDozeSensors(); } @@ -157,7 +167,7 @@ public class DozeSensorsTest extends SysuiTestCase { // GIVEN we only should register sensors using prox when not in low-powered mode / off // and the single tap sensor uses the proximity sensor when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true); - when(mDozeParameters.singleTapUsesProx()).thenReturn(true); + when(mDozeParameters.singleTapUsesProx(anyInt())).thenReturn(true); TestableDozeSensors dozeSensors = new TestableDozeSensors(); // THEN on initialization, the tap sensor isn't requested @@ -258,12 +268,55 @@ public class DozeSensorsTest extends SysuiTestCase { assertTrue(triggerSensor.mRegistered); } + @Test + public void testPostureOpen_registersCorrectTapGesture() { + // GIVEN device posture open + mDevicePosture = DevicePostureController.DEVICE_POSTURE_OPENED; + + // WHEN DozeSensors are initialized + new TestableDozeSensors(); + + // THEN we use the posture to determine which tap sensor to use + verify(mAmbientDisplayConfiguration).tapSensorType(eq(mDevicePosture)); + } + + @Test + public void testFindSensor() throws Exception { + // GIVEN a prox sensor + List<Sensor> sensors = new ArrayList<>(); + Sensor proxSensor = + createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY); + sensors.add(proxSensor); + + when(mSensorManager.getSensorList(anyInt())).thenReturn(sensors); + + // WHEN we try to find the prox sensor with the same type and name + // THEN we find the added sensor + assertEquals( + proxSensor, + DozeSensors.findSensor( + mSensorManager, + Sensor.STRING_TYPE_PROXIMITY, + proxSensor.getName())); + + // WHEN we try to find a prox sensor with a different name + // THEN no sensor is found + assertEquals( + null, + DozeSensors.findSensor( + mSensorManager, + Sensor.STRING_TYPE_PROXIMITY, + "some other name")); + } + + private class TestableDozeSensors extends DozeSensors { TestableDozeSensors() { super(getContext(), mSensorManager, mDozeParameters, mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog, - mProximitySensor, mFakeSettings, mAuthController); + mProximitySensor, mFakeSettings, mAuthController, + mDevicePosture); for (TriggerSensor sensor : mSensors) { if (sensor instanceof PluginSensor && ((PluginSensor) sensor).mPluginSensor.getType() @@ -288,4 +341,23 @@ public class DozeSensorsTest extends SysuiTestCase { mDozeLog); } } + + public static void setSensorType(Sensor sensor, int type, String strType) throws Exception { + Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE); + setter.setAccessible(true); + setter.invoke(sensor, type); + if (strType != null) { + Field f = sensor.getClass().getDeclaredField("mStringType"); + f.setAccessible(true); + f.set(sensor, strType); + } + } + + public static Sensor createSensor(int type, String strType) throws Exception { + Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor(); + constr.setAccessible(true); + Sensor sensor = constr.newInstance(); + setSensorType(sensor, type, strType); + return sensor; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 9577c7a2d6fa..b688fcc50373 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -45,6 +45,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dock.DockManager; import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; @@ -86,6 +87,8 @@ public class DozeTriggersTest extends SysuiTestCase { private UiEventLogger mUiEventLogger; @Mock private KeyguardStateController mKeyguardStateController; + @Mock + private DevicePostureController mDevicePostureController; private DozeTriggers mTriggers; private FakeSensorManager mSensors; @@ -117,7 +120,8 @@ public class DozeTriggersTest extends SysuiTestCase { mTriggers = new DozeTriggers(mContext, mHost, config, dozeParameters, asyncSensorManager, wakeLock, mDockManager, mProximitySensor, mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(), - mAuthController, mExecutor, mUiEventLogger, mKeyguardStateController); + mAuthController, mExecutor, mUiEventLogger, mKeyguardStateController, + mDevicePostureController); mTriggers.setDozeMachine(mMachine); waitForSensorManager(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index 47c5545ab587..d864aaeadee3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -405,6 +405,26 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test + fun testOnSmartspaceMediaDataLoaded_hasNullIntent_callsListener() { + val recommendationExtras = Bundle().apply { + putString("package_name", PACKAGE_NAME) + putParcelable("dismiss_intent", null) + } + whenever(mediaSmartspaceBaseAction.extras).thenReturn(recommendationExtras) + whenever(mediaSmartspaceTarget.baseAction).thenReturn(mediaSmartspaceBaseAction) + whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf()) + + smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget)) + + verify(listener).onSmartspaceMediaDataLoaded( + eq(KEY_MEDIA_SMARTSPACE), + eq(EMPTY_SMARTSPACE_MEDIA_DATA + .copy(targetId = KEY_MEDIA_SMARTSPACE, isActive = true, + isValid = false, dismissIntent = null)), + eq(false)) + } + + @Test fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_notCallsListener() { smartspaceMediaDataProvider.onTargetsAvailable(listOf()) verify(listener, never()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java index 2c686618a361..25ca8c95500b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java @@ -54,6 +54,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { // Mock private MediaOutputController mMediaOutputController = mock(MediaOutputController.class); + private MediaOutputDialog mMediaOutputDialog = mock(MediaOutputDialog.class); private MediaDevice mMediaDevice1 = mock(MediaDevice.class); private MediaDevice mMediaDevice2 = mock(MediaDevice.class); private Icon mIcon = mock(Icon.class); @@ -65,7 +66,7 @@ public class MediaOutputAdapterTest extends SysuiTestCase { @Before public void setUp() { - mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController); + mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController, mMediaOutputDialog); mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter .onCreateViewHolder(new LinearLayout(mContext), 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java index 9bd07b88417d..053851ec385d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java @@ -39,6 +39,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.phone.ShadeController; @@ -63,6 +64,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { private NotificationEntryManager mNotificationEntryManager = mock(NotificationEntryManager.class); private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class); + private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl; private MediaOutputController mMediaOutputController; @@ -75,7 +77,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase { public void setUp() { mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter, - mNotificationEntryManager, mUiEventLogger); + mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator); mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mMediaOutputController); mMediaOutputBaseDialogImpl.onCreate(new Bundle()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java index d1a617bcc0cb..f7e60caa2624 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java @@ -49,6 +49,7 @@ import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -91,6 +92,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { private NotificationEntryManager mNotificationEntryManager = mock(NotificationEntryManager.class); private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class); + private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); private Context mSpyContext; private MediaOutputController mMediaOutputController; @@ -113,7 +115,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter, - mNotificationEntryManager, mUiEventLogger); + mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator); mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager); mMediaOutputController.mLocalMediaManager = mLocalMediaManager; MediaDescription.Builder builder = new MediaDescription.Builder(); @@ -157,7 +159,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { public void start_withoutPackageName_verifyMediaControllerInit() { mMediaOutputController = new MediaOutputController(mSpyContext, null, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter, - mNotificationEntryManager, mUiEventLogger); + mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator); mMediaOutputController.start(mCb); @@ -178,7 +180,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { public void stop_withoutPackageName_verifyMediaControllerDeinit() { mMediaOutputController = new MediaOutputController(mSpyContext, null, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter, - mNotificationEntryManager, mUiEventLogger); + mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator); mMediaOutputController.start(mCb); @@ -449,7 +451,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { public void getNotificationLargeIcon_withoutPackageName_returnsNull() { mMediaOutputController = new MediaOutputController(mSpyContext, null, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter, - mNotificationEntryManager, mUiEventLogger); + mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator); assertThat(mMediaOutputController.getNotificationIcon()).isNull(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java index 86f6bdec43f0..8a3ea562269d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java @@ -36,6 +36,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.phone.ShadeController; @@ -65,6 +66,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { private final NotificationEntryManager mNotificationEntryManager = mock(NotificationEntryManager.class); private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class); + private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); private MediaOutputDialog mMediaOutputDialog; private MediaOutputController mMediaOutputController; @@ -74,10 +76,11 @@ public class MediaOutputDialogTest extends SysuiTestCase { public void setUp() { mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter, - mNotificationEntryManager, mUiEventLogger); + mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator); mMediaOutputController.mLocalMediaManager = mLocalMediaManager; mMediaOutputDialog = new MediaOutputDialog(mContext, false, mMediaOutputController, mUiEventLogger); + mMediaOutputDialog.show(); when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice); when(mMediaDevice.getFeatures()).thenReturn(mFeatures); @@ -123,6 +126,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { public void onCreate_ShouldLogVisibility() { MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false, mMediaOutputController, mUiEventLogger); + testDialog.show(); testDialog.dismissDialog(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java index c296ff5cf19a..e8cd6c88956d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java @@ -34,6 +34,7 @@ import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.phone.ShadeController; @@ -64,6 +65,7 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase { private NotificationEntryManager mNotificationEntryManager = mock(NotificationEntryManager.class); private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class); + private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class); private MediaOutputGroupDialog mMediaOutputGroupDialog; private MediaOutputController mMediaOutputController; @@ -73,10 +75,11 @@ public class MediaOutputGroupDialogTest extends SysuiTestCase { public void setUp() { mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false, mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter, - mNotificationEntryManager, mUiEventLogger); + mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator); mMediaOutputController.mLocalMediaManager = mLocalMediaManager; mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false, mMediaOutputController); + mMediaOutputGroupDialog.show(); when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt index fd932803ff37..ee9c2b82c283 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt @@ -199,8 +199,9 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(false) `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(false) - // WHEN a connection attempt is made - controller.buildAndConnectView(fakeParent) + // WHEN a connection attempt is made and view is attached + val view = controller.buildAndConnectView(fakeParent) + controller.stateChangeListener.onViewAttachedToWindow(view) // THEN no session is created verify(smartspaceManager, never()).createSmartspaceSession(any()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 1f3e1c7a6b86..902d11575597 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; @@ -81,6 +82,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationRankin import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -94,6 +96,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -120,6 +123,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private KeyguardEnvironment mEnvironment; @Mock private ExpandableNotificationRow mRow; @Mock private NotificationEntryListener mEntryListener; + @Mock private NotifCollectionListener mNotifCollectionListener; @Mock private NotificationRemoveInterceptor mRemoveInterceptor; @Mock private HeadsUpManager mHeadsUpManager; @Mock private RankingMap mRankingMap; @@ -215,6 +219,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mEnvironment)); mEntryManager.setUpWithPresenter(mPresenter); mEntryManager.addNotificationEntryListener(mEntryListener); + mEntryManager.addCollectionListener(mNotifCollectionListener); mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor); setUserSentiment(mSbn.getKey(), Ranking.USER_SENTIMENT_NEUTRAL); @@ -318,13 +323,20 @@ public class NotificationEntryManagerTest extends SysuiTestCase { eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON)); } + /** Regression test for b/201097913. */ @Test - public void testRemoveNotification_whilePending() { + public void testRemoveNotification_whilePending_onlyCollectionListenerNotified() { + // Add and then remove a pending entry (entry that hasn't been inflated). mEntryManager.addNotification(mSbn, mRankingMap); mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON); + // Verify that only the listener for the NEW pipeline is notified. + // Old pipeline: verify(mEntryListener, never()).onEntryRemoved( - eq(mEntry), any(), eq(false /* removedByUser */), eq(UNDEFINED_DISMISS_REASON)); + argThat(matchEntryOnSbn()), any(), anyBoolean(), anyInt()); + // New pipeline: + verify(mNotifCollectionListener).onEntryRemoved( + argThat(matchEntryOnSbn()), anyInt()); } @Test @@ -639,6 +651,11 @@ public class NotificationEntryManagerTest extends SysuiTestCase { PendingIntent.FLAG_IMMUTABLE)).build(); } + // TODO(b/201321631): Update more tests to use this function instead of eq(mEntry). + private ArgumentMatcher<NotificationEntry> matchEntryOnSbn() { + return e -> e.getSbn().equals(mSbn); + } + private static class FakeNotificationLifetimeExtender implements NotificationLifetimeExtender { private NotificationSafeToRemoveCallback mCallback; private boolean mExtendLifetimes = true; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index 33928ea78368..f7423bb7951d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -156,8 +156,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { private KeyguardBottomAreaView mQsFrame; private KeyguardStatusView mKeyguardStatusView; @Mock - private ViewGroup mBigClockContainer; - @Mock private NotificationIconAreaController mNotificationAreaController; @Mock private HeadsUpManagerPhone mHeadsUpManager; @@ -347,7 +345,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { when(mKeyguardBottomArea.getLeftView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class)); - when(mView.findViewById(R.id.big_clock_container)).thenReturn(mBigClockContainer); when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame); when(mView.findViewById(R.id.keyguard_status_view)) .thenReturn(mock(KeyguardStatusView.class)); @@ -778,6 +775,18 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { } @Test + public void testSwitchesToBigClockInSplitShadeOnAod() { + mStatusBarStateController.setState(KEYGUARD); + enableSplitShade(/* enabled= */ true); + when(mMediaDataManager.hasActiveMedia()).thenReturn(true); + when(mNotificationStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(2); + + mNotificationPanelViewController.setDozing(true, false, null); + + verify(mKeyguardStatusViewController).displayClock(LARGE); + } + + @Test public void testDisplaysSmallClockOnLockscreenInSplitShadeWhenMediaIsPlaying() { mStatusBarStateController.setState(KEYGUARD); enableSplitShade(/* enabled= */ true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 5115614f8bfb..6e3d5ce7953e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -308,18 +308,4 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mBouncer).updateKeyguardPosition(1.0f); } - - @Test - public void testNavBarHiddenWhenSleepAnimationStarts() { - mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */); - assertTrue(mStatusBarKeyguardViewManager.isNavBarVisible()); - - // Verify that the nav bar is hidden when the screen off animation starts - doReturn(true).when(mUnlockedScreenOffAnimationController).isScreenOffAnimationPlaying(); - mWakefulnessLifecycle.dispatchFinishedGoingToSleep(); - assertFalse(mStatusBarKeyguardViewManager.isNavBarVisible()); - - mWakefulnessLifecycle.dispatchFinishedWakingUp(); - assertTrue(mStatusBarKeyguardViewManager.isNavBarVisible()); - } } 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 88a3827d0582..fdda76df64d7 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 @@ -77,6 +77,8 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.InitController; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingCollectorFake; @@ -274,6 +276,8 @@ public class StatusBarTest extends SysuiTestCase { @Mock private StartingSurface mStartingSurface; @Mock private OperatorNameViewController mOperatorNameViewController; @Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory; + @Mock private ActivityLaunchAnimator mActivityLaunchAnimator; + @Mock private DialogLaunchAnimator mDialogLaunchAnimator; private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); @@ -452,7 +456,9 @@ public class StatusBarTest extends SysuiTestCase { mUnlockedScreenOffAnimationController, Optional.of(mStartingSurface), mTunerService, - mock(DumpManager.class)); + mock(DumpManager.class), + mActivityLaunchAnimator, + mDialogLaunchAnimator); when(mKeyguardViewMediator.registerStatusBar(any(StatusBar.class), any(ViewGroup.class), any(NotificationPanelViewController.class), any(BiometricUnlockController.class), any(ViewGroup.class), any(KeyguardBypassController.class))) @@ -794,6 +800,34 @@ public class StatusBarTest extends SysuiTestCase { } @Test + public void testSetExpansionAffectsAlpha_onlyWhenHidingKeyguard() { + mStatusBar.updateScrimController(); + verify(mScrimController).setExpansionAffectsAlpha(eq(true)); + + clearInvocations(mScrimController); + when(mBiometricUnlockController.isBiometricUnlock()).thenReturn(true); + mStatusBar.updateScrimController(); + verify(mScrimController).setExpansionAffectsAlpha(eq(true)); + + clearInvocations(mScrimController); + when(mKeyguardStateController.isShowing()).thenReturn(true); + mStatusBar.updateScrimController(); + verify(mScrimController).setExpansionAffectsAlpha(eq(false)); + + clearInvocations(mScrimController); + reset(mKeyguardStateController); + when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true); + mStatusBar.updateScrimController(); + verify(mScrimController).setExpansionAffectsAlpha(eq(false)); + + clearInvocations(mScrimController); + reset(mKeyguardStateController); + when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true); + mStatusBar.updateScrimController(); + verify(mScrimController).setExpansionAffectsAlpha(eq(false)); + } + + @Test public void testTransitionLaunch_noPreview_doesntGoUnlocked() { mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD); mStatusBar.showKeyguardImpl(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt index efe2c1774b08..fe7ec68f77b8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt @@ -33,6 +33,7 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.ActivityStarter import com.android.systemui.flags.FeatureFlags import com.android.systemui.statusbar.notification.collection.NotificationEntry @@ -105,7 +106,9 @@ class OngoingCallControllerTest : SysuiTestCase() { mockActivityStarter, mainExecutor, mockIActivityManager, - OngoingCallLogger(uiEventLoggerFake)) + OngoingCallLogger(uiEventLoggerFake), + DumpManager(), + ) controller.init() controller.addCallback(mockOngoingCallListener) controller.setChipView(chipView) @@ -221,18 +224,6 @@ class OngoingCallControllerTest : SysuiTestCase() { verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean()) } - /** Regression test for b/201097913. */ - @Test - fun onEntryCleanUp_callNotifAddedThenRemoved_listenerNotified() { - val ongoingCallNotifEntry = createOngoingCallNotifEntry() - notifCollectionListener.onEntryAdded(ongoingCallNotifEntry) - reset(mockOngoingCallListener) - - notifCollectionListener.onEntryCleanUp(ongoingCallNotifEntry) - - verify(mockOngoingCallListener).onOngoingCallStateChanged(anyBoolean()) - } - /** Regression test for b/188491504. */ @Test fun onEntryRemoved_removedNotifHasSameKeyAsAddedNotif_listenerNotified() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt index dba83e1eeeb9..dd43ea56609b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.policy +import android.app.IActivityManager import android.app.IActivityTaskManager import android.app.admin.DevicePolicyManager import android.content.Context @@ -31,6 +32,7 @@ import android.os.UserManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest +import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.util.UserIcons import com.android.systemui.GuestResumeSessionReceiver @@ -54,10 +56,11 @@ import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Mock +import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.anyString import org.mockito.Mockito.mock -import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -65,6 +68,7 @@ import org.mockito.MockitoAnnotations @SmallTest class UserSwitcherControllerTest : SysuiTestCase() { @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock private lateinit var activityManager: IActivityManager @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var devicePolicyManager: DevicePolicyManager @Mock private lateinit var handler: Handler @@ -78,6 +82,7 @@ class UserSwitcherControllerTest : SysuiTestCase() { @Mock private lateinit var secureSettings: SecureSettings @Mock private lateinit var falsingManager: FalsingManager @Mock private lateinit var dumpManager: DumpManager + @Mock private lateinit var interactionJankMonitor: InteractionJankMonitor private lateinit var testableLooper: TestableLooper private lateinit var uiBgExecutor: FakeExecutor private lateinit var uiEventLogger: UiEventLoggerFake @@ -110,6 +115,7 @@ class UserSwitcherControllerTest : SysuiTestCase() { userSwitcherController = UserSwitcherController( context, + activityManager, userManager, userTracker, keyguardStateController, @@ -125,6 +131,7 @@ class UserSwitcherControllerTest : SysuiTestCase() { userDetailAdapter, secureSettings, uiBgExecutor, + interactionJankMonitor, dumpManager) userSwitcherController.mPauseRefreshUsers = true @@ -132,7 +139,7 @@ class UserSwitcherControllerTest : SysuiTestCase() { } @Test - fun testAddGuest_okButtonPressed_isLogged() { + fun testAddGuest_okButtonPressed() { val emptyGuestUserRecord = UserSwitcherController.UserRecord( null, null, @@ -148,6 +155,8 @@ class UserSwitcherControllerTest : SysuiTestCase() { userSwitcherController.onUserListItemClicked(emptyGuestUserRecord) testableLooper.processAllMessages() + verify(interactionJankMonitor).begin(any()) + verify(activityManager).switchUser(guestInfo.id) assertEquals(1, uiEventLogger.numLogs()) assertEquals(QSUserSwitcherEvent.QS_USER_GUEST_ADD.id, uiEventLogger.eventId(0)) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt index de86821c0535..b54aadb8228f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt @@ -138,7 +138,7 @@ class WallpaperControllerTest : SysuiTestCase() { private fun createWallpaperInfo(useDefaultTransition: Boolean = true): WallpaperInfo { val info = mock(WallpaperInfo::class.java) - whenever(info.shouldUseDefaultDeviceStateChangeTransition()) + whenever(info.shouldUseDefaultDisplayStateChangeTransition()) .thenReturn(useDefaultTransition) return info } diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 904def0af2cf..6bd1fa6c335d 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -190,6 +190,9 @@ final class ContentCapturePerUserService Slog.w(TAG, "remote service died: " + service); synchronized (mLock) { mZombie = true; + writeServiceEvent( + FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_REMOTE_SERVICE_DIED, + getServiceComponentName()); } } diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index 1176c506cf60..93a820cf1406 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -711,6 +711,16 @@ public final class SensorPrivacyService extends SystemService { @Override public void setIndividualSensorPrivacy(@UserIdInt int userId, @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) { + if (DEBUG) { + Log.d(TAG, "callingUid=" + Binder.getCallingUid() + + " callingPid=" + Binder.getCallingPid() + + " setIndividualSensorPrivacy(" + + "userId=" + userId + + " source=" + source + + " sensor=" + sensor + + " enable=" + enable + + ")"); + } enforceManageSensorPrivacyPermission(); if (userId == UserHandle.USER_CURRENT) { userId = mCurrentUser; @@ -895,6 +905,14 @@ public final class SensorPrivacyService extends SystemService { @Override public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) { + if (DEBUG) { + Log.d(TAG, "callingUid=" + Binder.getCallingUid() + + " callingPid=" + Binder.getCallingPid() + + " isIndividualSensorPrivacyEnabled(" + + "userId=" + userId + + " sensor=" + sensor + + ")"); + } enforceObserveSensorPrivacyPermission(); if (userId == UserHandle.USER_CURRENT) { userId = mCurrentUser; diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index b4413a4447b7..63301ac49573 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -1025,7 +1025,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } - int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { // register IBinder b = callback.asBinder(); @@ -1048,21 +1047,24 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID if (!SubscriptionManager.isValidSubscriptionId(subId)) { + if (DBG) { + log("invalid subscription id, use default id"); + } r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } else {//APP specify subID r.subId = subId; } - r.phoneId = phoneId; + r.phoneId = getPhoneIdFromSubId(r.subId); r.eventList = events; if (DBG) { - log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); + log("listen: Register r=" + r + " r.subId=" + r.subId + " r.phoneId=" + r.phoneId); } - if (notifyNow && validatePhoneId(phoneId)) { + if (notifyNow && validatePhoneId(r.phoneId)) { if (events.contains(TelephonyCallback.EVENT_SERVICE_STATE_CHANGED)){ try { - if (VDBG) log("listen: call onSSC state=" + mServiceState[phoneId]); - ServiceState rawSs = new ServiceState(mServiceState[phoneId]); + if (VDBG) log("listen: call onSSC state=" + mServiceState[r.phoneId]); + ServiceState rawSs = new ServiceState(mServiceState[r.phoneId]); if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onServiceStateChanged(rawSs); } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { @@ -1078,8 +1080,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED)) { try { - if (mSignalStrength[phoneId] != null) { - int gsmSignalStrength = mSignalStrength[phoneId] + if (mSignalStrength[r.phoneId] != null) { + int gsmSignalStrength = mSignalStrength[r.phoneId] .getGsmSignalStrength(); r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 : gsmSignalStrength)); @@ -1092,7 +1094,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED)) { try { r.callback.onMessageWaitingIndicatorChanged( - mMessageWaiting[phoneId]); + mMessageWaiting[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1101,7 +1103,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED)) { try { r.callback.onCallForwardingIndicatorChanged( - mCallForwarding[phoneId]); + mCallForwarding[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1109,11 +1111,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED)) { try { - if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); + if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[r.phoneId]); if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { // null will be translated to empty CellLocation object in client. - r.callback.onCellLocationChanged(mCellIdentity[phoneId]); + r.callback.onCellLocationChanged(mCellIdentity[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1121,38 +1123,38 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED)) { try { - r.callback.onLegacyCallStateChanged(mCallState[phoneId], - getCallIncomingNumber(r, phoneId)); + r.callback.onLegacyCallStateChanged(mCallState[r.phoneId], + getCallIncomingNumber(r, r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_STATE_CHANGED)) { try { - r.callback.onCallStateChanged(mCallState[phoneId]); + r.callback.onCallStateChanged(mCallState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED)) { try { - r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], - mDataConnectionNetworkType[phoneId]); + r.callback.onDataConnectionStateChanged(mDataConnectionState[r.phoneId], + mDataConnectionNetworkType[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED)) { try { - r.callback.onDataActivity(mDataActivity[phoneId]); + r.callback.onDataActivity(mDataActivity[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED)) { try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + if (mSignalStrength[r.phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1162,8 +1164,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) { updateReportSignalStrengthDecision(r.subId); try { - if (mSignalStrength[phoneId] != null) { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + if (mSignalStrength[r.phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1172,11 +1174,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_INFO_CHANGED)) { try { - if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " - + mCellInfo.get(phoneId)); + if (DBG_LOC) { + log("listen: mCellInfo[" + r.phoneId + "] = " + + mCellInfo.get(r.phoneId)); + } if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); + r.callback.onCellInfoChanged(mCellInfo.get(r.phoneId)); } } catch (RemoteException ex) { remove(r.binder); @@ -1184,22 +1188,22 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED)) { try { - r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); + r.callback.onPreciseCallStateChanged(mPreciseCallState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED)) { try { - r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], - mCallPreciseDisconnectCause[phoneId]); + r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[r.phoneId], + mCallPreciseDisconnectCause[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED)) { try { - r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(phoneId)); + r.callback.onImsCallDisconnectCauseChanged(mImsReasonInfo.get(r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -1208,7 +1212,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED)) { try { for (PreciseDataConnectionState pdcs - : mPreciseDataConnectionStates.get(phoneId).values()) { + : mPreciseDataConnectionStates.get(r.phoneId).values()) { r.callback.onPreciseDataConnectionStateChanged(pdcs); } } catch (RemoteException ex) { @@ -1225,29 +1229,29 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED)) { try { r.callback.onVoiceActivationStateChanged( - mVoiceActivationState[phoneId]); + mVoiceActivationState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED)) { try { - r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]); + r.callback.onDataActivationStateChanged(mDataActivationState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED)) { try { - r.callback.onUserMobileDataStateChanged(mUserMobileDataState[phoneId]); + r.callback.onUserMobileDataStateChanged(mUserMobileDataState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED)) { try { - if (mTelephonyDisplayInfos[phoneId] != null) { - r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[phoneId]); + if (mTelephonyDisplayInfos[r.phoneId] != null) { + r.callback.onDisplayInfoChanged(mTelephonyDisplayInfos[r.phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -1284,20 +1288,20 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED)) { try { - r.callback.onSrvccStateChanged(mSrvccState[phoneId]); + r.callback.onSrvccStateChanged(mSrvccState[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) { try { - r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); + r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (events.contains(TelephonyCallback.EVENT_BARRING_INFO_CHANGED)) { - BarringInfo barringInfo = mBarringInfo.get(phoneId); + BarringInfo barringInfo = mBarringInfo.get(r.phoneId); BarringInfo biNoLocation = barringInfo != null ? barringInfo.createLocationInfoSanitizedCopy() : null; if (VDBG) log("listen: call onBarringInfoChanged=" + barringInfo); @@ -1315,8 +1319,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callback.onPhysicalChannelConfigChanged( shouldSanitizeLocationForPhysicalChannelConfig(r) ? getLocationSanitizedConfigs( - mPhysicalChannelConfigs.get(phoneId)) - : mPhysicalChannelConfigs.get(phoneId)); + mPhysicalChannelConfigs.get(r.phoneId)) + : mPhysicalChannelConfigs.get(r.phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -1325,7 +1329,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_DATA_ENABLED_CHANGED)) { try { r.callback.onDataEnabledChanged( - mIsDataEnabled[phoneId], mDataEnabledReason[phoneId]); + mIsDataEnabled[r.phoneId], mDataEnabledReason[r.phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -1333,9 +1337,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (events.contains( TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)) { try { - if (mLinkCapacityEstimateLists.get(phoneId) != null) { + if (mLinkCapacityEstimateLists.get(r.phoneId) != null) { r.callback.onLinkCapacityEstimateChanged(mLinkCapacityEstimateLists - .get(phoneId)); + .get(r.phoneId)); } } catch (RemoteException ex) { remove(r.binder); @@ -1577,7 +1581,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SERVICE_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { ServiceState stateToSend; @@ -1639,7 +1643,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((activationType == SIM_ACTIVATION_TYPE_VOICE) && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { if (DBG) { log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r + " subId=" + subId + " phoneId=" + phoneId @@ -1650,7 +1654,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((activationType == SIM_ACTIVATION_TYPE_DATA) && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ACTIVATION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { if (DBG) { log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r + " subId=" + subId + " phoneId=" + phoneId @@ -1692,7 +1696,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_SIGNAL_STRENGTHS_CHANGED) || r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED)) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG) { log("notifySignalStrengthForPhoneId: callback.onSsS r=" + r @@ -1706,7 +1710,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SIGNAL_STRENGTH_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { int gsmSignalStrength = signalStrength.getGsmSignalStrength(); int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); @@ -1753,7 +1757,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CARRIER_NETWORK_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCarrierNetworkChange(active); } catch (RemoteException ex) { @@ -1785,7 +1789,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_INFO_CHANGED) - && idMatch(r.subId, subId, phoneId) + && idMatch(r, subId, phoneId) && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { @@ -1819,7 +1823,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_MESSAGE_WAITING_INDICATOR_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onMessageWaitingIndicatorChanged(mwi); } catch (RemoteException ex) { @@ -1846,7 +1850,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_USER_MOBILE_DATA_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onUserMobileDataStateChanged(state); } catch (RemoteException ex) { @@ -1885,7 +1889,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED) - && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) { + && idMatch(r, subId, phoneId)) { try { if (!mConfigurationProvider.isDisplayInfoNrAdvancedSupported( r.callingPackage, Binder.getCallingUserHandle())) { @@ -1937,7 +1941,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_FORWARDING_INDICATOR_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallForwardingIndicatorChanged(cfi); } catch (RemoteException ex) { @@ -1966,7 +1970,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Notify by correct subId. if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ACTIVITY_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onDataActivity(state); } catch (RemoteException ex) { @@ -2014,7 +2018,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_CONNECTION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG) { log("Notify data connection state changed on sub: " + subId); @@ -2039,7 +2043,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onPreciseDataConnectionStateChanged(preciseState); } catch (RemoteException ex) { @@ -2086,7 +2090,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventAndUserLocked( r, TelephonyCallback.EVENT_CELL_LOCATION_CHANGED) - && idMatch(r.subId, subId, phoneId) + && idMatch(r, subId, phoneId) && (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { @@ -2140,7 +2144,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PRECISE_CALL_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onPreciseCallStateChanged(mPreciseCallState[phoneId]); } catch (RemoteException ex) { @@ -2149,7 +2153,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (notifyCallAttributes && r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); } catch (RemoteException ex) { @@ -2174,7 +2178,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_DISCONNECT_CAUSE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallDisconnectCauseChanged(mCallDisconnectCause[phoneId], mCallPreciseDisconnectCause[phoneId]); @@ -2199,7 +2203,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyImsCallDisconnectCause: mImsReasonInfo=" @@ -2231,7 +2235,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_SRVCC_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifySrvccStateChanged: mSrvccState=" + state + " r=" + r); @@ -2260,7 +2264,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_OEM_HOOK_RAW)) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onOemHookRawEvent(rawData); } catch (RemoteException ex) { @@ -2340,7 +2344,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onRadioPowerStateChanged(state); } catch (RemoteException ex) { @@ -2369,7 +2373,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_EMERGENCY_NUMBER_LIST_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); if (VDBG) { @@ -2456,7 +2460,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onCallAttributesChanged(mCallAttributes[phoneId]); } catch (RemoteException ex) { @@ -2487,7 +2491,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_REGISTRATION_FAILURE) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onRegistrationFailed( checkFineLocationAccess(r, Build.VERSION_CODES.BASE) @@ -2530,7 +2534,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_BARRING_INFO_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyBarringInfo: mBarringInfo=" @@ -2575,7 +2579,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (DBG_LOC) { log("notifyPhysicalChannelConfig: mPhysicalChannelConfigs=" @@ -2642,7 +2646,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_DATA_ENABLED_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onDataEnabledChanged(enabled, reason); } catch (RemoteException ex) { @@ -2677,7 +2681,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { if (VDBG) { log("notifyAllowedNetworkTypesChanged: reason= " + reason @@ -2719,7 +2723,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED) - && idMatch(r.subId, subId, phoneId)) { + && idMatch(r, subId, phoneId)) { try { r.callback.onLinkCapacityEstimateChanged(linkCapacityEstimateList); } catch (RemoteException ex) { @@ -3169,33 +3173,24 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } /** - * If the registrant specified a subId, then we should only notify it if subIds match. - * If the registrant registered with DEFAULT subId, we should notify only when the related subId - * is default subId (which could be INVALID if there's no default subId). + * Match the sub id or phone id of the event to the record * - * This should be the correct way to check record ID match. in idMatch the record's phoneId is - * speculated based on subId passed by the registrant so it's not a good reference. - * But to avoid triggering potential regression only replace idMatch with it when an issue with - * idMatch is reported. Eventually this should replace all instances of idMatch. + * We follow the rules below: + * 1) If sub id of the event is invalid, phone id should be used. + * 2) The event on default sub should be notified to the records + * which register the default sub id. + * 3) Sub id should be exactly matched for all other cases. */ - private boolean idMatchWithoutDefaultPhoneCheck(int subIdInRecord, int subIdToNotify) { - if (subIdInRecord == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - return (subIdToNotify == mDefaultSubId); - } else { - return (subIdInRecord == subIdToNotify); - } - } - - boolean idMatch(int rSubId, int subId, int phoneId) { + boolean idMatch(Record r, int subId, int phoneId) { - if(subId < 0) { - // Invalid case, we need compare phoneId with default one. - return (mDefaultPhoneId == phoneId); + if (subId < 0) { + // Invalid case, we need compare phoneId. + return (r.phoneId == phoneId); } - if(rSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + if (r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { return (subId == mDefaultSubId); } else { - return (rSubId == subId); + return (r.subId == subId); } } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 5797b061f2d0..5fc301e60b9d 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -53,6 +53,7 @@ import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.view.Display; import android.view.DisplayInfo; @@ -77,7 +78,6 @@ import java.util.List; import java.util.Locale; import java.util.Objects; - /** * The DisplayModeDirector is responsible for determining what modes are allowed to be automatically * picked by the system based on system-wide and display-specific configuration. @@ -92,6 +92,8 @@ public class DisplayModeDirector { private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4; private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5; private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6; + private static final int MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED = 7; + private static final int MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED = 8; // Special ID used to indicate that given vote is to be applied globally, rather than to a // specific display. @@ -161,9 +163,10 @@ public class DisplayModeDirector { } }; mSensorObserver = new SensorObserver(context, ballotBox, injector); - mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler()); mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox); mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); + mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(), + mDeviceConfigDisplaySettings); mDeviceConfig = injector.getDeviceConfig(); mAlwaysRespectAppRequest = false; } @@ -724,6 +727,11 @@ public class DisplayModeDirector { } @VisibleForTesting + HbmObserver getHbmObserver() { + return mHbmObserver; + } + + @VisibleForTesting DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { synchronized (mLock) { @@ -792,6 +800,19 @@ public class DisplayModeDirector { (DesiredDisplayModeSpecsListener) msg.obj; desiredDisplayModeSpecsListener.onDesiredDisplayModeSpecsChanged(); break; + + case MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED: { + int refreshRateInHbmSunlight = msg.arg1; + mHbmObserver.onDeviceConfigRefreshRateInHbmSunlightChanged( + refreshRateInHbmSunlight); + break; + } + + case MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED: { + int refreshRateInHbmHdr = msg.arg1; + mHbmObserver.onDeviceConfigRefreshRateInHbmHdrChanged(refreshRateInHbmHdr); + break; + } } } } @@ -918,16 +939,19 @@ public class DisplayModeDirector { // result is a range. public static final int PRIORITY_FLICKER_REFRESH_RATE = 1; + // High-brightness-mode may need a specific range of refresh-rates to function properly. + public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2; + // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate. // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY] - public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 2; + public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 3; // APP_REQUEST_REFRESH_RATE_RANGE is used to for internal apps to limit the refresh // rate in certain cases, mostly to preserve power. // @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate // @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate // It votes to [preferredMinRefreshRate, preferredMaxRefreshRate]. - public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 3; + public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 4; // We split the app request into different priorities in case we can satisfy one desire // without the other. @@ -942,27 +966,24 @@ public class DisplayModeDirector { // The preferred refresh rate is set on the main surface of the app outside of // DisplayModeDirector. // @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded - public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 4; - public static final int PRIORITY_APP_REQUEST_SIZE = 5; + public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5; + public static final int PRIORITY_APP_REQUEST_SIZE = 6; // SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest // of low priority voters. It votes [0, max(PEAK, MIN)] - public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 6; + public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 7; // LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on. - public static final int PRIORITY_LOW_POWER_MODE = 7; + public static final int PRIORITY_LOW_POWER_MODE = 8; // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the // higher priority voters' result is a range, it will fix the rate to a single choice. // It's used to avoid refresh rate switches in certain conditions which may result in the // user seeing the display flickering when the switches occur. - public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8; + public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 9; // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL. - public static final int PRIORITY_SKIN_TEMPERATURE = 9; - - // High-brightness-mode may need a specific range of refresh-rates to function properly. - public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10; + public static final int PRIORITY_SKIN_TEMPERATURE = 10; // The proximity sensor needs the refresh rate to be locked in order to function, so this is // set to a high priority. @@ -2258,33 +2279,78 @@ public class DisplayModeDirector { * HBM that are associated with that display. Restrictions are retrieved from * DisplayManagerInternal but originate in the display-device-config file. */ - private static class HbmObserver implements DisplayManager.DisplayListener { + public static class HbmObserver implements DisplayManager.DisplayListener { private final BallotBox mBallotBox; private final Handler mHandler; - private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray(); + private final SparseIntArray mHbmMode = new SparseIntArray(); private final Injector mInjector; + private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; + private int mRefreshRateInHbmSunlight; + private int mRefreshRateInHbmHdr; private DisplayManagerInternal mDisplayManagerInternal; - HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) { + HbmObserver(Injector injector, BallotBox ballotBox, Handler handler, + DeviceConfigDisplaySettings displaySettings) { mInjector = injector; mBallotBox = ballotBox; mHandler = handler; + mDeviceConfigDisplaySettings = displaySettings; } public void observe() { + mRefreshRateInHbmSunlight = mDeviceConfigDisplaySettings.getRefreshRateInHbmSunlight(); + mRefreshRateInHbmHdr = mDeviceConfigDisplaySettings.getRefreshRateInHbmHdr(); + mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mInjector.registerDisplayListener(this, mHandler, DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED); } + /** + * @return the refresh to lock to when the device is in high brightness mode for Sunlight. + */ + @VisibleForTesting + int getRefreshRateInHbmSunlight() { + return mRefreshRateInHbmSunlight; + } + + /** + * @return the refresh to lock to when the device is in high brightness mode for HDR. + */ + @VisibleForTesting + int getRefreshRateInHbmHdr() { + return mRefreshRateInHbmHdr; + } + + /** + * Recalculates the HBM vote when the device config has been changed. + */ + public void onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate) { + if (refreshRate != mRefreshRateInHbmSunlight) { + mRefreshRateInHbmSunlight = refreshRate; + onDeviceConfigRefreshRateInHbmChanged(); + } + } + + /** + * Recalculates the HBM vote when the device config has been changed. + */ + public void onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate) { + if (refreshRate != mRefreshRateInHbmHdr) { + mRefreshRateInHbmHdr = refreshRate; + onDeviceConfigRefreshRateInHbmChanged(); + } + } + @Override public void onDisplayAdded(int displayId) {} @Override public void onDisplayRemoved(int displayId) { mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null); + mHbmMode.delete(displayId); } @Override @@ -2294,31 +2360,56 @@ public class DisplayModeDirector { // Display no longer there. Assume we'll get an onDisplayRemoved very soon. return; } - final boolean isHbmEnabled = - info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF; - if (isHbmEnabled == mHbmEnabled.get(displayId)) { + final int hbmMode = info.highBrightnessMode; + if (hbmMode == mHbmMode.get(displayId)) { // no change, ignore. return; } + mHbmMode.put(displayId, hbmMode); + recalculateVotesForDisplay(displayId); + } + + private void onDeviceConfigRefreshRateInHbmChanged() { + final int[] displayIds = mHbmMode.copyKeys(); + if (displayIds != null) { + for (int id : displayIds) { + recalculateVotesForDisplay(id); + } + } + } + + private void recalculateVotesForDisplay(int displayId) { + final int hbmMode = mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); Vote vote = null; - mHbmEnabled.put(displayId, isHbmEnabled); - if (isHbmEnabled) { - final List<RefreshRateLimitation> limits = + if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) { + // Device resource properties take priority over DisplayDeviceConfig + if (mRefreshRateInHbmSunlight > 0) { + vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight, + mRefreshRateInHbmSunlight); + } else { + final List<RefreshRateLimitation> limits = mDisplayManagerInternal.getRefreshRateLimitations(displayId); - for (int i = 0; limits != null && i < limits.size(); i++) { - final RefreshRateLimitation limitation = limits.get(i); - if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { - vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max); - break; + for (int i = 0; limits != null && i < limits.size(); i++) { + final RefreshRateLimitation limitation = limits.get(i); + if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) { + vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max); + break; + } } } } + if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR + && mRefreshRateInHbmHdr > 0) { + vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr); + } mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote); } void dumpLocked(PrintWriter pw) { pw.println(" HbmObserver"); - pw.println(" mHbmEnabled: " + mHbmEnabled); + pw.println(" mHbmMode: " + mHbmMode); + pw.println(" mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight); + pw.println(" mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr); } } @@ -2437,6 +2528,29 @@ public class DisplayModeDirector { return refreshRate; } + public int getRefreshRateInHbmSunlight() { + final int defaultRefreshRateInHbmSunlight = + mContext.getResources().getInteger( + R.integer.config_defaultRefreshRateInHbmSunlight); + + final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, + defaultRefreshRateInHbmSunlight); + + return refreshRate; + } + + public int getRefreshRateInHbmHdr() { + final int defaultRefreshRateInHbmHdr = + mContext.getResources().getInteger(R.integer.config_defaultRefreshRateInHbmHdr); + + final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR, + defaultRefreshRateInHbmHdr); + + return refreshRate; + } + /* * Return null if no such property */ @@ -2476,6 +2590,15 @@ public class DisplayModeDirector { .sendToTarget(); mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0) .sendToTarget(); + + final int refreshRateInHbmSunlight = getRefreshRateInHbmSunlight(); + mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED, + refreshRateInHbmSunlight, 0) + .sendToTarget(); + + final int refreshRateInHbmHdr = getRefreshRateInHbmHdr(); + mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED, refreshRateInHbmHdr, 0) + .sendToTarget(); } private int[] getIntArrayProperty(String prop) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 45f5daac8dd9..dd2583a0ce1a 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -508,7 +508,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mKeyguardOccludedChanged; private ActivityTaskManagerInternal.SleepTokenAcquirer mScreenOffSleepTokenAcquirer; - volatile boolean mKeyguardOccluded; Intent mHomeIntent; Intent mCarDockIntent; Intent mDeskDockIntent; @@ -2399,7 +2398,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the keyguard is being hidden. This is okay because starting windows never show // secret information. // TODO(b/113840485): Occluded may not only happen on default display - if (displayId == DEFAULT_DISPLAY && mKeyguardOccluded) { + if (displayId == DEFAULT_DISPLAY && isKeyguardOccluded()) { windowFlags |= FLAG_SHOW_WHEN_LOCKED; } } @@ -3215,7 +3214,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return; } - if (!mKeyguardOccluded && mKeyguardDelegate.isInputRestricted()) { + if (!isKeyguardOccluded() && mKeyguardDelegate.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock // before launching home mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() { @@ -3266,42 +3265,38 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void setKeyguardCandidateLw(WindowState win) { mKeyguardCandidate = win; - setKeyguardOccludedLw(mKeyguardOccluded, true /* force */); + setKeyguardOccludedLw(isKeyguardOccluded(), true /* force */); } /** * Updates the occluded state of the Keyguard. * + * @param isOccluded Whether the Keyguard is occluded by another window. + * @param force notify the occluded status to KeyguardService and update flags even though + * occlude status doesn't change. * @return Whether the flags have changed and we have to redo the layout. */ private boolean setKeyguardOccludedLw(boolean isOccluded, boolean force) { if (DEBUG_KEYGUARD) Slog.d(TAG, "setKeyguardOccluded occluded=" + isOccluded); - final boolean wasOccluded = mKeyguardOccluded; + if (isKeyguardOccluded() == isOccluded && !force) { + return false; + } + final boolean showing = mKeyguardDelegate.isShowing(); - final boolean changed = wasOccluded != isOccluded || force; - if (!isOccluded && changed && showing) { - mKeyguardOccluded = false; - mKeyguardDelegate.setOccluded(false, true /* animate */); - if (mKeyguardCandidate != null) { - if (!mKeyguardDelegate.hasLockscreenWallpaper()) { - mKeyguardCandidate.getAttrs().flags |= FLAG_SHOW_WALLPAPER; - } - } - return true; - } else if (isOccluded && changed && showing) { - mKeyguardOccluded = true; - mKeyguardDelegate.setOccluded(true, false /* animate */); - if (mKeyguardCandidate != null) { + final boolean animate = showing && !isOccluded; + mKeyguardDelegate.setOccluded(isOccluded, animate); + + if (!showing) { + return false; + } + if (mKeyguardCandidate != null) { + if (isOccluded) { mKeyguardCandidate.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER; + } else if (!mKeyguardDelegate.hasLockscreenWallpaper()) { + mKeyguardCandidate.getAttrs().flags |= FLAG_SHOW_WALLPAPER; } - return true; - } else if (changed) { - mKeyguardOccluded = isOccluded; - mKeyguardDelegate.setOccluded(isOccluded, false /* animate */); - return false; - } else { - return false; } + return true; } /** {@inheritDoc} */ @@ -4596,7 +4591,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public boolean isKeyguardShowingAndNotOccluded() { if (mKeyguardDelegate == null) return false; - return mKeyguardDelegate.isShowing() && !mKeyguardOccluded; + return mKeyguardDelegate.isShowing() && !isKeyguardOccluded(); } @Override @@ -4622,7 +4617,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public boolean isKeyguardOccluded() { if (mKeyguardDelegate == null) return false; - return mKeyguardOccluded; + return mKeyguardDelegate.isOccluded(); } /** {@inheritDoc} */ @@ -5308,7 +5303,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { proto.write(KEYGUARD_DRAW_COMPLETE, mDefaultDisplayPolicy.isKeyguardDrawComplete()); proto.write(WINDOW_MANAGER_DRAW_COMPLETE, mDefaultDisplayPolicy.isWindowManagerDrawComplete()); - proto.write(KEYGUARD_OCCLUDED, mKeyguardOccluded); + proto.write(KEYGUARD_OCCLUDED, isKeyguardOccluded()); proto.write(KEYGUARD_OCCLUDED_CHANGED, mKeyguardOccludedChanged); proto.write(KEYGUARD_OCCLUDED_PENDING, mPendingKeyguardOccluded); if (mKeyguardDelegate != null) { @@ -5393,7 +5388,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final int key = mDisplayHomeButtonHandlers.keyAt(i); pw.println(mDisplayHomeButtonHandlers.get(key)); } - pw.print(prefix); pw.print("mKeyguardOccluded="); pw.print(mKeyguardOccluded); + pw.print(prefix); pw.print("mKeyguardOccluded="); pw.print(isKeyguardOccluded()); pw.print(" mKeyguardOccludedChanged="); pw.print(mKeyguardOccludedChanged); pw.print(" mPendingKeyguardOccluded="); pw.println(mPendingKeyguardOccluded); pw.print(prefix); pw.print("mAllowLockscreenWhenOnDisplays="); diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java index 0535af57d8ab..d1906785994a 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java @@ -67,7 +67,7 @@ public class KeyguardServiceDelegate { boolean showing; boolean showingAndNotOccluded; boolean inputRestricted; - boolean occluded; + volatile boolean occluded; boolean secure; boolean dreaming; boolean systemIsReady; @@ -272,6 +272,10 @@ public class KeyguardServiceDelegate { mKeyguardState.occluded = isOccluded; } + public boolean isOccluded() { + return mKeyguardState.occluded; + } + public void dismiss(IKeyguardDismissCallback callback, CharSequence message) { if (mKeyguardService != null) { mKeyguardService.dismiss(callback, message); diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 61770ea1c1c2..106cff17dbef 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -67,6 +67,7 @@ import static java.util.concurrent.TimeUnit.MICROSECONDS; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.AppOpsManager.HistoricalOp; @@ -82,6 +83,7 @@ import android.app.StatsManager.PullAtomMetadata; import android.bluetooth.BluetoothActivityEnergyInfo; import android.bluetooth.BluetoothAdapter; import android.bluetooth.UidTraffic; +import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; @@ -734,6 +736,10 @@ public class StatsPullAtomService extends SystemService { case FrameworkStatsLog.RKP_ERROR_STATS: case FrameworkStatsLog.KEYSTORE2_CRASH_STATS: return pullKeystoreAtoms(atomTag, data); + case FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS: + return pullAccessibilityShortcutStatsLocked(atomTag, data); + case FrameworkStatsLog.ACCESSIBILITY_FLOATING_MENU_STATS: + return pullAccessibilityFloatingMenuStatsLocked(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } @@ -930,6 +936,8 @@ public class StatsPullAtomService extends SystemService { registerKeystoreKeyOperationWithGeneralInfo(); registerRkpErrorStats(); registerKeystoreCrashStats(); + registerAccessibilityShortcutStats(); + registerAccessibilityFloatingMenuStats(); } private void initAndRegisterNetworkStatsPullers() { @@ -4150,6 +4158,26 @@ public class StatsPullAtomService extends SystemService { mStatsCallbackImpl); } + private void registerAccessibilityShortcutStats() { + int tagId = FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_STATS; + mStatsManager.setPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + DIRECT_EXECUTOR, + mStatsCallbackImpl + ); + } + + private void registerAccessibilityFloatingMenuStats() { + int tagId = FrameworkStatsLog.ACCESSIBILITY_FLOATING_MENU_STATS; + mStatsManager.setPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + DIRECT_EXECUTOR, + mStatsCallbackImpl + ); + } + int parseKeystoreStorageStats(KeystoreAtom[] atoms, List<StatsEvent> pulledData) { for (KeystoreAtom atomWrapper : atoms) { if (atomWrapper.payload.getTag() != KeystoreAtomPayload.storageStats) { @@ -4341,6 +4369,144 @@ public class StatsPullAtomService extends SystemService { } } + int pullAccessibilityShortcutStatsLocked(int atomTag, List<StatsEvent> pulledData) { + UserManager userManager = mContext.getSystemService(UserManager.class); + if (userManager == null) { + return StatsManager.PULL_SKIP; + } + final long token = Binder.clearCallingIdentity(); + try { + final ContentResolver resolver = mContext.getContentResolver(); + final int hardware_shortcut_type = + FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY; + final int triple_tap_shortcut = + FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__TRIPLE_TAP; + for (UserInfo userInfo : userManager.getUsers()) { + final int userId = userInfo.getUserHandle().getIdentifier(); + + if (isAccessibilityShortcutUser(mContext, userId)) { + final int software_shortcut_type = Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId); + final String software_shortcut_list = Settings.Secure.getStringForUser(resolver, + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId); + final int software_shortcut_service_num = countAccessibilityServices( + software_shortcut_list); + + final String hardware_shortcut_list = Settings.Secure.getStringForUser(resolver, + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId); + final int hardware_shortcut_service_num = countAccessibilityServices( + hardware_shortcut_list); + + // only allow magnification to use it for now + final int triple_tap_service_num = Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0, userId); + + pulledData.add( + FrameworkStatsLog.buildStatsEvent(atomTag, + software_shortcut_type, software_shortcut_service_num, + hardware_shortcut_type, hardware_shortcut_service_num, + triple_tap_shortcut, triple_tap_service_num)); + } + } + } catch (RuntimeException e) { + Slog.e(TAG, "pulling accessibility shortcuts stats failed at getUsers", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; + } + + int pullAccessibilityFloatingMenuStatsLocked(int atomTag, List<StatsEvent> pulledData) { + UserManager userManager = mContext.getSystemService(UserManager.class); + if (userManager == null) { + return StatsManager.PULL_SKIP; + } + final long token = Binder.clearCallingIdentity(); + try { + final ContentResolver resolver = mContext.getContentResolver(); + final int defaultSize = 0; + final int defaultIconType = 0; + final int defaultFadeEnabled = 1; + final float defaultOpacity = 0.55f; + + for (UserInfo userInfo : userManager.getUsers()) { + final int userId = userInfo.getUserHandle().getIdentifier(); + + if (isAccessibilityFloatingMenuUser(mContext, userId)) { + final int size = Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, defaultSize, userId); + final int type = Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, + defaultIconType, userId); + final boolean fadeEnabled = (Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, + defaultFadeEnabled, userId)) == 1; + final float opacity = Settings.Secure.getFloatForUser(resolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, + defaultOpacity, userId); + + pulledData.add( + FrameworkStatsLog.buildStatsEvent(atomTag, size, type, fadeEnabled, + opacity)); + } + } + } catch (RuntimeException e) { + Slog.e(TAG, "pulling accessibility floating menu stats failed at getUsers", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; + } + + /** + * Counts how many accessibility services (including features) there are in the colon-separated + * string list. + * + * @param semicolonList colon-separated string, it should be + * {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or + * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}. + * @return The number of accessibility services + */ + private int countAccessibilityServices(String semicolonList) { + if (TextUtils.isEmpty(semicolonList)) { + return 0; + } + final int semiColonNums = (int) semicolonList.chars().filter(ch -> ch == ':').count(); + return TextUtils.isEmpty(semicolonList) ? 0 : semiColonNums + 1; + } + + private boolean isAccessibilityShortcutUser(Context context, @UserIdInt int userId) { + final ContentResolver resolver = context.getContentResolver(); + + final String software_shortcut_list = Settings.Secure.getStringForUser(resolver, + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId); + final String hardware_shortcut_list = Settings.Secure.getStringForUser(resolver, + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId); + final boolean hardware_shortcut_dialog_shown = Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId) == 1; + final boolean software_shortcut_enabled = !TextUtils.isEmpty(software_shortcut_list); + final boolean hardware_shortcut_enabled = + hardware_shortcut_dialog_shown && !TextUtils.isEmpty(hardware_shortcut_list); + final boolean triple_tap_shortcut_enabled = Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0, userId) == 1; + + return software_shortcut_enabled || hardware_shortcut_enabled + || triple_tap_shortcut_enabled; + } + + private boolean isAccessibilityFloatingMenuUser(Context context, @UserIdInt int userId) { + final ContentResolver resolver = context.getContentResolver(); + final int mode = Settings.Secure.getIntForUser(resolver, + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId); + final String software_string = Settings.Secure.getStringForUser(resolver, + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId); + + return (mode == Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) + && !TextUtils.isEmpty(software_string); + } + // Thermal event received from vendor thermal management subsystem private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d0caf1ce444e..3b1da1d0053d 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1411,9 +1411,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this.task = newTask; if (shouldStartChangeTransition(newParent, oldParent)) { - // The new parent and old parent may be in different position. Need to offset the - // animation surface to keep it in its original position. - initializeChangeTransition(getBounds(), newParent.getBounds()); + // Animate change transition on TaskFragment level to get the correct window crop. + newParent.initializeChangeTransition(getBounds(), getSurfaceControl()); } super.onParentChanged(newParent, oldParent); @@ -1482,7 +1481,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // The starting window should keep covering its task when the activity is // reparented to a task fragment that may not fill the task bounds. associateStartingDataWithTask(); - overrideConfigurationPropagation(mStartingWindow, task); + attachStartingSurfaceToAssociatedTask(); } mImeInsetsFrozenUntilStartInput = false; } @@ -2383,13 +2382,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void attachStartingWindow(@NonNull WindowState startingWindow) { + startingWindow.mStartingData = mStartingData; mStartingWindow = startingWindow; if (mStartingData != null && mStartingData.mAssociatedTask != null) { - // Associate the configuration of starting window with the task. - overrideConfigurationPropagation(startingWindow, mStartingData.mAssociatedTask); + attachStartingSurfaceToAssociatedTask(); } } + private void attachStartingSurfaceToAssociatedTask() { + // Associate the configuration of starting window with the task. + overrideConfigurationPropagation(mStartingWindow, mStartingData.mAssociatedTask); + getSyncTransaction().reparent(mStartingWindow.mSurfaceControl, + mStartingData.mAssociatedTask.mSurfaceControl); + } + private void associateStartingDataWithTask() { mStartingData.mAssociatedTask = task; task.forAllActivities(r -> { diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 0ba77d8552d3..9db13ba825f4 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -596,11 +596,56 @@ public abstract class ActivityTaskManagerInternal { public abstract boolean isBaseOfLockedTask(String packageName); /** - * Create an interface to update configuration for an application. + * Creates an interface to update configuration for the calling application. */ public abstract PackageConfigurationUpdater createPackageConfigurationUpdater(); /** + * Creates an interface to update configuration for an arbitrary application specified by it's + * packageName and userId. + */ + public abstract PackageConfigurationUpdater createPackageConfigurationUpdater( + String packageName, int userId); + + /** + * Retrieves and returns the app-specific configuration for an arbitrary application specified + * by its packageName and userId. Returns null if no app-specific configuration has been set. + */ + @Nullable + public abstract PackageConfig getApplicationConfig(String packageName, + int userId); + + /** + * Holds app-specific configurations. + */ + public static class PackageConfig { + /** + * nightMode for the application, null if app-specific nightMode is not set. + */ + @Nullable + public final Integer mNightMode; + + /** + * {@link LocaleList} for the application, null if app-specific locales are not set. + */ + @Nullable + public final LocaleList mLocales; + + PackageConfig(Integer nightMode, LocaleList locales) { + mNightMode = nightMode; + mLocales = locales; + } + + /** + * Returns the string representation of the app-specific configuration. + */ + @Override + public String toString() { + return "PackageConfig: nightMode " + mNightMode + " locales " + mLocales; + } + } + + /** * An interface to update configuration for an application, and will persist override * configuration for this package. */ diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 6e5ba31b3ff6..89f7d92b2087 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -6557,6 +6557,20 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public PackageConfigurationUpdater createPackageConfigurationUpdater( + String packageName , int userId) { + return new PackageConfigurationUpdaterImpl(packageName, userId, + ActivityTaskManagerService.this); + } + + @Override + @Nullable + public ActivityTaskManagerInternal.PackageConfig getApplicationConfig(String packageName, + int userId) { + return mPackageConfigPersister.findPackageConfiguration(packageName, userId); + } + + @Override public boolean hasSystemAlertWindowPermission(int callingUid, int callingPid, String callingPackage) { return ActivityTaskManagerService.this.hasSystemAlertWindowPermission(callingUid, diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 04970c1d8fc2..ba305929d808 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -841,16 +841,18 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { logIfTransactionTooLarge(r.intent, r.getSavedState()); + if (r.isEmbedded()) { + // Sending TaskFragmentInfo to client to ensure the info is updated before + // the activity creation. + mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent( + r.getOrganizedTaskFragment()); + } // Create activity launch transaction. final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.appToken); final boolean isTransitionForward = r.isTransitionForward(); - IBinder fragmentToken = null; - if (r.getTaskFragment().getTaskFragmentOrganizerPid() == r.getPid()) { - fragmentToken = r.getTaskFragment().getFragmentToken(); - } clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global @@ -862,7 +864,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { results, newIntents, r.takeOptions(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken, - r.getLaunchedFromBubble(), fragmentToken)); + r.getLaunchedFromBubble())); // Set desired final state. final ActivityLifecycleItem lifecycleItem; diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 82377b34d22a..9561de09971b 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -343,9 +343,6 @@ public class AppTransitionController { switch (changingType) { case TYPE_TASK: return TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; - case TYPE_ACTIVITY: - // ActivityRecord is put in a change transition only when it is reparented - // to an organized TaskFragment. See ActivityRecord#shouldStartChangeTransition. case TYPE_TASK_FRAGMENT: return TRANSIT_OLD_TASK_FRAGMENT_CHANGE; default: @@ -533,40 +530,81 @@ public class AppTransitionController { * * @return {@code true} if the transition is overridden. */ - @VisibleForTesting - boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit, + private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit, ArraySet<Integer> activityTypes) { final ArrayList<WindowContainer> allWindows = new ArrayList<>(); allWindows.addAll(mDisplayContent.mClosingApps); allWindows.addAll(mDisplayContent.mOpeningApps); allWindows.addAll(mDisplayContent.mChangingContainers); - // Find the common TaskFragmentOrganizer of all windows. - ITaskFragmentOrganizer organizer = null; + // It should only animated by the organizer if all windows are below the same leaf Task. + Task leafTask = null; for (int i = allWindows.size() - 1; i >= 0; i--) { final ActivityRecord r = getAppFromContainer(allWindows.get(i)); if (r == null) { return false; } + // The activity may be a child of embedded Task, but we want to find the owner Task. + // As a result, find the organized TaskFragment first. final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment(); - final ITaskFragmentOrganizer curOrganizer = organizedTaskFragment != null - ? organizedTaskFragment.getTaskFragmentOrganizer() - : null; - if (curOrganizer == null) { - // All windows must below an organized TaskFragment. + // There are also cases where the Task contains non-embedded activity, such as launching + // split TaskFragments from a non-embedded activity. + // The hierarchy may looks like this: + // - Task + // - Activity + // - TaskFragment + // - Activity + // - TaskFragment + // - Activity + // We also want to have the organizer handle the transition for such case. + final Task task = organizedTaskFragment != null + ? organizedTaskFragment.getTask() + : r.getTask(); + if (task == null) { + return false; + } + // We don't want the organizer to handle transition of other non-embedded Task. + if (leafTask != null && leafTask != task) { + return false; + } + final ActivityRecord rootActivity = task.getRootActivity(); + // We don't want the organizer to handle transition when the whole app is closing. + if (rootActivity == null) { return false; } - if (organizer == null) { - organizer = curOrganizer; - } else if (!organizer.asBinder().equals(curOrganizer.asBinder())) { - // They must be controlled by the same organizer. + // We don't want the organizer to handle transition of non-embedded activity of other + // app. + if (r.getUid() != rootActivity.getUid() && !r.isEmbedded()) { return false; } + leafTask = task; + } + if (leafTask == null) { + return false; + } + + // We don't support remote animation for Task with multiple TaskFragmentOrganizers. + final ITaskFragmentOrganizer[] organizer = new ITaskFragmentOrganizer[1]; + final boolean hasMultipleOrganizers = leafTask.forAllLeafTaskFragments(taskFragment -> { + final ITaskFragmentOrganizer tfOrganizer = taskFragment.getTaskFragmentOrganizer(); + if (tfOrganizer == null) { + return false; + } + if (organizer[0] != null && !organizer[0].asBinder().equals(tfOrganizer.asBinder())) { + return true; + } + organizer[0] = tfOrganizer; + return false; + }); + if (hasMultipleOrganizers) { + ProtoLog.e(WM_DEBUG_APP_TRANSITIONS, "We don't support remote animation for" + + " Task with multiple TaskFragmentOrganizers."); + return false; } - final RemoteAnimationDefinition definition = organizer != null + final RemoteAnimationDefinition definition = organizer[0] != null ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController - .getRemoteAnimationDefinition(organizer) + .getRemoteAnimationDefinition(organizer[0]) : null; final RemoteAnimationAdapter adapter = definition != null ? definition.getAdapter(transit, activityTypes) diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index df973d86c7fa..ccfb174e3d16 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -3144,6 +3144,7 @@ public class DisplayPolicy { pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn); pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars="); pw.println(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars()); + mSystemGestures.dump(pw, prefix); pw.print(prefix); pw.println("Looper state:"); mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " "); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 526ccb0f374b..34e81498b1c3 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -442,7 +442,9 @@ public class DisplayRotation { return false; } - if (mDisplayContent.mFixedRotationTransitionListener + final RecentsAnimationController recentsAnimController = + mService.getRecentsAnimationController(); + if (recentsAnimController != null && mDisplayContent.mFixedRotationTransitionListener .isTopFixedOrientationRecentsAnimating() // If screen is off or the device is going to sleep, then still allow to update. && mService.mPolicy.okToAnimate(false /* ignoreScreenOn */)) { @@ -450,6 +452,7 @@ public class DisplayRotation { // In order to ignore its requested orientation to avoid a sensor led rotation (e.g // user rotating the device while the recents animation is running), we ignore // rotation update while the animation is running. + recentsAnimController.setCheckRotationAfterCleanup(); return false; } } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 1bc1d46a4230..1e7b676fbfe4 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -48,6 +48,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.LOGTAG_INPUT_FOCUS; +import static java.lang.Integer.MAX_VALUE; + import android.annotation.Nullable; import android.graphics.Rect; import android.graphics.Region; @@ -581,10 +583,11 @@ final class InputMonitor { if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) { if (recentsAnimationController.updateInputConsumerForApp( mRecentsAnimationInputConsumer.mWindowHandle)) { - final WindowState highestLayerWindow = - recentsAnimationController.getHighestLayerWindow(); - if (highestLayerWindow != null) { - mRecentsAnimationInputConsumer.show(mInputTransaction, highestLayerWindow); + final DisplayArea targetDA = + recentsAnimationController.getTargetAppDisplayArea(); + if (targetDA != null) { + mRecentsAnimationInputConsumer.reparent(mInputTransaction, targetDA); + mRecentsAnimationInputConsumer.show(mInputTransaction, MAX_VALUE - 1); mAddRecentsAnimationInputConsumerHandle = false; } } @@ -597,7 +600,7 @@ final class InputMonitor { rootTask.getSurfaceControl()); // We set the layer to z=MAX-1 so that it's always on top. mPipInputConsumer.reparent(mInputTransaction, rootTask); - mPipInputConsumer.show(mInputTransaction, Integer.MAX_VALUE - 1); + mPipInputConsumer.show(mInputTransaction, MAX_VALUE - 1); mAddPipInputConsumerHandle = false; } } diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index 45411a946f55..4b98013a99cc 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -36,6 +36,7 @@ import android.view.WindowManager; import com.android.server.UiThread; +import java.util.function.IntConsumer; import java.util.function.Supplier; /** @@ -70,7 +71,7 @@ public class Letterbox { private final LetterboxSurface mFullWindowSurface = new LetterboxSurface("fullWindow"); private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom }; // Reachability gestures. - private final Runnable mDoubleTapCallback; + private final IntConsumer mDoubleTapCallback; /** * Constructs a Letterbox. @@ -84,7 +85,7 @@ public class Letterbox { Supplier<Boolean> hasWallpaperBackgroundSupplier, Supplier<Integer> blurRadiusSupplier, Supplier<Float> darkScrimAlphaSupplier, - Runnable doubleTapCallback) { + IntConsumer doubleTapCallback) { mSurfaceControlFactory = surfaceControlFactory; mTransactionFactory = transactionFactory; mAreCornersRounded = areCornersRounded; @@ -262,7 +263,7 @@ public class Letterbox { @Override public boolean onDoubleTapEvent(MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_UP) { - mDoubleTapCallback.run(); + mDoubleTapCallback.accept((int) e.getX()); return true; } return false; diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 72fbfcc2959e..cbb473c10c6d 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -54,6 +54,27 @@ final class LetterboxConfiguration { /** Using wallpaper as a background which can be blurred or dimmed with dark scrim. */ static final int LETTERBOX_BACKGROUND_WALLPAPER = 3; + /** + * Enum for Letterbox reachability position types. + * + * <p>Order from left to right is important since it's used in {@link + * #movePositionForReachabilityToNextRightStop} and {@link + * #movePositionForReachabilityToNextLeftStop}. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({LETTERBOX_REACHABILITY_POSITION_LEFT, LETTERBOX_REACHABILITY_POSITION_CENTER, + LETTERBOX_REACHABILITY_POSITION_RIGHT}) + @interface LetterboxReachabilityPosition {}; + + /** Letterboxed app window is aligned to the left side. */ + static final int LETTERBOX_REACHABILITY_POSITION_LEFT = 0; + + /** Letterboxed app window is positioned in the horizontal center. */ + static final int LETTERBOX_REACHABILITY_POSITION_CENTER = 1; + + /** Letterboxed app window is aligned to the right side. */ + static final int LETTERBOX_REACHABILITY_POSITION_RIGHT = 2; + final Context mContext; // Aspect ratio of letterbox for fixed orientation, values <= @@ -85,25 +106,25 @@ final class LetterboxConfiguration { // side of the screen and 1.0 to the right side. private float mLetterboxHorizontalPositionMultiplier; - // Default horizontal position of a center of the letterboxed app window when reachability is - // enabled and an app is fullscreen in landscape device orientatio. 0 corresponds to the left - // side of the screen and 1.0 to the right side. - // It is used as a starting point for mLetterboxHorizontalMultiplierForReachability. - private float mDefaultPositionMultiplierForReachability; + // Default horizontal position the letterboxed app window when reachability is enabled and + // an app is fullscreen in landscape device orientatio. + // It is used as a starting point for mLetterboxPositionForReachability. + @LetterboxReachabilityPosition + private int mDefaultPositionForReachability; // Whether reachability repositioning is allowed for letterboxed fullscreen apps in landscape // device orientation. private boolean mIsReachabilityEnabled; - // Horizontal position of a center of the letterboxed app window. 0 corresponds to - // the left side of the screen and 1 to the right side. Keep it global to prevent - // "jumps" when switching between letterboxed apps. It's updated to reposition the app - // window in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). - // Used in LetterboxUiController#getHorizontalPositionMultiplier which is called from + // Horizontal position of a center of the letterboxed app window which is global to prevent + // "jumps" when switching between letterboxed apps. It's updated to reposition the app window + // in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in + // LetterboxUiController#getHorizontalPositionMultiplier which is called from // ActivityRecord#updateResolvedBoundsHorizontalPosition. // TODO(b/199426138): Global reachability setting causes a jump when resuming an app from // Overview after changing position in another app. - private volatile float mLetterboxHorizontalMultiplierForReachability; + @LetterboxReachabilityPosition + private volatile int mLetterboxPositionForReachability; LetterboxConfiguration(Context systemUiContext) { mContext = systemUiContext; @@ -120,9 +141,8 @@ final class LetterboxConfiguration { R.dimen.config_letterboxHorizontalPositionMultiplier); mIsReachabilityEnabled = mContext.getResources().getBoolean( R.bool.config_letterboxIsReachabilityEnabled); - mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat( - R.dimen.config_letterboxDefaultPositionMultiplierForReachability); - mLetterboxHorizontalMultiplierForReachability = mDefaultPositionMultiplierForReachability; + mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext); + mLetterboxPositionForReachability = mDefaultPositionForReachability; } /** @@ -395,58 +415,90 @@ final class LetterboxConfiguration { } /* - * Gets default horizontal position of a center of the letterboxed app window when reachability - * is enabled specified in {@link - * R.dimen.config_letterboxDefaultPositionMultiplierForReachability} or via an ADB command. - * 0 corresponds to the left side of the screen and 1 to the right side. The returned value is - * >= 0.0 and <= 1.0. + * Gets default horizontal position of the letterboxed app window when reachability is enabled. + * Specified in {@link R.integer.config_letterboxDefaultPositionForReachability} or via an ADB + * command. */ - float getDefaultPositionMultiplierForReachability() { - return (mDefaultPositionMultiplierForReachability < 0.0f - || mDefaultPositionMultiplierForReachability > 1.0f) - // Default to a right position if invalid value is provided. - ? 1.0f : mDefaultPositionMultiplierForReachability; + @LetterboxReachabilityPosition + int getDefaultPositionForReachability() { + return mDefaultPositionForReachability; } /** - * Overrides default horizontal position of a center of the letterboxed app window when - * reachability is enabled. If given value < 0.0 or > 1.0, then it and a value of {@link - * R.dimen.config_letterboxDefaultPositionMultiplierForReachability} are ignored and the right - * position (1.0) is used. + * Overrides default horizonal position of the letterboxed app window when reachability + * is enabled. */ - void setDefaultPositionMultiplierForReachability(float multiplier) { - mDefaultPositionMultiplierForReachability = multiplier; + void setDefaultPositionForReachability(@LetterboxReachabilityPosition int position) { + mDefaultPositionForReachability = position; } /** - * Resets default horizontal position of a center of the letterboxed app window when - * reachability is enabled to {@link - * R.dimen.config_letterboxDefaultPositionMultiplierForReachability}. + * Resets default horizontal position of the letterboxed app window when reachability is + * enabled to {@link R.integer.config_letterboxDefaultPositionForReachability}. */ - void resetDefaultPositionMultiplierForReachability() { - mDefaultPositionMultiplierForReachability = mContext.getResources().getFloat( - R.dimen.config_letterboxDefaultPositionMultiplierForReachability); + void resetDefaultPositionForReachability() { + mDefaultPositionForReachability = readLetterboxReachabilityPositionFromConfig(mContext); + } + + @LetterboxReachabilityPosition + private static int readLetterboxReachabilityPositionFromConfig(Context context) { + int position = context.getResources().getInteger( + R.integer.config_letterboxDefaultPositionForReachability); + return position == LETTERBOX_REACHABILITY_POSITION_LEFT + || position == LETTERBOX_REACHABILITY_POSITION_CENTER + || position == LETTERBOX_REACHABILITY_POSITION_RIGHT + ? position : LETTERBOX_REACHABILITY_POSITION_CENTER; } /* * Gets horizontal position of a center of the letterboxed app window when reachability * is enabled specified. 0 corresponds to the left side of the screen and 1 to the right side. * - * <p>The position multiplier is changed to a symmetrical value computed as (1 - current - * multiplier) after each double tap in the letterbox area. + * <p>The position multiplier is changed after each double tap in the letterbox area. */ float getHorizontalMultiplierForReachability() { - return mLetterboxHorizontalMultiplierForReachability; + switch (mLetterboxPositionForReachability) { + case LETTERBOX_REACHABILITY_POSITION_LEFT: + return 0.0f; + case LETTERBOX_REACHABILITY_POSITION_CENTER: + return 0.5f; + case LETTERBOX_REACHABILITY_POSITION_RIGHT: + return 1.0f; + default: + throw new AssertionError( + "Unexpected letterbox position type: " + mLetterboxPositionForReachability); + } + } + + /** Returns a string representing the given {@link LetterboxReachabilityPosition}. */ + static String letterboxReachabilityPositionToString( + @LetterboxReachabilityPosition int position) { + switch (position) { + case LETTERBOX_REACHABILITY_POSITION_LEFT: + return "LETTERBOX_REACHABILITY_POSITION_LEFT"; + case LETTERBOX_REACHABILITY_POSITION_CENTER: + return "LETTERBOX_REACHABILITY_POSITION_CENTER"; + case LETTERBOX_REACHABILITY_POSITION_RIGHT: + return "LETTERBOX_REACHABILITY_POSITION_RIGHT"; + default: + throw new AssertionError( + "Unexpected letterbox position type: " + position); + } + } + + /** + * Changes letterbox position for reachability to the next available one on the right side. + */ + void movePositionForReachabilityToNextRightStop() { + mLetterboxPositionForReachability = Math.min( + mLetterboxPositionForReachability + 1, LETTERBOX_REACHABILITY_POSITION_RIGHT); } /** - * Changes horizontal position of a center of the letterboxed app window to the opposite - * (1 - current multiplier) when reachability is enabled specified. 0 corresponds to the left - * side of the screen and 1 to the right side. + * Changes letterbox position for reachability to the next available one on the left side. */ - void flipHorizontalMultiplierForReachability() { - mLetterboxHorizontalMultiplierForReachability = - 1.0f - mLetterboxHorizontalMultiplierForReachability; + void movePositionForReachabilityToNextLeftStop() { + mLetterboxPositionForReachability = Math.max(mLetterboxPositionForReachability - 1, 0); } } diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index cf2afc93c419..7d073573835f 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -65,6 +65,10 @@ final class LetterboxUiController { private final LetterboxConfiguration mLetterboxConfiguration; private final ActivityRecord mActivityRecord; + // Taskbar expanded height. Used to determine whether to crop an app window to display rounded + // corners above the taskbar. + private float mExpandedTaskBarHeight; + private boolean mShowWallpaperForLetterboxBackground; @Nullable @@ -76,6 +80,8 @@ final class LetterboxUiController { // is created in its constructor. It shouldn't be used in this constructor but it's safe // to use it after since controller is only used in ActivityRecord. mActivityRecord = activityRecord; + mExpandedTaskBarHeight = + getResources().getDimensionPixelSize(R.dimen.taskbar_frame_height); } /** Cleans up {@link Letterbox} if it exists.*/ @@ -204,12 +210,23 @@ final class LetterboxUiController { return mActivityRecord.mWmService.mContext.getResources(); } - private void handleDoubleTap() { + private void handleDoubleTap(int x) { if (!isReachabilityEnabled() || mActivityRecord.isInTransition()) { return; } - mLetterboxConfiguration.flipHorizontalMultiplierForReachability(); + if (mLetterbox.getInnerFrame().left <= x && mLetterbox.getInnerFrame().right >= x) { + // Only react to clicks at the sides of the letterboxed app window. + return; + } + + if (mLetterbox.getInnerFrame().left > x) { + // Moving to the next stop on the left side of the app window: right > center > left. + mLetterboxConfiguration.movePositionForReachabilityToNextLeftStop(); + } else if (mLetterbox.getInnerFrame().right < x) { + // Moving to the next stop on the right side of the app window: left > center > right. + mLetterboxConfiguration.movePositionForReachabilityToNextRightStop(); + } // TODO(197549949): Add animation for transition. mActivityRecord.recomputeConfiguration(); @@ -314,12 +331,27 @@ final class LetterboxUiController { final InsetsSource taskbarInsetsSource = insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR); - Rect cropBounds = new Rect(mActivityRecord.getBounds()); - // Activity bounds are in screen coordinates while (0,0) for activity's surface control - // is at the top left corner of an app window so offsetting bounds accordingly. - cropBounds.offsetTo(0, 0); - // Rounded cornerners should be displayed above the taskbar. - cropBounds.bottom = Math.min(cropBounds.bottom, taskbarInsetsSource.getFrame().top); + Rect cropBounds = null; + + // Rounded corners should be displayed above the taskbar. When taskbar is hidden, + // an insets frame is equal to a navigation bar which shouldn't affect position of + // rounded corners since apps are expected to handle navigation bar inset. + // This condition checks whether the taskbar is visible. + if (taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) { + cropBounds = new Rect(mActivityRecord.getBounds()); + // Activity bounds are in screen coordinates while (0,0) for activity's surface + // control is at the top left corner of an app window so offsetting bounds + // accordingly. + cropBounds.offsetTo(0, 0); + // Rounded cornerners should be displayed above the taskbar. + cropBounds.bottom = + Math.min(cropBounds.bottom, taskbarInsetsSource.getFrame().top); + if (mActivityRecord.inSizeCompatMode() + && mActivityRecord.getSizeCompatScale() < 1.0f) { + cropBounds.scale(1.0f / mActivityRecord.getSizeCompatScale()); + } + } + transaction .setWindowCrop(windowSurface, cropBounds) .setCornerRadius(windowSurface, getRoundedCorners(insetsState)); diff --git a/services/core/java/com/android/server/wm/PackageConfigPersister.java b/services/core/java/com/android/server/wm/PackageConfigPersister.java index 52eea4d3d6e1..081a53e7bd05 100644 --- a/services/core/java/com/android/server/wm/PackageConfigPersister.java +++ b/services/core/java/com/android/server/wm/PackageConfigPersister.java @@ -272,6 +272,24 @@ public class PackageConfigPersister { } } + /** + * Retrieves and returns application configuration from persisted records if it exists, else + * returns null. + */ + ActivityTaskManagerInternal.PackageConfig findPackageConfiguration(String packageName, + int userId) { + synchronized (mLock) { + PackageConfigRecord packageConfigRecord = findRecord(mModified, packageName, userId); + if (packageConfigRecord == null) { + Slog.w(TAG, "App-specific configuration not found for packageName: " + packageName + + " and userId: " + userId); + return null; + } + return new ActivityTaskManagerInternal.PackageConfig( + packageConfigRecord.mNightMode, packageConfigRecord.mLocales); + } + } + // store a changed data so we don't need to get the process static class PackageConfigRecord { final String mName; diff --git a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java index 960250544299..8bbcf1f9c029 100644 --- a/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java +++ b/services/core/java/com/android/server/wm/PackageConfigurationUpdaterImpl.java @@ -16,24 +16,38 @@ package com.android.server.wm; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.LocaleList; +import android.util.ArraySet; import android.util.Slog; +import java.util.Optional; + /** * An implementation of {@link ActivityTaskManagerInternal.PackageConfigurationUpdater}. */ final class PackageConfigurationUpdaterImpl implements ActivityTaskManagerInternal.PackageConfigurationUpdater { private static final String TAG = "PackageConfigurationUpdaterImpl"; - private final int mPid; + private final Optional<Integer> mPid; private Integer mNightMode; private LocaleList mLocales; + private String mPackageName; + private int mUserId; private ActivityTaskManagerService mAtm; PackageConfigurationUpdaterImpl(int pid, ActivityTaskManagerService atm) { - mPid = pid; + mPid = Optional.of(pid); + mAtm = atm; + } + + PackageConfigurationUpdaterImpl(String packageName, int userId, + ActivityTaskManagerService atm) { + mPackageName = packageName; + mUserId = userId; mAtm = atm; + mPid = Optional.empty(); } @Override @@ -59,16 +73,29 @@ final class PackageConfigurationUpdaterImpl implements synchronized (mAtm.mGlobalLock) { final long ident = Binder.clearCallingIdentity(); try { - final WindowProcessController wpc = mAtm.mProcessMap.getProcess(mPid); - if (wpc == null) { - Slog.w(TAG, "Override application configuration: cannot find pid " + mPid); - return; + final int uid; + if (mPid.isPresent()) { + WindowProcessController wpc = mAtm.mProcessMap.getProcess(mPid.get()); + if (wpc == null) { + Slog.w(TAG, "commit: Override application configuration failed: " + + "cannot find pid " + mPid); + return; + } + uid = wpc.mUid; + mUserId = wpc.mUserId; + mPackageName = wpc.mInfo.packageName; + } else { + uid = mAtm.getPackageManagerInternalLocked().getPackageUid(mPackageName, + /* flags = */ PackageManager.MATCH_ALL, mUserId); + if (uid < 0) { + Slog.w(TAG, "commit: update of application configuration failed: " + + "userId or packageName not valid " + mUserId); + return; + } } - LocaleList localesOverride = LocaleOverlayHelper.combineLocalesIfOverlayExists( - mLocales, mAtm.getGlobalConfiguration().getLocales()); - wpc.applyAppSpecificConfig(mNightMode, localesOverride); - wpc.updateAppSpecificSettingsForAllActivities(mNightMode, localesOverride); - mAtm.mPackageConfigPersister.updateFromImpl(wpc.mName, wpc.mUserId, this); + updateConfig(uid, mPackageName); + mAtm.mPackageConfigPersister.updateFromImpl(mPackageName, mUserId, this); + } finally { Binder.restoreCallingIdentity(ident); } @@ -76,6 +103,19 @@ final class PackageConfigurationUpdaterImpl implements } } + private void updateConfig(int uid, String packageName) { + final ArraySet<WindowProcessController> processes = mAtm.mProcessMap.getProcesses(uid); + if (processes == null) return; + for (int i = processes.size() - 1; i >= 0; i--) { + final WindowProcessController wpc = processes.valueAt(i); + if (!wpc.mInfo.packageName.equals(packageName)) continue; + LocaleList localesOverride = LocaleOverlayHelper.combineLocalesIfOverlayExists( + mLocales, mAtm.getGlobalConfiguration().getLocales()); + wpc.applyAppSpecificConfig(mNightMode, localesOverride); + wpc.updateAppSpecificSettingsForAllActivities(mNightMode, localesOverride); + } + } + Integer getNightMode() { return mNightMode; } diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index ba85c9800e56..a663c62b40e5 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -123,6 +123,7 @@ public class RecentsAnimationController implements DeathRecipient { private final int mDisplayId; private boolean mWillFinishToHome = false; private final Runnable mFailsafeRunnable = this::onFailsafe; + private Runnable mCheckRotationAfterCleanup; // The recents component app token that is shown behind the visibile tasks private ActivityRecord mTargetActivityRecord; @@ -921,6 +922,24 @@ public class RecentsAnimationController implements DeathRecipient { } /** + * If the display rotation change is ignored while recents animation is running, make sure that + * the pending rotation change will be applied after the animation finishes. + */ + void setCheckRotationAfterCleanup() { + if (mCheckRotationAfterCleanup != null) return; + mCheckRotationAfterCleanup = () -> { + synchronized (mService.mGlobalLock) { + if (mDisplayContent.getDisplayRotation() + .updateRotationAndSendNewConfigIfChanged()) { + if (mTargetActivityRecord != null) { + mTargetActivityRecord.finishFixedRotationTransform(); + } + } + } + }; + } + + /** * @return Whether we should defer the cancel from a root task order change until the next app * transition. */ @@ -1007,6 +1026,10 @@ public class RecentsAnimationController implements DeathRecipient { if (mStatusBar != null) { mStatusBar.onRecentsAnimationStateChanged(false /* running */); } + if (mCheckRotationAfterCleanup != null) { + mService.mH.post(mCheckRotationAfterCleanup); + mCheckRotationAfterCleanup = null; + } } void scheduleFailsafe() { @@ -1102,21 +1125,11 @@ public class RecentsAnimationController implements DeathRecipient { return mTargetActivityRecord.findMainWindow(); } - /** - * Returns the window with the highest layer, or null if none is found. - */ - public WindowState getHighestLayerWindow() { - int highestLayer = Integer.MIN_VALUE; - Task highestLayerTask = null; - for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { - TaskAnimationAdapter adapter = mPendingAnimations.get(i); - int layer = adapter.mTask.getPrefixOrderIndex(); - if (layer > highestLayer) { - highestLayer = layer; - highestLayerTask = adapter.mTask; - } + DisplayArea getTargetAppDisplayArea() { + if (mTargetActivityRecord == null) { + return null; } - return highestLayerTask.getTopMostActivity().getTopChild(); + return mTargetActivityRecord.getDisplayArea(); } boolean isAnimatingTask(Task task) { diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java index 9c4f6f574487..89986cefb207 100644 --- a/services/core/java/com/android/server/wm/SurfaceFreezer.java +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -72,8 +72,11 @@ class SurfaceFreezer { * * @param startBounds The original bounds (on screen) of the surface we are snapshotting. * @param relativePosition The related position of the snapshot surface to its parent. + * @param freezeTarget The surface to take snapshot from. If {@code null}, we will take a + * snapshot from the {@link #mAnimatable} surface. */ - void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition) { + void freeze(SurfaceControl.Transaction t, Rect startBounds, Point relativePosition, + @Nullable SurfaceControl freezeTarget) { mFreezeBounds.set(startBounds); mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(), @@ -82,7 +85,7 @@ class SurfaceFreezer { mWmService.mTransactionFactory); mAnimatable.onAnimationLeashCreated(t, mLeash); - SurfaceControl freezeTarget = mAnimatable.getFreezeSnapshotTarget(); + freezeTarget = freezeTarget != null ? freezeTarget : mAnimatable.getFreezeSnapshotTarget(); if (freezeTarget != null) { SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = createSnapshotBuffer( freezeTarget, startBounds); diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java index 513b1b715a27..658f4efbdb2f 100644 --- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java +++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java @@ -16,6 +16,12 @@ package com.android.server.wm; +import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM; +import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; +import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT; +import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; + +import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; @@ -33,6 +39,8 @@ import android.view.MotionEvent; import android.view.WindowManagerPolicyConstants.PointerEventListener; import android.widget.OverScroller; +import java.io.PrintWriter; + /** * Listens for system-wide input gestures, firing callbacks when detected. * @hide @@ -54,7 +62,8 @@ class SystemGesturesPointerEventListener implements PointerEventListener { private final Context mContext; private final Handler mHandler; private int mDisplayCutoutTouchableRegionSize; - private int mSwipeStartThreshold; + // The thresholds for each edge of the display + private final Rect mSwipeStartThreshold = new Rect(); private int mSwipeDistanceThreshold; private final Callbacks mCallbacks; private final int[] mDownPointerId = new int[MAX_TRACKED_POINTERS]; @@ -66,7 +75,6 @@ class SystemGesturesPointerEventListener implements PointerEventListener { int screenHeight; int screenWidth; - private DisplayInfo mTmpDisplayInfo = new DisplayInfo(); private int mDownPointers; private boolean mSwipeFireable; private boolean mDebugFireable; @@ -88,27 +96,41 @@ class SystemGesturesPointerEventListener implements PointerEventListener { void onConfigurationChanged() { final Resources r = mContext.getResources(); + final int defaultThreshold = r.getDimensionPixelSize( + com.android.internal.R.dimen.system_gestures_start_threshold); + mSwipeStartThreshold.set(defaultThreshold, defaultThreshold, defaultThreshold, + defaultThreshold); + mSwipeDistanceThreshold = defaultThreshold; + final Display display = DisplayManagerGlobal.getInstance() .getRealDisplay(Display.DEFAULT_DISPLAY); - display.getDisplayInfo(mTmpDisplayInfo); - mSwipeStartThreshold = mTmpDisplayInfo.logicalWidth > mTmpDisplayInfo.logicalHeight - ? r.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height_landscape) - : r.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height_portrait); - final DisplayCutout displayCutout = display.getCutout(); if (displayCutout != null) { - final Rect bounds = displayCutout.getBoundingRectTop(); - if (!bounds.isEmpty()) { - // Expand swipe start threshold such that we can catch touches that just start below - // the notch area - mDisplayCutoutTouchableRegionSize = r.getDimensionPixelSize( - com.android.internal.R.dimen.display_cutout_touchable_region_size); - mSwipeStartThreshold += mDisplayCutoutTouchableRegionSize; + // Expand swipe start threshold such that we can catch touches that just start beyond + // the notch area + mDisplayCutoutTouchableRegionSize = r.getDimensionPixelSize( + com.android.internal.R.dimen.display_cutout_touchable_region_size); + final Rect[] bounds = displayCutout.getBoundingRectsAll(); + if (bounds[BOUNDS_POSITION_LEFT] != null) { + mSwipeStartThreshold.left = Math.max(mSwipeStartThreshold.left, + bounds[BOUNDS_POSITION_LEFT].width() + mDisplayCutoutTouchableRegionSize); + } + if (bounds[BOUNDS_POSITION_TOP] != null) { + mSwipeStartThreshold.top = Math.max(mSwipeStartThreshold.top, + bounds[BOUNDS_POSITION_TOP].height() + mDisplayCutoutTouchableRegionSize); + } + if (bounds[BOUNDS_POSITION_RIGHT] != null) { + mSwipeStartThreshold.right = Math.max(mSwipeStartThreshold.right, + bounds[BOUNDS_POSITION_RIGHT].width() + mDisplayCutoutTouchableRegionSize); + } + if (bounds[BOUNDS_POSITION_BOTTOM] != null) { + mSwipeStartThreshold.bottom = Math.max(mSwipeStartThreshold.bottom, + bounds[BOUNDS_POSITION_BOTTOM].height() + + mDisplayCutoutTouchableRegionSize); } } - mSwipeDistanceThreshold = mSwipeStartThreshold; if (DEBUG) Slog.d(TAG, "mSwipeStartThreshold=" + mSwipeStartThreshold - + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold); + + " mSwipeDistanceThreshold=" + mSwipeDistanceThreshold); } private static <T> T checkNull(String name, T arg) { @@ -275,22 +297,22 @@ class SystemGesturesPointerEventListener implements PointerEventListener { final long elapsed = time - mDownTime[i]; if (DEBUG) Slog.d(TAG, "pointer " + mDownPointerId[i] + " moved (" + fromX + "->" + x + "," + fromY + "->" + y + ") in " + elapsed); - if (fromY <= mSwipeStartThreshold + if (fromY <= mSwipeStartThreshold.top && y > fromY + mSwipeDistanceThreshold && elapsed < SWIPE_TIMEOUT_MS) { return SWIPE_FROM_TOP; } - if (fromY >= screenHeight - mSwipeStartThreshold + if (fromY >= screenHeight - mSwipeStartThreshold.bottom && y < fromY - mSwipeDistanceThreshold && elapsed < SWIPE_TIMEOUT_MS) { return SWIPE_FROM_BOTTOM; } - if (fromX >= screenWidth - mSwipeStartThreshold + if (fromX >= screenWidth - mSwipeStartThreshold.right && x < fromX - mSwipeDistanceThreshold && elapsed < SWIPE_TIMEOUT_MS) { return SWIPE_FROM_RIGHT; } - if (fromX <= mSwipeStartThreshold + if (fromX <= mSwipeStartThreshold.left && x > fromX + mSwipeDistanceThreshold && elapsed < SWIPE_TIMEOUT_MS) { return SWIPE_FROM_LEFT; @@ -298,6 +320,15 @@ class SystemGesturesPointerEventListener implements PointerEventListener { return SWIPE_NONE; } + public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { + final String inner = prefix + " "; + pw.println(prefix + TAG + ":"); + pw.print(inner); pw.print("mDisplayCutoutTouchableRegionSize="); + pw.println(mDisplayCutoutTouchableRegionSize); + pw.print(inner); pw.print("mSwipeStartThreshold="); pw.println(mSwipeStartThreshold); + pw.print(inner); pw.print("mSwipeDistanceThreshold="); pw.println(mSwipeDistanceThreshold); + } + private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener { private OverScroller mOverscroller; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index cad65071c02b..0819549ad8df 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -480,7 +480,6 @@ class Task extends TaskFragment { private Dimmer mDimmer = new Dimmer(this); private final Rect mTmpDimBoundsRect = new Rect(); - private final Point mLastSurfaceSize = new Point(); /** @see #setCanAffectSystemUiFlags */ private boolean mCanAffectSystemUiFlags = true; diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index a257e902dc46..66f2dbc8ec09 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1336,12 +1336,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) { final Task launchRootTask = mLaunchRootTasks.get(i).task; - // Return the focusable root task for improving the UX with staged split screen. final TaskFragment adjacentTaskFragment = launchRootTask != null ? launchRootTask.getAdjacentTaskFragment() : null; final Task adjacentRootTask = adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null; - if (adjacentRootTask != null && adjacentRootTask.isFocusedRootTaskOnDisplay()) { + if (sourceTask != null && sourceTask.getRootTask() == adjacentRootTask) { return adjacentRootTask; } else { return launchRootTask; diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 97c3e9aa1bfd..44b22c643347 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -240,6 +240,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { */ private int mTaskFragmentOrganizerPid = ActivityRecord.INVALID_PID; + final Point mLastSurfaceSize = new Point(); + private final Rect mTmpInsets = new Rect(); private final Rect mTmpBounds = new Rect(); private final Rect mTmpFullBounds = new Rect(); @@ -1392,7 +1394,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev); mPausingActivity = prev; mLastPausedActivity = prev; - if (prev.isNoHistory() && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) { + if (!prev.finishing && prev.isNoHistory() + && !mTaskSupervisor.mNoHistoryActivities.contains(prev)) { mTaskSupervisor.mNoHistoryActivities.add(prev); } prev.setState(PAUSING, "startPausingLocked"); @@ -1654,6 +1657,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } + @Override void onChildPositionChanged(WindowContainer child) { super.onChildPositionChanged(child); @@ -2049,14 +2053,58 @@ class TaskFragment extends WindowContainer<WindowContainer> { if (shouldStartChangeTransition(mTmpPrevBounds)) { initializeChangeTransition(mTmpPrevBounds); } else if (mTaskFragmentOrganizer != null) { - // Update the surface position here instead of in the organizer so that we can make sure + // Update the surface here instead of in the organizer so that we can make sure // it can be synced with the surface freezer. - updateSurfacePosition(getSyncTransaction()); + final SurfaceControl.Transaction t = getSyncTransaction(); + updateSurfacePosition(t); + updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */); } sendTaskFragmentInfoChanged(); } + /** Updates the surface size so that the sub windows cannot be shown out of bounds. */ + private void updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t, + boolean forceUpdate) { + if (mTaskFragmentOrganizer == null) { + // We only want to update for organized TaskFragment. Task will handle itself. + return; + } + if (mSurfaceControl == null || mSurfaceAnimator.hasLeash() || mSurfaceFreezer.hasLeash()) { + return; + } + + final Rect bounds = getBounds(); + final int width = bounds.width(); + final int height = bounds.height(); + if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { + return; + } + t.setWindowCrop(mSurfaceControl, width, height); + mLastSurfaceSize.set(width, height); + } + + @Override + public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) { + super.onAnimationLeashCreated(t, leash); + // Reset surface bounds for animation. It will be taken care by the animation leash, and + // reset again onAnimationLeashLost. + if (mTaskFragmentOrganizer != null + && (mLastSurfaceSize.x != 0 || mLastSurfaceSize.y != 0)) { + t.setWindowCrop(mSurfaceControl, 0, 0); + mLastSurfaceSize.set(0, 0); + } + } + + @Override + public void onAnimationLeashLost(SurfaceControl.Transaction t) { + super.onAnimationLeashLost(t); + // Update the surface bounds after animation. + if (mTaskFragmentOrganizer != null) { + updateOrganizedTaskFragmentSurfaceSize(t, true /* forceUpdate */); + } + } + /** Whether we should prepare a transition for this {@link TaskFragment} bounds change. */ private boolean shouldStartChangeTransition(Rect startBounds) { if (mWmService.mDisableTransitionAnimation @@ -2075,9 +2123,14 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Override void setSurfaceControl(SurfaceControl sc) { super.setSurfaceControl(sc); - // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to - // emit the callbacks now. - sendTaskFragmentAppeared(); + if (mTaskFragmentOrganizer != null) { + final SurfaceControl.Transaction t = getSyncTransaction(); + updateSurfacePosition(t); + updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */); + // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to + // emit the callbacks now. + sendTaskFragmentAppeared(); + } } void sendTaskFragmentInfoChanged() { @@ -2099,10 +2152,6 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } - int getTaskFragmentOrganizerPid() { - return mTaskFragmentOrganizerPid; - } - /** * Returns a {@link TaskFragmentInfo} with information from this TaskFragment. Should not be * called from {@link Task}. diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 30d2a323aabe..d91165685c63 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -505,29 +505,46 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } for (int i = 0, n = mPendingTaskFragmentEvents.size(); i < n; i++) { PendingTaskFragmentEvent event = mPendingTaskFragmentEvents.get(i); - final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg; - final TaskFragment taskFragment = event.mTaskFragment; - final TaskFragmentOrganizerState state = - mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder()); - if (state == null) continue; - switch (event.mEventType) { - case PendingTaskFragmentEvent.EVENT_APPEARED: - state.onTaskFragmentAppeared(taskFragmentOrg, taskFragment); - break; - case PendingTaskFragmentEvent.EVENT_VANISHED: - state.onTaskFragmentVanished(taskFragmentOrg, taskFragment); - break; - case PendingTaskFragmentEvent.EVENT_INFO_CHANGED: - state.onTaskFragmentInfoChanged(taskFragmentOrg, taskFragment); - break; - case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED: - state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment); - break; - case PendingTaskFragmentEvent.EVENT_ERROR: - state.onTaskFragmentError(taskFragmentOrg, event.mErrorCallback, - event.mException); - } + dispatchEvent(event); } mPendingTaskFragmentEvents.clear(); } + + void dispatchPendingInfoChangedEvent(TaskFragment taskFragment) { + PendingTaskFragmentEvent event = getPendingTaskFragmentEvent(taskFragment, + PendingTaskFragmentEvent.EVENT_INFO_CHANGED); + if (event == null) { + return; + } + + dispatchEvent(event); + mPendingTaskFragmentEvents.remove(event); + } + + private void dispatchEvent(PendingTaskFragmentEvent event) { + final ITaskFragmentOrganizer taskFragmentOrg = event.mTaskFragmentOrg; + final TaskFragment taskFragment = event.mTaskFragment; + final TaskFragmentOrganizerState state = + mTaskFragmentOrganizerState.get(taskFragmentOrg.asBinder()); + if (state == null) { + return; + } + switch (event.mEventType) { + case PendingTaskFragmentEvent.EVENT_APPEARED: + state.onTaskFragmentAppeared(taskFragmentOrg, taskFragment); + break; + case PendingTaskFragmentEvent.EVENT_VANISHED: + state.onTaskFragmentVanished(taskFragmentOrg, taskFragment); + break; + case PendingTaskFragmentEvent.EVENT_INFO_CHANGED: + state.onTaskFragmentInfoChanged(taskFragmentOrg, taskFragment); + break; + case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED: + state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment); + break; + case PendingTaskFragmentEvent.EVENT_ERROR: + state.onTaskFragmentError(taskFragmentOrg, event.mErrorCallback, + event.mException); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 7a166f86f6d6..841783d6b8cd 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2621,23 +2621,27 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * For now, this will only be called for the following cases: * 1. {@link Task} is changing windowing mode between fullscreen and freeform. * 2. {@link TaskFragment} is organized and is changing window bounds. - * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. + * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. (The + * transition will happen on the {@link TaskFragment} for this case). * - * This shouldn't be called on other {@link WindowContainer} unless there is a valid use case. + * This shouldn't be called on other {@link WindowContainer} unless there is a valid + * use case. * * @param startBounds The original bounds (on screen) of the surface we are snapshotting. - * @param parentBounds The parent bounds (on screen) to calculate the animation surface - * position. + * @param freezeTarget The surface to take snapshot from. If {@code null}, we will take a + * snapshot from {@link #getFreezeSnapshotTarget()}. */ - void initializeChangeTransition(Rect startBounds, Rect parentBounds) { + void initializeChangeTransition(Rect startBounds, @Nullable SurfaceControl freezeTarget) { mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); mDisplayContent.mChangingContainers.add(this); + // Calculate the relative position in parent container. + final Rect parentBounds = getParent().getBounds(); mTmpPoint.set(startBounds.left - parentBounds.left, startBounds.top - parentBounds.top); - mSurfaceFreezer.freeze(getSyncTransaction(), startBounds, mTmpPoint); + mSurfaceFreezer.freeze(getSyncTransaction(), startBounds, mTmpPoint, freezeTarget); } void initializeChangeTransition(Rect startBounds) { - initializeChangeTransition(startBounds, getParent().getBounds()); + initializeChangeTransition(startBounds, null /* freezeTarget */); } ArraySet<WindowContainer> getAnimationSources() { @@ -3160,7 +3164,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) void updateSurfacePosition(Transaction t) { - if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) { + if (mSurfaceControl == null || mSurfaceAnimator.hasLeash() || mSurfaceFreezer.hasLeash()) { return; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7735900d6929..c77cd509ca4f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1770,17 +1770,15 @@ public class WindowManagerService extends IWindowManager.Stub final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty(); win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows); - if (type == TYPE_APPLICATION_STARTING && activity != null) { - activity.attachStartingWindow(win); - ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s", - activity, win); - } - boolean imMayMove = true; win.mToken.addWindow(win); displayPolicy.addWindowLw(win, attrs); - if (type == TYPE_INPUT_METHOD) { + if (type == TYPE_APPLICATION_STARTING && activity != null) { + activity.attachStartingWindow(win); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s", + activity, win); + } else if (type == TYPE_INPUT_METHOD) { displayContent.setInputMethodWindowLocked(win); imMayMove = false; } else if (type == TYPE_INPUT_METHOD_DIALOG) { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 47d7f030bcaa..0f8587c99958 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -23,6 +23,9 @@ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_ import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_SOLID_COLOR; import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_BACKGROUND_WALLPAPER; +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_CENTER; +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_LEFT; +import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_REACHABILITY_POSITION_RIGHT; import android.content.res.Resources.NotFoundException; import android.graphics.Color; @@ -44,6 +47,7 @@ import com.android.internal.protolog.ProtoLogImpl; import com.android.server.LocalServices; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; +import com.android.server.wm.LetterboxConfiguration.LetterboxReachabilityPosition; import java.io.IOException; import java.io.PrintWriter; @@ -787,22 +791,33 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } - private int runSetLetterboxDefaultPositionMultiplierForReachability(PrintWriter pw) + private int runSetLetterboxDefaultPositionForReachability(PrintWriter pw) throws RemoteException { - final float multiplier; + @LetterboxReachabilityPosition final int position; try { String arg = getNextArgRequired(); - multiplier = Float.parseFloat(arg); - } catch (NumberFormatException e) { - getErrPrintWriter().println("Error: bad multiplier format " + e); - return -1; + switch (arg) { + case "left": + position = LETTERBOX_REACHABILITY_POSITION_LEFT; + break; + case "center": + position = LETTERBOX_REACHABILITY_POSITION_CENTER; + break; + case "right": + position = LETTERBOX_REACHABILITY_POSITION_RIGHT; + break; + default: + getErrPrintWriter().println( + "Error: 'left', 'center' or 'right' are expected as an argument"); + return -1; + } } catch (IllegalArgumentException e) { getErrPrintWriter().println( - "Error: multiplier should be provided as an argument " + e); + "Error: 'left', 'center' or 'right' are expected as an argument" + e); return -1; } synchronized (mInternal.mGlobalLock) { - mLetterboxConfiguration.setDefaultPositionMultiplierForReachability(multiplier); + mLetterboxConfiguration.setDefaultPositionForReachability(position); } return 0; } @@ -841,8 +856,8 @@ public class WindowManagerShellCommand extends ShellCommand { case "--isReachabilityEnabled": runSetLetterboxIsReachabilityEnabled(pw); break; - case "--defaultPositionMultiplierReachability": - runSetLetterboxDefaultPositionMultiplierForReachability(pw); + case "--defaultPositionForReachability": + runSetLetterboxDefaultPositionForReachability(pw); break; default: getErrPrintWriter().println( @@ -885,8 +900,8 @@ public class WindowManagerShellCommand extends ShellCommand { case "isReachabilityEnabled": mLetterboxConfiguration.getIsReachabilityEnabled(); break; - case "defaultPositionMultiplierForReachability": - mLetterboxConfiguration.getDefaultPositionMultiplierForReachability(); + case "defaultPositionForReachability": + mLetterboxConfiguration.getDefaultPositionForReachability(); break; default: getErrPrintWriter().println( @@ -982,7 +997,7 @@ public class WindowManagerShellCommand extends ShellCommand { mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha(); mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier(); mLetterboxConfiguration.resetIsReachabilityEnabled(); - mLetterboxConfiguration.resetDefaultPositionMultiplierForReachability(); + mLetterboxConfiguration.resetDefaultPositionForReachability(); } } @@ -996,8 +1011,9 @@ public class WindowManagerShellCommand extends ShellCommand { + mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio()); pw.println("Is reachability enabled: " + mLetterboxConfiguration.getIsReachabilityEnabled()); - pw.println("Default position multiplier for reachability: " - + mLetterboxConfiguration.getDefaultPositionMultiplierForReachability()); + pw.println("Default position for reachability: " + + LetterboxConfiguration.letterboxReachabilityPositionToString( + mLetterboxConfiguration.getDefaultPositionForReachability())); pw.println("Background type: " + LetterboxConfiguration.letterboxBackgroundTypeToString( @@ -1135,11 +1151,9 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" --isReachabilityEnabled [true|1|false|0]"); pw.println(" Whether reachability repositioning is allowed for letterboxed"); pw.println(" fullscreen apps in landscape device orientation."); - pw.println(" --defaultPositionMultiplierReachability multiplier"); - pw.println(" Default horizontal position of app window center when reachability is"); - pw.println(" enabled. If multiplier < 0.0 or > 1, both it and "); - pw.println(" R.dimen.config_letterboxDefaultPositionMultiplierForReachability"); - pw.println(" are ignored and right position (1.0) is used."); + pw.println(" --defaultPositionForReachability [left|center|right]"); + pw.println(" Default horizontal position of app window when reachability is."); + pw.println(" enabled."); pw.println(" reset-letterbox-style [aspectRatio|cornerRadius|backgroundType"); pw.println(" |backgroundColor|wallpaperBlurRadius|wallpaperDarkScrimAlpha"); pw.println(" |horizontalPositionMultiplier|isReachabilityEnabled"); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 69313810fa93..781b53df998e 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -462,6 +462,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub container.onRequestedOverrideConfigurationChanged(c); } effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; + if (windowMask != 0 && container.isEmbedded()) { + // Changing bounds of the embedded TaskFragments may result in lifecycle changes. + effects |= TRANSACT_EFFECTS_LIFECYCLE; + } } if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) { if (container.setFocusable(change.getFocusable())) { diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 6eb2e8a2fd54..719d52c89209 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -264,7 +264,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } onConfigurationChanged(atm.getGlobalConfiguration()); - mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mName); + mAtm.mPackageConfigPersister.updateConfigIfNeeded(this, mUserId, mInfo.packageName); } public void setPid(int pid) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 3f99e7ddc1e4..5f9d4f5182bc 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -308,6 +308,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @NonNull WindowToken mToken; // The same object as mToken if this is an app window and null for non-app windows. ActivityRecord mActivityRecord; + /** Non-null if this is a starting window. */ + StartingData mStartingData; // mAttrs.flags is tested in animation without being locked. If the bits tested are ever // modified they will need to be locked. @@ -5483,6 +5485,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mWillReplaceWindow; } + private boolean isStartingWindowAssociatedToTask() { + return mStartingData != null && mStartingData.mAssociatedTask != null; + } + private void applyDims() { if (!mAnimatingExit && mAppDied) { mIsDimming = true; @@ -5632,7 +5638,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP outPoint.offset(-parent.mWindowFrames.mFrame.left + mTmpPoint.x, -parent.mWindowFrames.mFrame.top + mTmpPoint.y); } else if (parentWindowContainer != null) { - final Rect parentBounds = parentWindowContainer.getBounds(); + final Rect parentBounds = isStartingWindowAssociatedToTask() + ? mStartingData.mAssociatedTask.getBounds() + : parentWindowContainer.getBounds(); outPoint.offset(-parentBounds.left, -parentBounds.top); } @@ -5669,9 +5677,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } boolean needsRelativeLayeringToIme() { - // We only use the relative layering mode in split screen, as part of elevating the IME - // and windows above it's target above the docked divider. - if (!inSplitScreenWindowingMode()) { + // We use the relative layering when IME isn't attached to the app. Such as part of + // elevating the IME and windows above it's target above the docked divider in + // split-screen, or make the popupMenu to be above the IME when the parent window is the + // IME layering target in bubble/freeform mode. + if (mDisplayContent.isImeAttachedToApp()) { return false; } @@ -5715,6 +5725,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override void assignLayer(Transaction t, int layer) { + if (isStartingWindowAssociatedToTask()) { + // The starting window should cover the task. + t.setLayer(mSurfaceControl, Integer.MAX_VALUE); + return; + } // See comment in assignRelativeLayerForImeTargetChild if (needsRelativeLayeringToIme()) { getDisplayContent().assignRelativeLayerForImeTargetChild(t, this); @@ -5727,6 +5742,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return mIsDimming; } + @Override + protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) { + if (isStartingWindowAssociatedToTask()) { + // Its surface is already put in task. Don't reparent when transferring starting window + // across activities. + return; + } + super.reparentSurfaceControl(t, newParent); + } + + @Override + public SurfaceControl getAnimationLeashParent() { + if (isStartingWindowAssociatedToTask()) { + return mStartingData.mAssociatedTask.mSurfaceControl; + } + return super.getAnimationLeashParent(); + } + // TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA // then we can drop all negative layering on the windowing side and simply inherit // the default implementation here. diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c283ef07dce6..02497a4de250 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3618,6 +3618,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(); Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)); + Preconditions.checkCallAuthorization( + isCallingFromPackage(adminReceiver.getPackageName(), caller.getUid()) + || isSystemUid(caller)); synchronized (getLockObject()) { ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle); @@ -8353,7 +8356,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public boolean setDeviceOwner(ComponentName admin, String ownerName, int userId) { + public boolean setDeviceOwner(ComponentName admin, String ownerName, int userId, + boolean setProfileOwnerOnCurrentUserIfNecessary) { if (!mHasFeature) { logMissingFeatureAction("Cannot set " + ComponentName.flattenToShortString(admin) + " as device owner for user " + userId); @@ -8414,19 +8418,18 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mDeviceAdminServiceController.startServiceForOwner( admin.getPackageName(), userId, "set-device-owner"); - Slogf.i(LOG_TAG, "Device owner set: %s on user %d", admin.flattenToShortString(), - userId); + Slogf.i(LOG_TAG, "Device owner set: " + admin + " on user " + userId); - if (mInjector.userManagerIsHeadlessSystemUserMode()) { + if (setProfileOwnerOnCurrentUserIfNecessary + && mInjector.userManagerIsHeadlessSystemUserMode()) { int currentForegroundUser = getCurrentForegroundUserId(); - Slogf.i(LOG_TAG, "setDeviceOwner(): setting %s as profile owner on user %d", - admin.flattenToShortString(), currentForegroundUser); + Slogf.i(LOG_TAG, "setDeviceOwner(): setting " + admin + + " as profile owner on user " + currentForegroundUser); // Sets profile owner on current foreground user since // the human user will complete the DO setup workflow from there. - mInjector.binderWithCleanCallingIdentity(() -> manageUserUnchecked( - /* deviceOwner= */ admin, /* profileOwner= */ admin, + manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin, /* managedUser= */ currentForegroundUser, /* adminExtras= */ null, - /* showDisclaimer= */ false)); + /* showDisclaimer= */ false); } return true; } @@ -12713,74 +12716,21 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // This method is called from AM with its lock held, so don't take the DPMS lock. // b/29242568 - ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId); - if (profileOwner != null) { - return DevicePolicyManagerService.this - .createShowAdminSupportIntent(profileOwner, userId); - } - - final Pair<Integer, ComponentName> deviceOwner = - mOwners.getDeviceOwnerUserIdAndComponent(); - if (deviceOwner != null && deviceOwner.first == userId) { - return DevicePolicyManagerService.this - .createShowAdminSupportIntent(deviceOwner.second, userId); - } - - // We're not specifying the device admin because there isn't one. - if (useDefaultIfNoAdmin) { - return DevicePolicyManagerService.this.createShowAdminSupportIntent(null, userId); + if (getEnforcingAdminAndUserDetailsInternal(userId, null) != null + || useDefaultIfNoAdmin) { + return DevicePolicyManagerService.this.createShowAdminSupportIntent(userId); } return null; } @Override public Intent createUserRestrictionSupportIntent(int userId, String userRestriction) { - final long ident = mInjector.binderClearCallingIdentity(); - try { - final List<UserManager.EnforcingUser> sources = mUserManager - .getUserRestrictionSources(userRestriction, UserHandle.of(userId)); - if (sources == null || sources.isEmpty()) { - // The restriction is not enforced. - return null; - } else if (sources.size() > 1) { - // In this case, we'll show an admin support dialog that does not - // specify the admin. - // TODO(b/128928355): if this restriction is enforced by multiple DPCs, return - // the admin for the calling user. - return DevicePolicyManagerService.this.createShowAdminSupportIntent( - null, userId); - } - final UserManager.EnforcingUser enforcingUser = sources.get(0); - final int sourceType = enforcingUser.getUserRestrictionSource(); - final int enforcingUserId = enforcingUser.getUserHandle().getIdentifier(); - if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) { - // Restriction was enforced by PO - final ComponentName profileOwner = mOwners.getProfileOwnerComponent( - enforcingUserId); - if (profileOwner != null) { - return DevicePolicyManagerService.this.createShowAdminSupportIntent( - profileOwner, enforcingUserId); - } - } else if (sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { - // Restriction was enforced by DO - final Pair<Integer, ComponentName> deviceOwner = - mOwners.getDeviceOwnerUserIdAndComponent(); - if (deviceOwner != null) { - return DevicePolicyManagerService.this.createShowAdminSupportIntent( - deviceOwner.second, deviceOwner.first); - } - } else if (sourceType == UserManager.RESTRICTION_SOURCE_SYSTEM) { - /* - * In this case, the user restriction is enforced by the system. - * So we won't show an admin support intent, even if it is also - * enforced by a profile/device owner. - */ - return null; - } - } finally { - mInjector.binderRestoreCallingIdentity(ident); + Intent intent = null; + if (getEnforcingAdminAndUserDetailsInternal(userId, userRestriction) != null) { + intent = DevicePolicyManagerService.this.createShowAdminSupportIntent(userId); + intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, userRestriction); } - return null; + return intent; } @Override @@ -13075,53 +13025,153 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private Intent createShowAdminSupportIntent(ComponentName admin, int userId) { + private Intent createShowAdminSupportIntent(int userId) { // This method is called with AMS lock held, so don't take DPMS lock final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS); intent.putExtra(Intent.EXTRA_USER_ID, userId); - intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin); intent.setFlags(FLAG_ACTIVITY_NEW_TASK); return intent; } - @Override - public Intent createAdminSupportIntent(String restriction) { - Objects.requireNonNull(restriction); - final CallerIdentity caller = getCallerIdentity(); - Intent intent = null; - if (DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction) || - DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) { + /** + * @param restriction The restriction enforced by admin. It could be any user restriction or + * policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and + * {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}. + */ + private Bundle getEnforcingAdminAndUserDetailsInternal(int userId, String restriction) { + Bundle result = null; + if (restriction == null) { + ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId); + if (profileOwner != null) { + result = new Bundle(); + result.putInt(Intent.EXTRA_USER_ID, userId); + result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, + profileOwner); + return result; + } + final Pair<Integer, ComponentName> deviceOwner = + mOwners.getDeviceOwnerUserIdAndComponent(); + if (deviceOwner != null && deviceOwner.first == userId) { + result = new Bundle(); + result.putInt(Intent.EXTRA_USER_ID, userId); + result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, + deviceOwner.second); + return result; + } + } else if (DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction) + || DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) { synchronized (getLockObject()) { - final DevicePolicyData policy = getUserData(caller.getUserId()); + final DevicePolicyData policy = getUserData(userId); final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { final ActiveAdmin admin = policy.mAdminList.get(i); if ((admin.disableCamera && - DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) || - (admin.disableScreenCapture && DevicePolicyManager - .POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction))) { - intent = createShowAdminSupportIntent(admin.info.getComponent(), - caller.getUserId()); - break; + DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) + || (admin.disableScreenCapture && DevicePolicyManager + .POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction))) { + result = new Bundle(); + result.putInt(Intent.EXTRA_USER_ID, userId); + result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, + admin.info.getComponent()); + return result; } } // For the camera, a device owner on a different user can disable it globally, // so we need an additional check. - if (intent == null + if (result == null && DevicePolicyManager.POLICY_DISABLE_CAMERA.equals(restriction)) { final ActiveAdmin admin = getDeviceOwnerAdminLocked(); if (admin != null && admin.disableCamera) { - intent = createShowAdminSupportIntent(admin.info.getComponent(), - mOwners.getDeviceOwnerUserId()); + result = new Bundle(); + result.putInt(Intent.EXTRA_USER_ID, mOwners.getDeviceOwnerUserId()); + result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, + admin.info.getComponent()); + return result; } } } } else { - // if valid, |restriction| can only be a user restriction - intent = mLocalService.createUserRestrictionSupportIntent(caller.getUserId(), - restriction); + long ident = mInjector.binderClearCallingIdentity(); + try { + List<UserManager.EnforcingUser> sources = mUserManager + .getUserRestrictionSources(restriction, UserHandle.of(userId)); + if (sources == null || sources.isEmpty()) { + // The restriction is not enforced. + return null; + } else if (sources.size() > 1) { + // In this case, we'll show an admin support dialog that does not + // specify the admin. + // TODO(b/128928355): if this restriction is enforced by multiple DPCs, return + // the admin for the calling user. + result = new Bundle(); + result.putInt(Intent.EXTRA_USER_ID, userId); + return result; + } + final UserManager.EnforcingUser enforcingUser = sources.get(0); + final int sourceType = enforcingUser.getUserRestrictionSource(); + final int enforcingUserId = enforcingUser.getUserHandle().getIdentifier(); + if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) { + // Restriction was enforced by PO + final ComponentName profileOwner = mOwners.getProfileOwnerComponent( + enforcingUserId); + if (profileOwner != null) { + result = new Bundle(); + result.putInt(Intent.EXTRA_USER_ID, enforcingUserId); + result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, + profileOwner); + return result; + } + } else if (sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) { + // Restriction was enforced by DO + final Pair<Integer, ComponentName> deviceOwner = + mOwners.getDeviceOwnerUserIdAndComponent(); + if (deviceOwner != null) { + result = new Bundle(); + result.putInt(Intent.EXTRA_USER_ID, deviceOwner.first); + result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN, + deviceOwner.second); + return result; + } + } else if (sourceType == UserManager.RESTRICTION_SOURCE_SYSTEM) { + /* + * In this case, the user restriction is enforced by the system. + * So we won't show an admin support intent, even if it is also + * enforced by a profile/device owner. + */ + return null; + } + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } } - if (intent != null) { + return null; + } + + /** + * @param restriction The restriction enforced by admin. It could be any user restriction or + * policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and + * {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}. + * @return Details of admin and user which enforced the restriction for the userId. + */ + @Override + public Bundle getEnforcingAdminAndUserDetails(int userId, String restriction) { + Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity())); + return getEnforcingAdminAndUserDetailsInternal(userId, restriction); + } + + /** + * @param restriction The restriction enforced by admin. It could be any user restriction or + * policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and + * {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}. + */ + @Override + public Intent createAdminSupportIntent(String restriction) { + Objects.requireNonNull(restriction); + final CallerIdentity caller = getCallerIdentity(); + final int userId = caller.getUserId(); + Intent intent = null; + if (getEnforcingAdminAndUserDetailsInternal(userId, restriction) != null) { + intent = createShowAdminSupportIntent(userId); intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, restriction); } return intent; @@ -14079,6 +14129,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final CallerIdentity caller = getCallerIdentity(); Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)); + Preconditions.checkCallAuthorization(canManageUsers(caller)); Preconditions.checkCallAuthorization(isManagedProfile(userHandle), "You can not get organization name outside a managed profile, userId = %d", userHandle); @@ -17428,7 +17479,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // TODO(b/178187130): Directly set DO and remove the check once silent provisioning is no // longer used. if (getDeviceOwnerComponent(/* callingUserOnly= */ true) == null) { - return setDeviceOwner(adminComponent, name, userId); + return setDeviceOwner(adminComponent, name, userId, + /* setProfileOwnerOnCurrentUserIfNecessary= */ true); } return true; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java index 85fe65ca5563..e1d720ca25c8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java @@ -46,11 +46,13 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { private static final String USER_OPTION = "--user"; private static final String NAME_OPTION = "--name"; + private static final String DO_ONLY_OPTION = "--device-owner-only"; private final DevicePolicyManagerService mService; private int mUserId = UserHandle.USER_SYSTEM; private String mName = ""; private ComponentName mComponent; + private boolean mSetDoOnly; DevicePolicyManagerServiceShellCommand(DevicePolicyManagerService service) { mService = Objects.requireNonNull(service); @@ -130,8 +132,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { pw.printf(" %s [ %s <USER_ID> | current ] <COMPONENT>\n", CMD_SET_ACTIVE_ADMIN, USER_OPTION); pw.printf(" Sets the given component as active admin for an existing user.\n\n"); - pw.printf(" %s [ %s <USER_ID> | current *EXPERIMENTAL* ] [ %s <NAME> ] " - + "<COMPONENT>\n", CMD_SET_DEVICE_OWNER, USER_OPTION, NAME_OPTION); + pw.printf(" %s [ %s <USER_ID> | current *EXPERIMENTAL* ] [ %s <NAME> ] [ %s ]" + + "<COMPONENT>\n", CMD_SET_DEVICE_OWNER, USER_OPTION, NAME_OPTION, DO_ONLY_OPTION); pw.printf(" Sets the given component as active admin, and its package as device owner." + "\n\n"); pw.printf(" %s [ %s <USER_ID> | current ] [ %s <NAME> ] <COMPONENT>\n", @@ -254,7 +256,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { mService.setActiveAdmin(mComponent, /* refreshing= */ true, mUserId); try { - if (!mService.setDeviceOwner(mComponent, mName, mUserId)) { + if (!mService.setDeviceOwner(mComponent, mName, mUserId, + /* setProfileOwnerOnCurrentUserIfNecessary= */ !mSetDoOnly)) { throw new RuntimeException( "Can't set package " + mComponent + " as device owner."); } @@ -351,6 +354,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand { if (mUserId == UserHandle.USER_CURRENT) { mUserId = ActivityManager.getCurrentUser(); } + } else if (DO_ONLY_OPTION.equals(opt)) { + mSetDoOnly = true; } else if (canHaveName && NAME_OPTION.equals(opt)) { mName = getNextArgRequired(); } else { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 7b20bf0f6bc7..3ac30d0258a5 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -2960,9 +2960,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(intent.getAction()).isEqualTo(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS); assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, -1)) .isEqualTo(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID)); - assertThat( - (ComponentName) intent.getParcelableExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN)) - .isEqualTo(admin1); assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)) .isEqualTo(UserManager.DISALLOW_ADJUST_VOLUME); @@ -2999,7 +2996,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(intent.getStringExtra(DevicePolicyManager.EXTRA_RESTRICTION)) .isEqualTo(DevicePolicyManager.POLICY_DISABLE_CAMERA); assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, -1)) - .isEqualTo(UserHandle.getUserId(DpmMockContext.CALLER_SYSTEM_USER_UID)); + .isEqualTo(UserHandle.getUserId(DpmMockContext.CALLER_UID)); // ScreenCapture should not be disabled by device owner intent = dpm.createAdminSupportIntent(DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); assertThat(intent).isNull(); @@ -7753,6 +7750,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT); } + @Test + public void testGetOrganizationNameForUser_calledByNonPrivilegedApp_throwsException() { + assertExpectException(SecurityException.class, "Calling identity is not authorized", + () -> dpm.getOrganizationNameForUser(UserHandle.USER_SYSTEM)); + } + private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) { final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage, userVpnUid, List.of(new AppOpsManager.OpEntry( diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java index 4564296810ff..0dd5c61121db 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -20,6 +20,8 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REF import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE; @@ -1408,6 +1410,12 @@ public class DisplayModeDirectorTest { public void testHbmVoting_forHdr() { DisplayModeDirector director = createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + final int hbmRefreshRate = 72; + + // Specify limitation before starting DisplayModeDirector to avoid waiting on property + // propagation + mInjector.getDeviceConfig().setRefreshRateInHbmHdr(hbmRefreshRate); + director.start(createMockSensorManager()); ArgumentCaptor<DisplayListener> captor = @@ -1432,7 +1440,7 @@ public class DisplayModeDirectorTest { new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); - assertVoteForRefreshRate(vote, 60.f); + assertVoteForRefreshRate(vote, hbmRefreshRate); // Turn off HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( @@ -1443,6 +1451,44 @@ public class DisplayModeDirectorTest { } @Test + public void testHbmObserverGetsUpdatedRefreshRateInHbmSunlight() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0); + + final int initialRefreshRate = 60; + mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(initialRefreshRate); + director.start(createMockSensorManager()); + assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight()) + .isEqualTo(initialRefreshRate); + + final int updatedRefreshRate = 90; + mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(updatedRefreshRate); + // Need to wait for the property change to propagate to the main thread. + waitForIdleSync(); + assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight()) + .isEqualTo(updatedRefreshRate); + } + + @Test + public void testHbmObserverGetsUpdatedRefreshRateInHbmHdr() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0); + + final int initialRefreshRate = 60; + mInjector.getDeviceConfig().setRefreshRateInHbmHdr(initialRefreshRate); + director.start(createMockSensorManager()); + assertThat(director.getHbmObserver().getRefreshRateInHbmHdr()) + .isEqualTo(initialRefreshRate); + + final int updatedRefreshRate = 90; + mInjector.getDeviceConfig().setRefreshRateInHbmHdr(updatedRefreshRate); + // Need to wait for the property change to propagate to the main thread. + waitForIdleSync(); + assertThat(director.getHbmObserver().getRefreshRateInHbmHdr()) + .isEqualTo(updatedRefreshRate); + } + + @Test public void testHbmVoting_forSunlight() { DisplayModeDirector director = createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); @@ -1455,11 +1501,12 @@ public class DisplayModeDirectorTest { | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); DisplayListener listener = captor.getValue(); + final int initialRefreshRate = 60; // Specify Limitation when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn( List.of(new RefreshRateLimitation( DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, - 60.f, 60.f))); + initialRefreshRate, initialRefreshRate))); // Verify that there is no HBM vote initially Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); @@ -1470,7 +1517,39 @@ public class DisplayModeDirectorTest { new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); listener.onDisplayChanged(DISPLAY_ID); vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); - assertVoteForRefreshRate(vote, 60.f); + assertVoteForRefreshRate(vote, initialRefreshRate); + + // Change refresh rate vote value through DeviceConfig, ensure it takes precedence + final int updatedRefreshRate = 90; + mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(updatedRefreshRate); + // Need to wait for the property change to propagate to the main thread. + waitForIdleSync(); + assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight()) + .isEqualTo(updatedRefreshRate); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, updatedRefreshRate); + + // Turn off HBM + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Turn HBM on again and ensure the updated vote value stuck + when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( + new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT)); + listener.onDisplayChanged(DISPLAY_ID); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, updatedRefreshRate); + + // Reset DeviceConfig refresh rate, ensure vote falls back to the initial value + mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(0); + // Need to wait for the property change to propagate to the main thread. + waitForIdleSync(); + assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight()).isEqualTo(0); + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertVoteForRefreshRate(vote, initialRefreshRate); // Turn off HBM when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn( @@ -1518,6 +1597,63 @@ public class DisplayModeDirectorTest { assertNull(vote); } + private void setHbmAndAssertRefreshRate( + DisplayModeDirector director, DisplayListener listener, int mode, float rr) { + when(mInjector.getBrightnessInfo(DISPLAY_ID)) + .thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode)); + listener.onDisplayChanged(DISPLAY_ID); + + final Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + if (Float.isNaN(rr)) { + assertNull(vote); + } else { + assertVoteForRefreshRate(vote, rr); + } + } + + @Test + public void testHbmVoting_forSunlightAndHdr() { + DisplayModeDirector director = + createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0); + + // Specify HDR limitation before starting DisplayModeDirector to avoid waiting on property + // propagation + final int hdrRr = 60; + mInjector.getDeviceConfig().setRefreshRateInHbmHdr(hdrRr); + director.start(createMockSensorManager()); + + ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class); + verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class), + eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS + | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED)); + DisplayListener listener = captor.getValue(); + + // Specify Sunlight limitations + final float sunlightRr = 90.0f; + when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)) + .thenReturn(List.of(new RefreshRateLimitation( + DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, sunlightRr, + sunlightRr))); + + // Verify that there is no HBM vote initially + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE); + assertNull(vote); + + // Verify all state transitions + setHbmAndAssertRefreshRate( + director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, sunlightRr); + setHbmAndAssertRefreshRate( + director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, hdrRr); + setHbmAndAssertRefreshRate( + director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, Float.NaN); + setHbmAndAssertRefreshRate( + director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, hdrRr); + setHbmAndAssertRefreshRate( + director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, sunlightRr); + setHbmAndAssertRefreshRate( + director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, Float.NaN); + } + @Test public void testHbmVoting_RemovedDisplay() { DisplayModeDirector director = @@ -1622,6 +1758,16 @@ public class DisplayModeDirectorTest { String.valueOf(fps)); } + void setRefreshRateInHbmSunlight(int fps) { + putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, String.valueOf(fps)); + } + + void setRefreshRateInHbmHdr(int fps) { + putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, + KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps)); + } + void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) { String thresholds = toPropertyValue(brightnessThresholds); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index c434b137317e..65733d7a4129 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2700,8 +2700,8 @@ public class ActivityRecordTests extends WindowTestsBase { final WindowState startingWindow = createWindowState( new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), activity1); activity1.addWindow(startingWindow); - activity1.attachStartingWindow(startingWindow); activity1.mStartingData = mock(StartingData.class); + activity1.attachStartingWindow(startingWindow); final Task task = activity1.getTask(); final Rect taskBounds = task.getBounds(); final int width = taskBounds.width(); @@ -2729,6 +2729,10 @@ public class ActivityRecordTests extends WindowTestsBase { assertTrue(activity2.isResizeable()); activity1.reparent(taskFragment1, POSITION_TOP); + verify(activity1.getSyncTransaction()).reparent(eq(startingWindow.mSurfaceControl), + eq(task.mSurfaceControl)); + assertEquals(activity1.mStartingData, startingWindow.mStartingData); + assertEquals(task.mSurfaceControl, startingWindow.getAnimationLeashParent()); assertEquals(task, activity1.mStartingData.mAssociatedTask); assertEquals(taskFragment1.getBounds(), activity1.getBounds()); // The activity was resized by task fragment, but starting window must still cover the task. diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index 764f63dcd013..5de4fcbb5aa7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -33,6 +33,7 @@ import static com.android.server.wm.ActivityRecord.State.STOPPING; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -748,6 +749,92 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { assertFalse(wpcAfterConfigChange2.getConfiguration().isNightModeActive()); } + @Test + public void testPackageConfigUpdate_localesNotSet_localeConfigRetrievedNull() { + Configuration config = mAtm.getGlobalConfiguration(); + config.setLocales(LocaleList.forLanguageTags("en-XC")); + mAtm.updateGlobalConfigurationLocked(config, true, true, + DEFAULT_USER_ID); + WindowProcessController wpc = createWindowProcessController( + DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + mAtm.mProcessMap.put(Binder.getCallingPid(), wpc); + mAtm.mInternal.onProcessAdded(wpc); + + ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal + .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + // when no configuration is set we get a null object. + assertNull(appSpecificConfig); + + ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = + mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME, + DEFAULT_USER_ID); + packageConfigUpdater.setNightMode(Configuration.UI_MODE_NIGHT_YES).commit(); + + ActivityTaskManagerInternal.PackageConfig appSpecificConfig2 = mAtm.mInternal + .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + assertNotNull(appSpecificConfig2); + assertNull(appSpecificConfig2.mLocales); + assertEquals(appSpecificConfig2.mNightMode.intValue(), Configuration.UI_MODE_NIGHT_YES); + } + + @Test + public void testPackageConfigUpdate_appNotRunning_configSuccessfullyApplied() { + Configuration config = mAtm.getGlobalConfiguration(); + config.setLocales(LocaleList.forLanguageTags("en-XC")); + mAtm.updateGlobalConfigurationLocked(config, true, true, + DEFAULT_USER_ID); + + ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = + mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME, + DEFAULT_USER_ID); + packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")).commit(); + + // Verifies if the persisted app-specific configuration is same as the committed + // configuration. + ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal + .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + assertNotNull(appSpecificConfig); + assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB"), appSpecificConfig.mLocales); + + // Verifies if the persisted configuration for an arbitrary app is applied correctly when + // a new WindowProcessController is created for it. + WindowProcessController wpcAfterConfigChange = createWindowProcessController( + DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), + wpcAfterConfigChange.getConfiguration().getLocales()); + } + + @Test + public void testPackageConfigUpdate_appRunning_configSuccessfullyApplied() { + Configuration config = mAtm.getGlobalConfiguration(); + config.setLocales(LocaleList.forLanguageTags("en-XC")); + mAtm.updateGlobalConfigurationLocked(config, true, true, + DEFAULT_USER_ID); + WindowProcessController wpc = createWindowProcessController( + DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + mAtm.mProcessMap.put(Binder.getCallingPid(), wpc); + mAtm.mInternal.onProcessAdded(wpc); + + ActivityTaskManagerInternal.PackageConfigurationUpdater packageConfigUpdater = + mAtm.mInternal.createPackageConfigurationUpdater(DEFAULT_PACKAGE_NAME, + DEFAULT_USER_ID); + + packageConfigUpdater.setLocales(LocaleList.forLanguageTags("en-XA,ar-XB")).commit(); + + ActivityTaskManagerInternal.PackageConfig appSpecificConfig = mAtm.mInternal + .getApplicationConfig(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID); + + // Verifies if the persisted app-specific configuration is same as the committed + // configuration. + assertNotNull(appSpecificConfig); + assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB"), appSpecificConfig.mLocales); + + // Verifies if the committed configuration is successfully applied to the required + // application while it is currently running. + assertEquals(LocaleList.forLanguageTags("en-XA,ar-XB,en-XC"), + wpc.getConfiguration().getLocales()); + } + private WindowProcessController createWindowProcessController(String packageName, int userId) { WindowProcessListener mMockListener = Mockito.mock(WindowProcessListener.class); 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 d6d7f07b2ef3..5fa76bb2e25b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -27,6 +27,8 @@ import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -44,6 +46,7 @@ import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.annotation.Nullable; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -763,59 +766,148 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Test - public void testGetRemoteAnimationOverrideTaskFragmentOrganizer() { - // TaskFragmentOrganizer registers remote animation. + public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); - final ITaskFragmentOrganizer iOrganizer = - ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); - final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); - definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); - mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); - mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); + setupTaskFragmentRemoteAnimation(organizer, adapter); // Create a TaskFragment with embedded activity. - final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(createTask(mDisplayContent)) - .createActivityCount(1) - .setOrganizer(organizer) - .build(); + final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity( + createTask(mDisplayContent), organizer); final ActivityRecord activity = taskFragment.getTopMostActivity(); activity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); - // Prepare a transition for TaskFragment. - mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); - mDisplayContent.mOpeningApps.add(activity); - mDisplayContent.mChangingContainers.add(taskFragment); - mDisplayContent.mAppTransitionController.handleAppTransitionReady(); + // Prepare a transition. + prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); - // Check if the transition has been overridden. + // Should be overridden. verify(mDisplayContent.mAppTransition) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test + public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() { + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + setupTaskFragmentRemoteAnimation(organizer, adapter); + + final Task task = createTask(mDisplayContent); + // Closing non-embedded activity. + final ActivityRecord closingActivity = createActivityRecord(task); + closingActivity.allDrawn = true; + // Opening TaskFragment with embedded activity. + final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); + final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); + openingActivity.allDrawn = true; + spyOn(mDisplayContent.mAppTransition); + + // Prepare a transition. + prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); + + // Should be overridden. + verify(mDisplayContent.mAppTransition) + .overridePendingAppTransitionRemote(adapter, false /* sync */); + } + + @Test + public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() { + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + setupTaskFragmentRemoteAnimation(organizer, adapter); + + final Task task = createTask(mDisplayContent); + // Closing TaskFragment with embedded activity. + final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer); + final ActivityRecord closingActivity = taskFragment1.getTopMostActivity(); + closingActivity.allDrawn = true; + closingActivity.info.applicationInfo.uid = 12345; + // Opening TaskFragment with embedded activity with different UID. + final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer); + final ActivityRecord openingActivity = taskFragment2.getTopMostActivity(); + openingActivity.info.applicationInfo.uid = 54321; + openingActivity.allDrawn = true; + spyOn(mDisplayContent.mAppTransition); + + // Prepare a transition. + prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1); + + // Should be overridden. + verify(mDisplayContent.mAppTransition) + .overridePendingAppTransitionRemote(adapter, false /* sync */); + } + + @Test + public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() { + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + setupTaskFragmentRemoteAnimation(organizer, adapter); + + // Closing activity in Task1. + final ActivityRecord closingActivity = createActivityRecord(mDisplayContent); + closingActivity.allDrawn = true; + // Opening TaskFragment with embedded activity in Task2. + final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity( + createTask(mDisplayContent), organizer); + final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); + openingActivity.allDrawn = true; + spyOn(mDisplayContent.mAppTransition); + + // Prepare a transition for TaskFragment. + prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); + + // Should not be overridden. + verify(mDisplayContent.mAppTransition, never()) + .overridePendingAppTransitionRemote(adapter, false /* sync */); + } + + @Test + public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() { + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( + new TestRemoteAnimationRunner(), 10, 1); + setupTaskFragmentRemoteAnimation(organizer, adapter); + + final Task task = createTask(mDisplayContent); + // Closing TaskFragment with embedded activity. + final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); + final ActivityRecord closingActivity = taskFragment.getTopMostActivity(); + closingActivity.allDrawn = true; + closingActivity.info.applicationInfo.uid = 12345; + // Opening non-embedded activity with different UID. + final ActivityRecord openingActivity = createActivityRecord(task); + openingActivity.info.applicationInfo.uid = 54321; + openingActivity.allDrawn = true; + spyOn(mDisplayContent.mAppTransition); + + // Prepare a transition. + prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); + + // Should not be overridden + verify(mDisplayContent.mAppTransition, never()) + .overridePendingAppTransitionRemote(adapter, false /* sync */); + } + + @Test public void testTransitionGoodToGoForTaskFragments() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final Task task = createTask(mDisplayContent); - final TaskFragment changeTaskFragment = new TaskFragmentBuilder(mAtm) - .setParentTask(task) - .createActivityCount(1) - .setOrganizer(organizer) - .build(); + final TaskFragment changeTaskFragment = + createTaskFragmentWithEmbeddedActivity(task, organizer); final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) .setOrganizer(organizer) .build(); changeTaskFragment.getTopMostActivity().allDrawn = true; - mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); - mDisplayContent.mChangingContainers.add(changeTaskFragment); spyOn(mDisplayContent.mAppTransition); spyOn(emptyTaskFragment); - mDisplayContent.mAppTransitionController.handleAppTransitionReady(); + prepareAndTriggerAppTransition( + null /* openingActivity */, null /* closingActivity*/, changeTaskFragment); // Transition not ready because there is an empty non-finishing TaskFragment. verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); @@ -829,4 +921,34 @@ public class AppTransitionControllerTest extends WindowTestsBase { // removed. verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); } + + /** Registers remote animation for the organizer. */ + private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, + RemoteAnimationAdapter adapter) { + final ITaskFragmentOrganizer iOrganizer = + ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); + final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); + definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); + definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter); + definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); + mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); + mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); + } + + private void prepareAndTriggerAppTransition(@Nullable ActivityRecord openingActivity, + @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment) { + if (openingActivity != null) { + mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); + mDisplayContent.mOpeningApps.add(openingActivity); + } + if (closingActivity != null) { + mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CLOSE, 0); + mDisplayContent.mClosingApps.add(closingActivity); + } + if (changingTaskFragment != null) { + mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); + mDisplayContent.mChangingContainers.add(changingTaskFragment); + } + mDisplayContent.mAppTransitionController.handleAppTransitionReady(); + } }
\ No newline at end of file diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 405d714256ab..fb8bc7be38ce 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -35,6 +35,8 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.junit.Assert.assertEquals; @@ -42,6 +44,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import android.graphics.Rect; import android.os.Binder; @@ -54,6 +57,7 @@ import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; import android.view.WindowManager; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentOrganizer; @@ -397,7 +401,9 @@ public class AppTransitionTests extends WindowTestsBase { @Test public void testActivityRecordReparentToTaskFragment() { final ActivityRecord activity = createActivityRecord(mDc); + final SurfaceControl activityLeash = mock(SurfaceControl.class); activity.setVisibility(true); + activity.setSurfaceControl(activityLeash); final Task task = activity.getTask(); // Add a TaskFragment of half of the Task size. @@ -412,15 +418,20 @@ public class AppTransitionTests extends WindowTestsBase { final Rect taskBounds = new Rect(); task.getBounds(taskBounds); taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom); + spyOn(taskFragment); assertTrue(mDc.mChangingContainers.isEmpty()); assertFalse(mDc.mAppTransition.isTransitionSet()); // Schedule app transition when reparent activity to a TaskFragment of different size. + final Rect startBounds = new Rect(activity.getBounds()); activity.reparent(taskFragment, POSITION_TOP); - assertTrue(mDc.mChangingContainers.contains(activity)); + // It should transit at TaskFragment level with snapshot on the activity surface. + verify(taskFragment).initializeChangeTransition(activity.getBounds(), activityLeash); + assertTrue(mDc.mChangingContainers.contains(taskFragment)); assertTrue(mDc.mAppTransition.containsTransitRequest(TRANSIT_CHANGE)); + assertEquals(startBounds, taskFragment.mSurfaceFreezer.mFreezeBounds); } private class TestRemoteAnimationRunner implements IRemoteAnimationRunner { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index e3402177140d..24bbf4682157 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1562,6 +1562,7 @@ public class DisplayContentTests extends WindowTestsBase { final ActivityRecord activity = createActivityRecord(mDisplayContent); final ActivityRecord recentsActivity = createActivityRecord(mDisplayContent); recentsActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); + doReturn(mock(RecentsAnimationController.class)).when(mWm).getRecentsAnimationController(); // Do not rotate if the recents animation is animating on top. mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity); @@ -2513,7 +2514,7 @@ public class DisplayContentTests extends WindowTestsBase { assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop))); } - private static int getRotatedOrientation(DisplayContent dc) { + static int getRotatedOrientation(DisplayContent dc) { return dc.mBaseDisplayWidth > dc.mBaseDisplayHeight ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE; diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java index 78946fca7e8b..1e86522a2307 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java @@ -63,7 +63,7 @@ public class LetterboxTest { mLetterbox = new Letterbox(mSurfaces, StubTransaction::new, () -> mAreCornersRounded, () -> Color.valueOf(mColor), () -> mHasWallpaperBackground, () -> mBlurRadius, () -> mDarkScrimAlpha, - /* doubleTapCallback= */ () -> {}); + /* doubleTapCallback= */ x -> {}); mTransaction = spy(StubTransaction.class); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index d88fbee6ae13..a680cba8b266 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -41,8 +41,8 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -439,6 +439,22 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { } @Test + public void testCheckRotationAfterCleanup() { + mWm.setRecentsAnimationController(mController); + spyOn(mDisplayContent.mFixedRotationTransitionListener); + doReturn(true).when(mDisplayContent.mFixedRotationTransitionListener) + .isTopFixedOrientationRecentsAnimating(); + // Rotation update is skipped while the recents animation is running. + assertFalse(mDisplayContent.getDisplayRotation().updateOrientation(DisplayContentTests + .getRotatedOrientation(mDefaultDisplay), false /* forceUpdate */)); + final int prevRotation = mDisplayContent.getRotation(); + mWm.cleanupRecentsAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); + waitHandlerIdle(mWm.mH); + // The display should be updated to the changed orientation after the animation is finished. + assertNotEquals(mDisplayContent.getRotation(), prevRotation); + } + + @Test public void testWallpaperHasFixedRotationApplied() { unblockDisplayRotation(mDefaultDisplay); mWm.setRecentsAnimationController(mController); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java new file mode 100644 index 000000000000..cb209abf6aa9 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + +import static org.mockito.Mockito.clearInvocations; + +import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; +import android.view.SurfaceControl; +import android.window.ITaskFragmentOrganizer; +import android.window.TaskFragmentOrganizer; + +import androidx.test.filters.MediumTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Test class for {@link TaskFragment}. + * + * Build/Install/Run: + * atest WmTests:TaskFragmentTest + */ +@MediumTest +@Presubmit +@RunWith(WindowTestRunner.class) +public class TaskFragmentTest extends WindowTestsBase { + + private TaskFragmentOrganizer mOrganizer; + private TaskFragment mTaskFragment; + private SurfaceControl mLeash; + @Mock + private SurfaceControl.Transaction mTransaction; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mOrganizer = new TaskFragmentOrganizer(Runnable::run); + final ITaskFragmentOrganizer iOrganizer = + ITaskFragmentOrganizer.Stub.asInterface(mOrganizer.getOrganizerToken().asBinder()); + mAtm.mWindowOrganizerController.mTaskFragmentOrganizerController + .registerOrganizer(iOrganizer); + mTaskFragment = new TaskFragmentBuilder(mAtm) + .setCreateParentTask() + .setOrganizer(mOrganizer) + .build(); + mLeash = mTaskFragment.getSurfaceControl(); + spyOn(mTaskFragment); + doReturn(mTransaction).when(mTaskFragment).getSyncTransaction(); + doReturn(mTransaction).when(mTaskFragment).getPendingTransaction(); + } + + @Test + public void testOnConfigurationChanged_updateSurface() { + final Rect bounds = new Rect(100, 100, 1100, 1100); + mTaskFragment.setBounds(bounds); + + verify(mTransaction).setPosition(mLeash, 100, 100); + verify(mTransaction).setWindowCrop(mLeash, 1000, 1000); + } + + @Test + public void testStartChangeTransition_resetSurface() { + final Rect startBounds = new Rect(0, 0, 1000, 1000); + final Rect endBounds = new Rect(500, 500, 1000, 1000); + mTaskFragment.setBounds(startBounds); + doReturn(true).when(mTaskFragment).isVisible(); + + clearInvocations(mTransaction); + mTaskFragment.setBounds(endBounds); + + // Surface reset when prepare transition. + verify(mTaskFragment).initializeChangeTransition(startBounds); + verify(mTransaction).setPosition(mLeash, 0, 0); + verify(mTransaction).setWindowCrop(mLeash, 0, 0); + + clearInvocations(mTransaction); + mTaskFragment.mSurfaceFreezer.unfreeze(mTransaction); + + // Update surface after animation. + verify(mTransaction).setPosition(mLeash, 500, 500); + verify(mTransaction).setWindowCrop(mLeash, 500, 500); + } +} 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 b17ea5e48db5..e6ad68aafaec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.view.InsetsState.ITYPE_IME; @@ -835,8 +836,7 @@ public class WindowStateTests extends WindowTestsBase { WindowState sameTokenWindow = createWindow(null, TYPE_BASE_APPLICATION, mAppWindow.mToken, "SameTokenWindow"); mDisplayContent.setImeLayeringTarget(mAppWindow); - sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); assertTrue(sameTokenWindow.needsRelativeLayeringToIme()); sameTokenWindow.removeImmediately(); assertFalse(sameTokenWindow.needsRelativeLayeringToIme()); @@ -848,8 +848,7 @@ public class WindowStateTests extends WindowTestsBase { WindowState sameTokenWindow = createWindow(null, TYPE_APPLICATION_STARTING, mAppWindow.mToken, "SameTokenWindow"); mDisplayContent.setImeLayeringTarget(mAppWindow); - sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode( - WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + sameTokenWindow.mActivityRecord.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); assertFalse(sameTokenWindow.needsRelativeLayeringToIme()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 6626aa46e7da..8ec1bd6c5787 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -699,6 +699,15 @@ class WindowTestsBase extends SystemServiceTestsBase { return builder.build(); } + static TaskFragment createTaskFragmentWithEmbeddedActivity(@NonNull Task parentTask, + TaskFragmentOrganizer organizer) { + return new TaskFragmentBuilder(parentTask.mAtmService) + .setParentTask(parentTask) + .createActivityCount(1) + .setOrganizer(organizer) + .build(); + } + /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay() { return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL); diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java index d967891fdb76..22ea3d5be71b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; @@ -37,6 +38,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER; import static com.google.common.truth.Truth.assertThat; @@ -493,4 +495,27 @@ public class ZOrderingTests extends WindowTestsBase { assertZOrderGreaterThan(mTransaction, mNavBarWindow.mToken.getSurfaceControl(), mDisplayContent.getImeContainer().getSurfaceControl()); } + + @Test + public void testPopupWindowAndParentIsImeTarget_expectHigherThanIme_inMultiWindow() { + // Simulate the app window is in multi windowing mode and being IME target + mAppWindow.getConfiguration().windowConfiguration.setWindowingMode( + WINDOWING_MODE_MULTI_WINDOW); + mDisplayContent.setImeLayeringTarget(mAppWindow); + mDisplayContent.setImeInputTarget(mAppWindow); + + // Create a popupWindow + assertWindowHigher(mImeWindow, mAppWindow); + final WindowState popupWindow = createWindow(mAppWindow, TYPE_APPLICATION_PANEL, + mDisplayContent, "PopupWindow"); + spyOn(popupWindow); + + mDisplayContent.assignChildLayers(mTransaction); + + // Verify the surface layer of the popupWindow should higher than IME + verify(popupWindow).needsRelativeLayeringToIme(); + assertThat(popupWindow.needsRelativeLayeringToIme()).isTrue(); + assertZOrderGreaterThan(mTransaction, popupWindow.getSurfaceControl(), + mDisplayContent.getImeContainer().getSurfaceControl()); + } } diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 4d81b5e54470..7a424c87d1d6 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -308,6 +308,12 @@ public final class TelephonyPermissions { return checkPrivilegedReadPermissionOrCarrierPrivilegePermission( context, subId, callingPackage, callingFeatureId, message, false, reportFailure); } + + private static void throwSecurityExceptionAsUidDoesNotHaveAccess(String message, int uid) { + throw new SecurityException(message + ": The uid " + uid + + " does not meet the requirements to access device identifiers."); + } + /** * Checks whether the app with the given pid/uid can read device identifiers. * @@ -343,9 +349,14 @@ public final class TelephonyPermissions { LegacyPermissionManager permissionManager = (LegacyPermissionManager) context.getSystemService(Context.LEGACY_PERMISSION_SERVICE); - if (permissionManager.checkDeviceIdentifierAccess(callingPackage, message, callingFeatureId, - pid, uid) == PackageManager.PERMISSION_GRANTED) { - return true; + try { + if (permissionManager.checkDeviceIdentifierAccess(callingPackage, message, + callingFeatureId, + pid, uid) == PackageManager.PERMISSION_GRANTED) { + return true; + } + } catch (SecurityException se) { + throwSecurityExceptionAsUidDoesNotHaveAccess(message, uid); } if (reportFailure) { @@ -410,8 +421,8 @@ public final class TelephonyPermissions { return false; } } - throw new SecurityException(message + ": The user " + uid - + " does not meet the requirements to access device identifiers."); + throwSecurityExceptionAsUidDoesNotHaveAccess(message, uid); + return true; } /** |