diff options
304 files changed, 5198 insertions, 1154 deletions
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index aba4b2c0d591..23f2bdb7fa54 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -49,6 +49,12 @@ public class TaskInfo { private static final String TAG = "TaskInfo"; /** + * The value to use when the property has not a specific value. + * @hide + */ + public static final int PROPERTY_VALUE_UNSET = -1; + + /** * The id of the user the task was running as if this is a leaf task. The id of the current * running user of the system otherwise. * @hide @@ -230,6 +236,40 @@ public class TaskInfo { public boolean topActivityEligibleForLetterboxEducation; /** + * Whether the double tap is enabled + * @hide + */ + public boolean isLetterboxDoubleTapEnabled; + + /** + * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or + * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise. + * @hide + */ + public int topActivityLetterboxVerticalPosition; + + /** + * If {@link isLetterboxDoubleTapEnabled} it contains the current letterbox vertical position or + * {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise. + * @hide + */ + public int topActivityLetterboxHorizontalPosition; + + /** + * If {@link isLetterboxDoubleTapEnabled} it contains the current width of the letterboxed + * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise + * @hide + */ + public int topActivityLetterboxWidth; + + /** + * If {@link isLetterboxDoubleTapEnabled} it contains the current height of the letterboxed + * activity or {@link TaskInfo.PROPERTY_VALUE_UNSET} otherwise + * @hide + */ + public int topActivityLetterboxHeight; + + /** * Whether this task is resizable. Unlike {@link #resizeMode} (which is what the top activity * supports), this is what the system actually uses for resizability based on other policy and * developer options. @@ -407,7 +447,8 @@ public class TaskInfo { /** @hide */ public boolean hasCompatUI() { return hasCameraCompatControl() || topActivityInSizeCompat - || topActivityEligibleForLetterboxEducation; + || topActivityEligibleForLetterboxEducation + || isLetterboxDoubleTapEnabled; } /** @@ -447,6 +488,12 @@ public class TaskInfo { && isResizeable == that.isResizeable && supportsMultiWindow == that.supportsMultiWindow && displayAreaFeatureId == that.displayAreaFeatureId + && isLetterboxDoubleTapEnabled == that.isLetterboxDoubleTapEnabled + && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition + && topActivityLetterboxWidth == that.topActivityLetterboxWidth + && topActivityLetterboxHeight == that.topActivityLetterboxHeight + && topActivityLetterboxHorizontalPosition + == that.topActivityLetterboxHorizontalPosition && Objects.equals(positionInParent, that.positionInParent) && Objects.equals(pictureInPictureParams, that.pictureInPictureParams) && Objects.equals(shouldDockBigOverlays, that.shouldDockBigOverlays) @@ -475,6 +522,12 @@ public class TaskInfo { && topActivityInSizeCompat == that.topActivityInSizeCompat && topActivityEligibleForLetterboxEducation == that.topActivityEligibleForLetterboxEducation + && isLetterboxDoubleTapEnabled == that.isLetterboxDoubleTapEnabled + && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition + && topActivityLetterboxHorizontalPosition + == that.topActivityLetterboxHorizontalPosition + && topActivityLetterboxWidth == that.topActivityLetterboxWidth + && topActivityLetterboxHeight == that.topActivityLetterboxHeight && cameraCompatControlState == that.cameraCompatControlState // Bounds are important if top activity has compat controls. && (!hasCompatUI() || configuration.windowConfiguration.getBounds() @@ -529,6 +582,11 @@ public class TaskInfo { mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR); displayAreaFeatureId = source.readInt(); cameraCompatControlState = source.readInt(); + isLetterboxDoubleTapEnabled = source.readBoolean(); + topActivityLetterboxVerticalPosition = source.readInt(); + topActivityLetterboxHorizontalPosition = source.readInt(); + topActivityLetterboxWidth = source.readInt(); + topActivityLetterboxHeight = source.readInt(); } /** @@ -576,6 +634,11 @@ public class TaskInfo { dest.writeTypedObject(mTopActivityLocusId, flags); dest.writeInt(displayAreaFeatureId); dest.writeInt(cameraCompatControlState); + dest.writeBoolean(isLetterboxDoubleTapEnabled); + dest.writeInt(topActivityLetterboxVerticalPosition); + dest.writeInt(topActivityLetterboxHorizontalPosition); + dest.writeInt(topActivityLetterboxWidth); + dest.writeInt(topActivityLetterboxHeight); } @Override @@ -611,6 +674,12 @@ public class TaskInfo { + " topActivityInSizeCompat=" + topActivityInSizeCompat + " topActivityEligibleForLetterboxEducation= " + topActivityEligibleForLetterboxEducation + + " topActivityLetterboxed= " + isLetterboxDoubleTapEnabled + + " topActivityLetterboxVerticalPosition= " + topActivityLetterboxVerticalPosition + + " topActivityLetterboxHorizontalPosition= " + + topActivityLetterboxHorizontalPosition + + " topActivityLetterboxWidth=" + topActivityLetterboxWidth + + " topActivityLetterboxHeight=" + topActivityLetterboxHeight + " locusId=" + mTopActivityLocusId + " displayAreaFeatureId=" + displayAreaFeatureId + " cameraCompatControlState=" diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java index 77072890a1eb..856bde870bcf 100644 --- a/core/java/android/content/ContentCaptureOptions.java +++ b/core/java/android/content/ContentCaptureOptions.java @@ -70,6 +70,12 @@ public final class ContentCaptureOptions implements Parcelable { public final int logHistorySize; /** + * Disable flush when receiving a VIEW_TREE_APPEARING event. + * @hide + */ + public final boolean disableFlushForViewTreeAppearing; + + /** * List of activities explicitly allowlisted for content capture (or {@code null} if allowlisted * for all acitivites in the package). */ @@ -90,7 +96,8 @@ public final class ContentCaptureOptions implements Parcelable { public ContentCaptureOptions(int loggingLevel) { this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0, /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0, - /* logHistorySize= */ 0, /* whitelistedComponents= */ null); + /* logHistorySize= */ 0, /* disableFlushForViewTreeAppearing= */ false, + /* whitelistedComponents= */ null); } /** @@ -98,10 +105,23 @@ public final class ContentCaptureOptions implements Parcelable { */ public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, - @SuppressLint("NullableCollection") + @SuppressLint({"ConcreteCollection", "NullableCollection"}) + @Nullable ArraySet<ComponentName> whitelistedComponents) { + this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs, + textChangeFlushingFrequencyMs, logHistorySize, + ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING, + whitelistedComponents); + } + + /** @hide */ + public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, + int textChangeFlushingFrequencyMs, int logHistorySize, + boolean disableFlushForViewTreeAppearing, + @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable ArraySet<ComponentName> whitelistedComponents) { this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs, - textChangeFlushingFrequencyMs, logHistorySize, whitelistedComponents); + textChangeFlushingFrequencyMs, logHistorySize, disableFlushForViewTreeAppearing, + whitelistedComponents); } /** @hide */ @@ -111,11 +131,14 @@ public final class ContentCaptureOptions implements Parcelable { ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE, ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS, ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS, - ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE, whitelistedComponents); + ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE, + ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING, + whitelistedComponents); } private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize, + boolean disableFlushForViewTreeAppearing, @Nullable ArraySet<ComponentName> whitelistedComponents) { this.lite = lite; this.loggingLevel = loggingLevel; @@ -123,6 +146,7 @@ public final class ContentCaptureOptions implements Parcelable { this.idleFlushingFrequencyMs = idleFlushingFrequencyMs; this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs; this.logHistorySize = logHistorySize; + this.disableFlushForViewTreeAppearing = disableFlushForViewTreeAppearing; this.whitelistedComponents = whitelistedComponents; } @@ -171,7 +195,8 @@ public final class ContentCaptureOptions implements Parcelable { .append(", maxBufferSize=").append(maxBufferSize) .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs) .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs) - .append(", logHistorySize=").append(logHistorySize); + .append(", logHistorySize=").append(logHistorySize) + .append(", disableFlushForViewTreeAppearing=").append(disableFlushForViewTreeAppearing); if (whitelistedComponents != null) { string.append(", whitelisted=").append(whitelistedComponents); } @@ -189,6 +214,7 @@ public final class ContentCaptureOptions implements Parcelable { pw.print(", idle="); pw.print(idleFlushingFrequencyMs); pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs); pw.print(", logSize="); pw.print(logHistorySize); + pw.print(", disableFlushForViewTreeAppearing="); pw.print(disableFlushForViewTreeAppearing); if (whitelistedComponents != null) { pw.print(", whitelisted="); pw.print(whitelistedComponents); } @@ -209,6 +235,7 @@ public final class ContentCaptureOptions implements Parcelable { parcel.writeInt(idleFlushingFrequencyMs); parcel.writeInt(textChangeFlushingFrequencyMs); parcel.writeInt(logHistorySize); + parcel.writeBoolean(disableFlushForViewTreeAppearing); parcel.writeArraySet(whitelistedComponents); } @@ -226,12 +253,13 @@ public final class ContentCaptureOptions implements Parcelable { final int idleFlushingFrequencyMs = parcel.readInt(); final int textChangeFlushingFrequencyMs = parcel.readInt(); final int logHistorySize = parcel.readInt(); + final boolean disableFlushForViewTreeAppearing = parcel.readBoolean(); @SuppressWarnings("unchecked") final ArraySet<ComponentName> whitelistedComponents = (ArraySet<ComponentName>) parcel.readArraySet(null); return new ContentCaptureOptions(loggingLevel, maxBufferSize, idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize, - whitelistedComponents); + disableFlushForViewTreeAppearing, whitelistedComponents); } @Override diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 226278cbe44d..319f1298a87f 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1035,6 +1035,20 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { 254631730L; // buganizer id /** + * This change id enables compat policy that ignores app requested orientation in + * response to an app calling {@link android.app.Activity#setRequestedOrientation} more + * than twice in one second if an activity is not letterboxed for fixed orientation. + * See com.android.server.wm.LetterboxUiController#shouldIgnoreRequestedOrientation + * for details. + * @hide + */ + @ChangeId + @Overridable + @Disabled + public static final long OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED = + 273509367L; // buganizer id + + /** * This change id forces the packages it is applied to never have Display API sandboxing * applied for a letterbox or SCM activity. The Display APIs will continue to provide * DisplayArea bounds. diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 7ccf07a2a764..ccc39b6080d7 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -17,12 +17,7 @@ package android.hardware; import static android.system.OsConstants.EACCES; -import static android.system.OsConstants.EBUSY; -import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.ENODEV; -import static android.system.OsConstants.ENOSYS; -import static android.system.OsConstants.EOPNOTSUPP; -import static android.system.OsConstants.EUSERS; import android.annotation.Nullable; import android.annotation.SdkConstant; @@ -56,6 +51,7 @@ import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; @@ -491,8 +487,22 @@ public class Camera { boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait( ActivityThread.currentApplication().getApplicationContext()); + boolean forceSlowJpegMode = shouldForceSlowJpegMode(); return native_setup(new WeakReference<Camera>(this), cameraId, - ActivityThread.currentOpPackageName(), overrideToPortrait); + ActivityThread.currentOpPackageName(), overrideToPortrait, forceSlowJpegMode); + } + + private boolean shouldForceSlowJpegMode() { + Context applicationContext = ActivityThread.currentApplication().getApplicationContext(); + String[] slowJpegPackageNames = applicationContext.getResources().getStringArray( + R.array.config_forceSlowJpegModeList); + String callingPackageName = applicationContext.getPackageName(); + for (String packageName : slowJpegPackageNames) { + if (TextUtils.equals(packageName, callingPackageName)) { + return true; + } + } + return false; } /** used by Camera#open, Camera#open(int) */ @@ -563,7 +573,7 @@ public class Camera { @UnsupportedAppUsage private native int native_setup(Object cameraThis, int cameraId, String packageName, - boolean overrideToPortrait); + boolean overrideToPortrait, boolean forceSlowJpegMode); private native final void native_release(); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 76475f2142c0..4f49f12691d0 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2808,6 +2808,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getMobileRadioMeasuredBatteryConsumptionUC(); /** + * Returns the battery consumption (in microcoulombs) of the phone calls, derived from on device + * power measurement data. + * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. + * + * {@hide} + */ + public abstract long getPhoneEnergyConsumptionUC(); + + /** * Returns the battery consumption (in microcoulombs) of the screen while on, derived from on * device power measurement data. * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable. diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 36e0dc35cb8e..b02e123e5254 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -141,12 +141,15 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private int mRingerMode; private int mZenMode; private boolean mPlaySample; + private final boolean mDeviceHasProductStrategies; private static final int MSG_SET_STREAM_VOLUME = 0; private static final int MSG_START_SAMPLE = 1; private static final int MSG_STOP_SAMPLE = 2; private static final int MSG_INIT_SAMPLE = 3; + private static final int MSG_UPDATE_SLIDER_MAYBE_LATER = 4; private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000; + private static final int CHECK_UPDATE_SLIDER_LATER_MS = 500; private static final long SET_STREAM_VOLUME_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500); private static final long START_SAMPLE_DELAY_MS = TimeUnit.MILLISECONDS.toMillis(500); private static final long DURATION_TO_START_DELAYING = TimeUnit.MILLISECONDS.toMillis(2000); @@ -170,6 +173,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba boolean playSample) { mContext = context; mAudioManager = context.getSystemService(AudioManager.class); + mDeviceHasProductStrategies = hasAudioProductStrategies(); mNotificationManager = context.getSystemService(NotificationManager.class); mNotificationPolicy = mNotificationManager.getConsolidatedNotificationPolicy(); mAllowAlarms = (mNotificationPolicy.priorityCategories & NotificationManager.Policy @@ -186,7 +190,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } mZenMode = mNotificationManager.getZenMode(); - if (hasAudioProductStrategies()) { + if (mDeviceHasProductStrategies) { mVolumeGroupId = getVolumeGroupIdForLegacyStreamType(mStreamType); mAttributes = getAudioAttributesForLegacyStreamType( mStreamType); @@ -213,6 +217,12 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mDefaultUri = defaultUri; } + /** + * DO NOT CALL every time this is needed, use once in constructor, + * read mDeviceHasProductStrategies instead + * @return true if stream types are used for volume management, false if volume groups are + * used for volume management + */ private boolean hasAudioProductStrategies() { return AudioManager.getAudioProductStrategies().size() > 0; } @@ -330,6 +340,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba onInitSample(); } break; + case MSG_UPDATE_SLIDER_MAYBE_LATER: + onUpdateSliderMaybeLater(); + break; default: Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what); } @@ -353,6 +366,21 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba : isDelay() ? START_SAMPLE_DELAY_MS : 0); } + private void onUpdateSliderMaybeLater() { + if (isDelay()) { + postUpdateSliderMaybeLater(); + return; + } + updateSlider(); + } + + private void postUpdateSliderMaybeLater() { + if (mHandler == null) return; + mHandler.removeMessages(MSG_UPDATE_SLIDER_MAYBE_LATER); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SLIDER_MAYBE_LATER), + CHECK_UPDATE_SLIDER_LATER_MS); + } + // After stop volume it needs to add a small delay when playing volume or set stream. // It is because the call volume is from the earpiece and the alarm/ring/media // is from the speaker. If play the alarm volume or set alarm stream right after stop @@ -422,7 +450,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba postStopSample(); mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); mReceiver.setListening(false); - if (hasAudioProductStrategies()) { + if (mDeviceHasProductStrategies) { unregisterVolumeGroupCb(); } mSeekBar.setOnSeekBarChangeListener(null); @@ -442,7 +470,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba System.getUriFor(System.VOLUME_SETTINGS_INT[mStreamType]), false, mVolumeObserver); mReceiver.setListening(true); - if (hasAudioProductStrategies()) { + if (mDeviceHasProductStrategies) { registerVolumeGroupCb(); } } @@ -466,6 +494,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mLastProgress = progress; mHandler.removeMessages(MSG_SET_STREAM_VOLUME); mHandler.removeMessages(MSG_START_SAMPLE); + mHandler.removeMessages(MSG_UPDATE_SLIDER_MAYBE_LATER); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME), isDelay() ? SET_STREAM_VOLUME_DELAY_MS : 0); } @@ -608,7 +637,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (AudioManager.VOLUME_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); - if (hasAudioProductStrategies() && !isDelay()) { + if (mDeviceHasProductStrategies && !isDelay()) { updateVolumeSlider(streamType, streamValue); } } else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { @@ -620,9 +649,16 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } } else if (AudioManager.STREAM_DEVICES_CHANGED_ACTION.equals(action)) { int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); - if (hasAudioProductStrategies() && !isDelay()) { - int streamVolume = mAudioManager.getStreamVolume(streamType); - updateVolumeSlider(streamType, streamVolume); + + if (mDeviceHasProductStrategies) { + if (isDelay()) { + // not the right time to update the sliders, try again later + postUpdateSliderMaybeLater(); + } else { + int streamVolume = mAudioManager.getStreamVolume(streamType); + updateVolumeSlider(streamType, streamVolume); + } + } else { int volumeGroup = getVolumeGroupIdForLegacyStreamType(streamType); if (volumeGroup != AudioVolumeGroup.DEFAULT_VOLUME_GROUP diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 8f76a1831605..2887d1f85d21 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -61,6 +61,7 @@ import android.hardware.display.DisplayManager.DisplayListener; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -96,6 +97,7 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.window.ClientWindowFrames; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.HandlerCaller; import com.android.internal.view.BaseIWindow; @@ -104,9 +106,10 @@ import com.android.internal.view.BaseSurfaceHolder; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -166,11 +169,12 @@ public abstract class WallpaperService extends Service { private static final int MSG_RESIZE_PREVIEW = 10110; private static final int MSG_REPORT_SHOWN = 10150; private static final int MSG_UPDATE_DIMMING = 10200; - private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY, - Float.NEGATIVE_INFINITY); + /** limit calls to {@link Engine#onComputeColors} to at most once per second */ private static final int NOTIFY_COLORS_RATE_LIMIT_MS = 1000; - private static final int PROCESS_LOCAL_COLORS_INTERVAL_MS = 1000; + + /** limit calls to {@link Engine#processLocalColorsInternal} to at most once per 2 seconds */ + private static final int PROCESS_LOCAL_COLORS_INTERVAL_MS = 2000; private static final boolean ENABLE_WALLPAPER_DIMMING = SystemProperties.getBoolean("persist.debug.enable_wallpaper_dimming", true); @@ -180,6 +184,9 @@ public abstract class WallpaperService extends Service { private final ArrayList<Engine> mActiveEngines = new ArrayList<Engine>(); + private Handler mBackgroundHandler; + private HandlerThread mBackgroundThread; + static final class WallpaperCommand { String action; int x; @@ -198,14 +205,6 @@ public abstract class WallpaperService extends Service { */ public class Engine { IWallpaperEngineWrapper mIWallpaperEngine; - final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); - final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); - - // 2D matrix [x][y] to represent a page of a portion of a window - EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; - Bitmap mLastScreenshot; - int mLastWindowPage = -1; - private boolean mResetWindowPages; // Copies from mIWallpaperEngine. HandlerCaller mCaller; @@ -267,11 +266,34 @@ public abstract class WallpaperService extends Service { final Object mLock = new Object(); boolean mOffsetMessageEnqueued; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - float mPendingXOffset; - float mPendingYOffset; - float mPendingXOffsetStep; - float mPendingYOffsetStep; + @GuardedBy("mLock") + private float mPendingXOffset; + @GuardedBy("mLock") + private float mPendingYOffset; + @GuardedBy("mLock") + private float mPendingXOffsetStep; + @GuardedBy("mLock") + private float mPendingYOffsetStep; + + /** + * local color extraction related fields. When a user calls `addLocalColorAreas` + */ + @GuardedBy("mLock") + private final ArraySet<RectF> mLocalColorAreas = new ArraySet<>(4); + + @GuardedBy("mLock") + private final ArraySet<RectF> mLocalColorsToAdd = new ArraySet<>(4); + private long mLastProcessLocalColorsTimestamp; + private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); + private int mPixelCopyCount = 0; + // 2D matrix [x][y] to represent a page of a portion of a window + @GuardedBy("mLock") + private EngineWindowPage[] mWindowPages = new EngineWindowPage[0]; + private Bitmap mLastScreenshot; + private boolean mResetWindowPages; + boolean mPendingSync; MotionEvent mPendingMove; boolean mIsInAmbientMode; @@ -280,12 +302,8 @@ public abstract class WallpaperService extends Service { private long mLastColorInvalidation; private final Runnable mNotifyColorsChanged = this::notifyColorsChanged; - // used to throttle processLocalColors - private long mLastProcessLocalColorsTimestamp; - private AtomicBoolean mProcessLocalColorsPending = new AtomicBoolean(false); private final Supplier<Long> mClockFunction; private final Handler mHandler; - private Display mDisplay; private Context mDisplayContext; private int mDisplayState; @@ -825,7 +843,7 @@ public abstract class WallpaperService extends Service { + "was not established."); } mResetWindowPages = true; - processLocalColors(mPendingXOffset, mPendingXOffsetStep); + processLocalColors(); } catch (RemoteException e) { Log.w(TAG, "Can't notify system because wallpaper connection was lost.", e); } @@ -1361,10 +1379,9 @@ public abstract class WallpaperService extends Service { mIsCreating = false; mSurfaceCreated = true; if (redrawNeeded) { - resetWindowPages(); mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE); - processLocalColors(mPendingXOffset, mPendingXOffsetStep); + processLocalColors(); } reposition(); reportEngineShown(shouldWaitForEngineShown()); @@ -1509,7 +1526,7 @@ public abstract class WallpaperService extends Service { if (!mDestroyed) { mVisible = visible; reportVisibility(); - if (mReportedVisible) processLocalColors(mPendingXOffset, mPendingXOffsetStep); + if (mReportedVisible) processLocalColors(); } else { AnimationHandler.requestAnimatorsEnabled(visible, this); } @@ -1594,14 +1611,14 @@ public abstract class WallpaperService extends Service { } // setup local color extraction data - processLocalColors(xOffset, xOffsetStep); + processLocalColors(); } /** * Thread-safe util to call {@link #processLocalColorsInternal} with a minimum interval of * {@link #PROCESS_LOCAL_COLORS_INTERVAL_MS} between two calls. */ - private void processLocalColors(float xOffset, float xOffsetStep) { + private void processLocalColors() { if (mProcessLocalColorsPending.compareAndSet(false, true)) { final long now = mClockFunction.get(); final long timeSinceLastColorProcess = now - mLastProcessLocalColorsTimestamp; @@ -1611,80 +1628,98 @@ public abstract class WallpaperService extends Service { mHandler.postDelayed(() -> { mLastProcessLocalColorsTimestamp = now + timeToWait; mProcessLocalColorsPending.set(false); - processLocalColorsInternal(xOffset, xOffsetStep); + processLocalColorsInternal(); }, timeToWait); } } - private void processLocalColorsInternal(float xOffset, float xOffsetStep) { - // implemented by the wallpaper + /** + * Default implementation of the local color extraction. + * This will take a screenshot of the whole wallpaper on the main thread. + * Then, in a background thread, for each launcher page, for each area that needs color + * extraction in this page, creates a sub-bitmap and call {@link WallpaperColors#fromBitmap} + * to extract the colors. Every time a launcher page has been processed, call + * {@link #notifyLocalColorsChanged} with the color and areas of this page. + */ + private void processLocalColorsInternal() { if (supportsLocalColorExtraction()) return; - if (DEBUG) { - Log.d(TAG, "processLocalColors " + xOffset + " of step " - + xOffsetStep); - } - //below is the default implementation - if (xOffset % xOffsetStep > MIN_PAGE_ALLOWED_MARGIN - || !mSurfaceHolder.getSurface().isValid()) return; - int xCurrentPage; + float xOffset; + float xOffsetStep; + float wallpaperDimAmount; + int xPage; int xPages; - if (!validStep(xOffsetStep)) { + Set<RectF> areas; + EngineWindowPage current; + + synchronized (mLock) { + xOffset = mPendingXOffset; + xOffsetStep = mPendingXOffsetStep; + wallpaperDimAmount = mWallpaperDimAmount; + if (DEBUG) { - Log.w(TAG, "invalid offset step " + xOffsetStep); + Log.d(TAG, "processLocalColors " + xOffset + " of step " + + xOffsetStep); + } + if (xOffset % xOffsetStep > MIN_PAGE_ALLOWED_MARGIN + || !mSurfaceHolder.getSurface().isValid()) return; + int xCurrentPage; + if (!validStep(xOffsetStep)) { + if (DEBUG) { + Log.w(TAG, "invalid offset step " + xOffsetStep); + } + xOffset = 0; + xOffsetStep = 1; + xCurrentPage = 0; + xPages = 1; + } else { + xPages = Math.round(1 / xOffsetStep) + 1; + xOffsetStep = (float) 1 / (float) xPages; + float shrink = (float) (xPages - 1) / (float) xPages; + xOffset *= shrink; + xCurrentPage = Math.round(xOffset / xOffsetStep); + } + if (DEBUG) { + Log.d(TAG, "xPages " + xPages + " xPage " + xCurrentPage); + Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset); } - xOffset = 0; - xOffsetStep = 1; - xCurrentPage = 0; - xPages = 1; - } else { - xPages = Math.round(1 / xOffsetStep) + 1; - xOffsetStep = (float) 1 / (float) xPages; - float shrink = (float) (xPages - 1) / (float) xPages; - xOffset *= shrink; - xCurrentPage = Math.round(xOffset / xOffsetStep); - } - if (DEBUG) { - Log.d(TAG, "xPages " + xPages + " xPage " + xCurrentPage); - Log.d(TAG, "xOffsetStep " + xOffsetStep + " xOffset " + xOffset); - } - float finalXOffsetStep = xOffsetStep; - float finalXOffset = xOffset; + float finalXOffsetStep = xOffsetStep; + float finalXOffset = xOffset; - Trace.beginSection("WallpaperService#processLocalColors"); - resetWindowPages(); - int xPage = xCurrentPage; - EngineWindowPage current; - if (mWindowPages.length == 0 || (mWindowPages.length != xPages)) { - mWindowPages = new EngineWindowPage[xPages]; - initWindowPages(mWindowPages, finalXOffsetStep); - } - if (mLocalColorsToAdd.size() != 0) { - for (RectF colorArea : mLocalColorsToAdd) { - if (!isValid(colorArea)) continue; - mLocalColorAreas.add(colorArea); - int colorPage = getRectFPage(colorArea, finalXOffsetStep); - EngineWindowPage currentPage = mWindowPages[colorPage]; - currentPage.setLastUpdateTime(0); - currentPage.removeColor(colorArea); + resetWindowPages(); + xPage = xCurrentPage; + if (mWindowPages.length == 0 || (mWindowPages.length != xPages)) { + mWindowPages = new EngineWindowPage[xPages]; + initWindowPages(mWindowPages, finalXOffsetStep); } - mLocalColorsToAdd.clear(); - } - if (xPage >= mWindowPages.length) { - if (DEBUG) { - Log.e(TAG, "error xPage >= mWindowPages.length page: " + xPage); - Log.e(TAG, "error on page " + xPage + " out of " + xPages); - Log.e(TAG, - "error on xOffsetStep " + finalXOffsetStep - + " xOffset " + finalXOffset); + if (mLocalColorsToAdd.size() != 0) { + for (RectF colorArea : mLocalColorsToAdd) { + if (!isValid(colorArea)) continue; + mLocalColorAreas.add(colorArea); + int colorPage = getRectFPage(colorArea, finalXOffsetStep); + EngineWindowPage currentPage = mWindowPages[colorPage]; + currentPage.setLastUpdateTime(0); + currentPage.removeColor(colorArea); + } + mLocalColorsToAdd.clear(); } - xPage = mWindowPages.length - 1; + if (xPage >= mWindowPages.length) { + if (DEBUG) { + Log.e(TAG, "error xPage >= mWindowPages.length page: " + xPage); + Log.e(TAG, "error on page " + xPage + " out of " + xPages); + Log.e(TAG, + "error on xOffsetStep " + finalXOffsetStep + + " xOffset " + finalXOffset); + } + xPage = mWindowPages.length - 1; + } + current = mWindowPages[xPage]; + areas = new HashSet<>(current.getAreas()); } - current = mWindowPages[xPage]; - updatePage(current, xPage, xPages, finalXOffsetStep); - Trace.endSection(); + updatePage(current, areas, xPage, xPages, wallpaperDimAmount); } + @GuardedBy("mLock") private void initWindowPages(EngineWindowPage[] windowPages, float step) { for (int i = 0; i < windowPages.length; i++) { windowPages[i] = new EngineWindowPage(); @@ -1701,16 +1736,16 @@ public abstract class WallpaperService extends Service { } } - void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages, - float xOffsetStep) { + void updatePage(EngineWindowPage currentPage, Set<RectF> areas, int pageIndx, int numPages, + float wallpaperDimAmount) { + // in case the clock is zero, we start with negative time long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION; long lapsed = current - currentPage.getLastUpdateTime(); // Always update the page when the last update time is <= 0 // This is important especially when the device first boots - if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) { - return; - } + if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) return; + Surface surface = mSurfaceHolder.getSurface(); if (!surface.isValid()) return; boolean widthIsLarger = mSurfaceSize.x > mSurfaceSize.y; @@ -1723,43 +1758,59 @@ public abstract class WallpaperService extends Service { Log.e(TAG, "wrong width and height values of bitmap " + width + " " + height); return; } + final String pixelCopySectionName = "WallpaperService#pixelCopy"; + final int pixelCopyCount = mPixelCopyCount++; + Trace.beginAsyncSection(pixelCopySectionName, pixelCopyCount); Bitmap screenShot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); final Bitmap finalScreenShot = screenShot; - Trace.beginSection("WallpaperService#pixelCopy"); - PixelCopy.request(surface, screenShot, (res) -> { - Trace.endSection(); - if (DEBUG) Log.d(TAG, "result of pixel copy is " + res); - if (res != PixelCopy.SUCCESS) { - Bitmap lastBitmap = currentPage.getBitmap(); - // assign the last bitmap taken for now - currentPage.setBitmap(mLastScreenshot); - Bitmap lastScreenshot = mLastScreenshot; - if (lastScreenshot != null && !lastScreenshot.isRecycled() - && !Objects.equals(lastBitmap, lastScreenshot)) { - updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); + try { + // TODO(b/274427458) check if this can be done in the background. + PixelCopy.request(surface, screenShot, (res) -> { + Trace.endAsyncSection(pixelCopySectionName, pixelCopyCount); + if (DEBUG) { + Log.d(TAG, "result of pixel copy is: " + + (res == PixelCopy.SUCCESS ? "SUCCESS" : "FAILURE")); } - } else { - mLastScreenshot = finalScreenShot; - // going to hold this lock for a while - currentPage.setBitmap(finalScreenShot); - currentPage.setLastUpdateTime(current); - updatePageColors(currentPage, pageIndx, numPages, xOffsetStep); - } - }, mHandler); - + if (res != PixelCopy.SUCCESS) { + Bitmap lastBitmap = currentPage.getBitmap(); + // assign the last bitmap taken for now + currentPage.setBitmap(mLastScreenshot); + Bitmap lastScreenshot = mLastScreenshot; + if (lastScreenshot != null && !Objects.equals(lastBitmap, lastScreenshot)) { + updatePageColors( + currentPage, areas, pageIndx, numPages, wallpaperDimAmount); + } + } else { + mLastScreenshot = finalScreenShot; + currentPage.setBitmap(finalScreenShot); + currentPage.setLastUpdateTime(current); + updatePageColors( + currentPage, areas, pageIndx, numPages, wallpaperDimAmount); + } + }, mBackgroundHandler); + } catch (IllegalArgumentException e) { + // this can potentially happen if the surface is invalidated right between the + // surface.isValid() check and the PixelCopy operation. + // in this case, stop: we'll compute colors on the next processLocalColors call. + Log.w(TAG, "Cancelling processLocalColors: exception caught during PixelCopy"); + } } // locked by the passed page - private void updatePageColors(EngineWindowPage page, int pageIndx, int numPages, - float xOffsetStep) { + private void updatePageColors(EngineWindowPage page, Set<RectF> areas, + int pageIndx, int numPages, float wallpaperDimAmount) { if (page.getBitmap() == null) return; + if (!mBackgroundHandler.getLooper().isCurrentThread()) { + throw new IllegalStateException( + "ProcessLocalColors should be called from the background thread"); + } Trace.beginSection("WallpaperService#updatePageColors"); if (DEBUG) { Log.d(TAG, "updatePageColorsLocked for page " + pageIndx + " with areas " + page.getAreas().size() + " and bitmap size of " + page.getBitmap().getWidth() + " x " + page.getBitmap().getHeight()); } - for (RectF area: page.getAreas()) { + for (RectF area: areas) { if (area == null) continue; RectF subArea = generateSubRect(area, pageIndx, numPages); Bitmap b = page.getBitmap(); @@ -1769,12 +1820,12 @@ public abstract class WallpaperService extends Service { int height = Math.round(b.getHeight() * subArea.height()); Bitmap target; try { - target = Bitmap.createBitmap(page.getBitmap(), x, y, width, height); + target = Bitmap.createBitmap(b, x, y, width, height); } catch (Exception e) { Log.e(TAG, "Error creating page local color bitmap", e); continue; } - WallpaperColors color = WallpaperColors.fromBitmap(target, mWallpaperDimAmount); + WallpaperColors color = WallpaperColors.fromBitmap(target, wallpaperDimAmount); target.recycle(); WallpaperColors currentColor = page.getColors(area); @@ -1791,12 +1842,14 @@ public abstract class WallpaperService extends Service { + " local color callback for area" + area + " for page " + pageIndx + " of " + numPages); } - try { - mConnection.onLocalWallpaperColorsChanged(area, color, - mDisplayContext.getDisplayId()); - } catch (RemoteException e) { - Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); - } + mHandler.post(() -> { + try { + mConnection.onLocalWallpaperColorsChanged(area, color, + mDisplayContext.getDisplayId()); + } catch (RemoteException e) { + Log.e(TAG, "Error calling Connection.onLocalWallpaperColorsChanged", e); + } + }); } } Trace.endSection(); @@ -1822,16 +1875,17 @@ public abstract class WallpaperService extends Service { return new RectF(left, in.top, right, in.bottom); } + @GuardedBy("mLock") private void resetWindowPages() { if (supportsLocalColorExtraction()) return; if (!mResetWindowPages) return; mResetWindowPages = false; - mLastWindowPage = -1; for (int i = 0; i < mWindowPages.length; i++) { mWindowPages[i].setLastUpdateTime(0L); } } + @GuardedBy("mLock") private int getRectFPage(RectF area, float step) { if (!isValid(area)) return 0; if (!validStep(step)) return 0; @@ -1852,12 +1906,12 @@ public abstract class WallpaperService extends Service { if (DEBUG) { Log.d(TAG, "addLocalColorsAreas adding local color areas " + regions); } - mHandler.post(() -> { - mLocalColorsToAdd.addAll(regions); - processLocalColors(mPendingXOffset, mPendingYOffset); + mBackgroundHandler.post(() -> { + synchronized (mLock) { + mLocalColorsToAdd.addAll(regions); + } + processLocalColors(); }); - - } /** @@ -1867,16 +1921,18 @@ public abstract class WallpaperService extends Service { */ public void removeLocalColorsAreas(@NonNull List<RectF> regions) { if (supportsLocalColorExtraction()) return; - mHandler.post(() -> { - float step = mPendingXOffsetStep; - mLocalColorsToAdd.removeAll(regions); - mLocalColorAreas.removeAll(regions); - if (!validStep(step)) { - return; - } - for (int i = 0; i < mWindowPages.length; i++) { - for (int j = 0; j < regions.size(); j++) { - mWindowPages[i].removeArea(regions.get(j)); + mBackgroundHandler.post(() -> { + synchronized (mLock) { + float step = mPendingXOffsetStep; + mLocalColorsToAdd.removeAll(regions); + mLocalColorAreas.removeAll(regions); + if (!validStep(step)) { + return; + } + for (int i = 0; i < mWindowPages.length; i++) { + for (int j = 0; j < regions.size(); j++) { + mWindowPages[i].removeArea(regions.get(j)); + } } } }); @@ -1894,7 +1950,7 @@ public abstract class WallpaperService extends Service { } private boolean validStep(float step) { - return !PROHIBITED_STEPS.contains(step) && step > 0. && step <= 1.; + return !Float.isNaN(step) && step > 0f && step <= 1f; } void doCommand(WallpaperCommand cmd) { @@ -2498,6 +2554,9 @@ public abstract class WallpaperService extends Service { @Override public void onCreate() { Trace.beginSection("WPMS.onCreate"); + mBackgroundThread = new HandlerThread("DefaultWallpaperLocalColorExtractor"); + mBackgroundThread.start(); + mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); super.onCreate(); Trace.endSection(); } @@ -2510,6 +2569,7 @@ public abstract class WallpaperService extends Service { mActiveEngines.get(i).detach(); } mActiveEngines.clear(); + mBackgroundThread.quitSafely(); Trace.endSection(); } diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java index 59b5286f6fc5..34c7b8b9889f 100644 --- a/core/java/android/view/contentcapture/ContentCaptureContext.java +++ b/core/java/android/view/contentcapture/ContentCaptureContext.java @@ -82,11 +82,19 @@ public final class ContentCaptureContext implements Parcelable { @SystemApi public static final int FLAG_RECONNECTED = 0x4; + /** + * Flag used to disable flush when receiving a VIEW_TREE_APPEARING event. + * + * @hide + */ + public static final int FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING = 1 << 3; + /** @hide */ @IntDef(flag = true, prefix = { "FLAG_" }, value = { FLAG_DISABLED_BY_APP, FLAG_DISABLED_BY_FLAG_SECURE, - FLAG_RECONNECTED + FLAG_RECONNECTED, + FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING }) @Retention(RetentionPolicy.SOURCE) @interface ContextCreationFlags{} @@ -252,7 +260,8 @@ public final class ContentCaptureContext implements Parcelable { * Gets the flags associated with this context. * * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE}, - * {@link #FLAG_DISABLED_BY_APP} and {@link #FLAG_RECONNECTED}. + * {@link #FLAG_DISABLED_BY_APP}, {@link #FLAG_RECONNECTED} and {@link + * #FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING}. * * @hide */ diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 497f0668107f..668351b949c1 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -51,6 +51,7 @@ import android.view.WindowManager; import android.view.contentcapture.ContentCaptureSession.FlushReason; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.SyncResultReceiver; import java.io.PrintWriter; @@ -343,6 +344,14 @@ public final class ContentCaptureManager { */ public static final String DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT = "idle_unbind_timeout"; + /** + * Sets to disable flush when receiving a VIEW_TREE_APPEARING event. + * + * @hide + */ + public static final String DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING = + "disable_flush_for_view_tree_appearing"; + /** @hide */ @TestApi public static final int LOGGING_LEVEL_OFF = 0; @@ -373,6 +382,8 @@ public final class ContentCaptureManager { public static final int DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS = 1_000; /** @hide */ public static final int DEFAULT_LOG_HISTORY_SIZE = 10; + /** @hide */ + public static final boolean DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING = false; private final Object mLock = new Object(); @@ -448,6 +459,7 @@ public final class ContentCaptureManager { mOptions = Objects.requireNonNull(options, "options cannot be null"); ContentCaptureHelper.setLoggingLevel(mOptions.loggingLevel); + setFlushViewTreeAppearingEventDisabled(mOptions.disableFlushForViewTreeAppearing); if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName()); @@ -687,6 +699,38 @@ public final class ContentCaptureManager { } /** + * Explicitly sets enable or disable flush for view tree appearing event. + * + * @hide + */ + @VisibleForTesting + public void setFlushViewTreeAppearingEventDisabled(boolean disabled) { + if (sDebug) { + Log.d(TAG, "setFlushViewTreeAppearingEventDisabled(): setting to " + disabled); + } + + synchronized (mLock) { + if (disabled) { + mFlags |= ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING; + } else { + mFlags &= ~ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING; + } + } + } + + /** + * Gets whether content capture is needed to flush for view tree appearing event. + * + * @hide + */ + public boolean getFlushViewTreeAppearingEventDisabled() { + synchronized (mLock) { + return (mFlags & ContentCaptureContext.FLAG_DISABLED_FLUSH_FOR_VIEW_TREE_APPEARING) + != 0; + } + } + + /** * Gets whether content capture is enabled for the given user. * * <p>This method is typically used by the content capture service settings page, so it can diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 2134d819943e..bdec1970eda9 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -170,6 +170,12 @@ public abstract class ContentCaptureSession implements AutoCloseable { public static final int FLUSH_REASON_TEXT_CHANGE_TIMEOUT = 6; /** @hide */ public static final int FLUSH_REASON_SESSION_CONNECTED = 7; + /** @hide */ + public static final int FLUSH_REASON_FORCE_FLUSH = 8; + /** @hide */ + public static final int FLUSH_REASON_VIEW_TREE_APPEARING = 9; + /** @hide */ + public static final int FLUSH_REASON_VIEW_TREE_APPEARED = 10; /** @hide */ @IntDef(prefix = { "FLUSH_REASON_" }, value = { @@ -179,7 +185,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { FLUSH_REASON_SESSION_FINISHED, FLUSH_REASON_IDLE_TIMEOUT, FLUSH_REASON_TEXT_CHANGE_TIMEOUT, - FLUSH_REASON_SESSION_CONNECTED + FLUSH_REASON_SESSION_CONNECTED, + FLUSH_REASON_FORCE_FLUSH, + FLUSH_REASON_VIEW_TREE_APPEARING, + FLUSH_REASON_VIEW_TREE_APPEARED }) @Retention(RetentionPolicy.SOURCE) public @interface FlushReason{} @@ -614,6 +623,12 @@ public abstract class ContentCaptureSession implements AutoCloseable { return "TEXT_CHANGE"; case FLUSH_REASON_SESSION_CONNECTED: return "CONNECTED"; + case FLUSH_REASON_FORCE_FLUSH: + return "FORCE_FLUSH"; + case FLUSH_REASON_VIEW_TREE_APPEARING: + return "VIEW_TREE_APPEARING"; + case FLUSH_REASON_VIEW_TREE_APPEARED: + return "VIEW_TREE_APPEARED"; default: return "UNKOWN-" + reason; } diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 1f5e462d71fd..9848acd8dfcc 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -458,6 +458,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { case ContentCaptureEvent.TYPE_SESSION_FINISHED: flushReason = FLUSH_REASON_SESSION_FINISHED; break; + case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING: + flushReason = FLUSH_REASON_VIEW_TREE_APPEARING; + break; + case ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED: + flushReason = FLUSH_REASON_VIEW_TREE_APPEARED; + break; default: flushReason = FLUSH_REASON_FULL; } @@ -764,7 +770,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { /** Public because is also used by ViewRootImpl */ public void notifyViewTreeEvent(int sessionId, boolean started) { final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED; - mHandler.post(() -> sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH)); + final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled(); + + mHandler.post(() -> sendEvent( + new ContentCaptureEvent(sessionId, type), + disableFlush ? !started : FORCE_FLUSH)); } void notifySessionResumed(int sessionId) { diff --git a/core/java/com/android/internal/app/procstats/UidState.java b/core/java/com/android/internal/app/procstats/UidState.java index 8761b7470cd3..49113465c26a 100644 --- a/core/java/com/android/internal/app/procstats/UidState.java +++ b/core/java/com/android/internal/app/procstats/UidState.java @@ -150,6 +150,7 @@ public final class UidState { public void resetSafely(long now) { mDurations.resetTable(); mStartTime = now; + mProcesses.removeIf(p -> !p.isInUse()); } /** diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index e7217def7689..475f7fd2bdae 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -16,6 +16,10 @@ package com.android.internal.jank; +import static android.Manifest.permission.READ_DEVICE_CONFIG; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.provider.DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR; + import static com.android.internal.jank.FrameTracker.REASON_CANCEL_NORMAL; import static com.android.internal.jank.FrameTracker.REASON_CANCEL_TIMEOUT; import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL; @@ -94,6 +98,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.UiThread; import android.annotation.WorkerThread; +import android.app.ActivityThread; import android.content.Context; import android.os.Build; import android.os.Handler; @@ -436,18 +441,37 @@ public class InteractionJankMonitor { mWorker = worker; mWorker.start(); mSamplingInterval = DEFAULT_SAMPLING_INTERVAL; + mEnabled = DEFAULT_ENABLED; + + final Context context = ActivityThread.currentApplication(); + if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) != PERMISSION_GRANTED) { + if (DEBUG) { + Log.d(TAG, "Initialized the InteractionJankMonitor." + + " (No READ_DEVICE_CONFIG permission to change configs)" + + " enabled=" + mEnabled + ", interval=" + mSamplingInterval + + ", missedFrameThreshold=" + mTraceThresholdMissedFrames + + ", frameTimeThreshold=" + mTraceThresholdFrameTimeMillis + + ", package=" + context.getPackageName()); + } + return; + } - // Post initialization to the background in case we're running on the main - // thread. + // Post initialization to the background in case we're running on the main thread. mWorker.getThreadHandler().post( - () -> mPropertiesChangedListener.onPropertiesChanged( - DeviceConfig.getProperties( - DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR))); - DeviceConfig.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_INTERACTION_JANK_MONITOR, - new HandlerExecutor(mWorker.getThreadHandler()), - mPropertiesChangedListener); - mEnabled = DEFAULT_ENABLED; + () -> { + try { + mPropertiesChangedListener.onPropertiesChanged( + DeviceConfig.getProperties(NAMESPACE_INTERACTION_JANK_MONITOR)); + DeviceConfig.addOnPropertiesChangedListener( + NAMESPACE_INTERACTION_JANK_MONITOR, + new HandlerExecutor(mWorker.getThreadHandler()), + mPropertiesChangedListener); + } catch (SecurityException ex) { + Log.d(TAG, "Can't get properties: READ_DEVICE_CONFIG granted=" + + context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) + + ", package=" + context.getPackageName()); + } + }); } /** diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 6fed26c4a81d..e1e57de15346 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -166,8 +166,8 @@ public class BatteryStatsImpl extends BatteryStats { // In-memory Parcel magic number, used to detect attempts to unmarshall bad data private static final int MAGIC = 0xBA757475; // 'BATSTATS' - // Current on-disk Parcel version - static final int VERSION = 210; + // Current on-disk Parcel version. Must be updated when the format of the parcelable changes + public static final int VERSION = 211; // The maximum number of names wakelocks we will keep track of // per uid; once the limit is reached, we batch the remaining wakelocks @@ -6491,6 +6491,9 @@ public class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mPhoneOn = true; mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs); + if (mConstants.PHONE_ON_EXTERNAL_STATS_COLLECTION) { + scheduleSyncExternalStatsLocked("phone-on", ExternalStatsSync.UPDATE_RADIO); + } } } @@ -6509,6 +6512,7 @@ public class BatteryStatsImpl extends BatteryStats { addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs); mPhoneOn = false; mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs); + scheduleSyncExternalStatsLocked("phone-off", ExternalStatsSync.UPDATE_RADIO); } } @@ -8475,6 +8479,12 @@ public class BatteryStatsImpl extends BatteryStats { @GuardedBy("this") @Override + public long getPhoneEnergyConsumptionUC() { + return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_PHONE); + } + + @GuardedBy("this") + @Override public long getScreenOnMeasuredBatteryConsumptionUC() { return getPowerBucketConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON); } @@ -13717,18 +13727,36 @@ public class BatteryStatsImpl extends BatteryStats { } synchronized (this) { + final long totalRadioDurationMs = + mMobileRadioActiveTimer.getTimeSinceMarkLocked( + elapsedRealtimeMs * 1000) / 1000; + mMobileRadioActiveTimer.setMark(elapsedRealtimeMs); + final long phoneOnDurationMs = Math.min(totalRadioDurationMs, + mPhoneOnTimer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000); + mPhoneOnTimer.setMark(elapsedRealtimeMs); + if (!mOnBatteryInternal || mIgnoreNextExternalStats) { return; } final SparseDoubleArray uidEstimatedConsumptionMah; + final long dataConsumedChargeUC; if (consumedChargeUC > 0 && mMobileRadioPowerCalculator != null && mGlobalMeasuredEnergyStats != null) { + // Crudely attribute power consumption. Added (totalRadioDurationMs / 2) to the + // numerator for long rounding. + final long phoneConsumedChargeUC = + (consumedChargeUC * phoneOnDurationMs + totalRadioDurationMs / 2) + / totalRadioDurationMs; + dataConsumedChargeUC = consumedChargeUC - phoneConsumedChargeUC; mGlobalMeasuredEnergyStats.updateStandardBucket( - MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC); + MeasuredEnergyStats.POWER_BUCKET_PHONE, phoneConsumedChargeUC); + mGlobalMeasuredEnergyStats.updateStandardBucket( + MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, dataConsumedChargeUC); uidEstimatedConsumptionMah = new SparseDoubleArray(); } else { uidEstimatedConsumptionMah = null; + dataConsumedChargeUC = POWER_DATA_UNAVAILABLE; } if (deltaInfo != null) { @@ -13888,14 +13916,9 @@ public class BatteryStatsImpl extends BatteryStats { // Update the MeasuredEnergyStats information. if (uidEstimatedConsumptionMah != null) { double totalEstimatedConsumptionMah = 0.0; - - // Estimate total active radio power consumption since last mark. - final long totalRadioTimeMs = mMobileRadioActiveTimer.getTimeSinceMarkLocked( - elapsedRealtimeMs * 1000) / 1000; - mMobileRadioActiveTimer.setMark(elapsedRealtimeMs); totalEstimatedConsumptionMah += mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah( - totalRadioTimeMs); + totalRadioDurationMs); // Estimate idle power consumption at each signal strength level final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length; @@ -13919,7 +13942,7 @@ public class BatteryStatsImpl extends BatteryStats { mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs); distributeEnergyToUidsLocked(MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO, - consumedChargeUC, uidEstimatedConsumptionMah, + dataConsumedChargeUC, uidEstimatedConsumptionMah, totalEstimatedConsumptionMah, elapsedRealtimeMs); } @@ -16651,6 +16674,8 @@ public class BatteryStatsImpl extends BatteryStats { public static final String KEY_MAX_HISTORY_BUFFER_KB = "max_history_buffer_kb"; public static final String KEY_BATTERY_CHARGED_DELAY_MS = "battery_charged_delay_ms"; + public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION = + "phone_on_external_stats_collection"; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 1_000; @@ -16663,6 +16688,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE = 64; private static final int DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB = 64; /*Kilo Bytes*/ private static final int DEFAULT_BATTERY_CHARGED_DELAY_MS = 900000; /* 15 min */ + private static final boolean DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION = true; public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME; /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an @@ -16678,6 +16704,8 @@ public class BatteryStatsImpl extends BatteryStats { public int MAX_HISTORY_FILES; public int MAX_HISTORY_BUFFER; /*Bytes*/ public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS; + public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION = + DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION; private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -16754,6 +16782,11 @@ public class BatteryStatsImpl extends BatteryStats { DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB : DEFAULT_MAX_HISTORY_BUFFER_KB) * 1024; + + PHONE_ON_EXTERNAL_STATS_COLLECTION = mParser.getBoolean( + KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION, + DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION); + updateBatteryChargedDelayMsLocked(); } } @@ -16808,6 +16841,8 @@ public class BatteryStatsImpl extends BatteryStats { pw.println(MAX_HISTORY_BUFFER/1024); pw.print(KEY_BATTERY_CHARGED_DELAY_MS); pw.print("="); pw.println(BATTERY_CHARGED_DELAY_MS); + pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("="); + pw.println(PHONE_ON_EXTERNAL_STATS_COLLECTION); } } diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java index cb893defab14..f1c4ffe07788 100644 --- a/core/java/com/android/internal/os/PhonePowerCalculator.java +++ b/core/java/com/android/internal/os/PhonePowerCalculator.java @@ -40,14 +40,27 @@ public class PhonePowerCalculator extends PowerCalculator { @Override public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + final long energyConsumerUC = batteryStats.getPhoneEnergyConsumptionUC(); + final int powerModel = getPowerModel(energyConsumerUC, query); + final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000; - final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs); - if (phoneOnPower != 0) { - builder.getAggregateBatteryConsumerBuilder( - BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) - .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower) - .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs); + final double phoneOnPower; + switch (powerModel) { + case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY: + phoneOnPower = uCtoMah(energyConsumerUC); + break; + case BatteryConsumer.POWER_MODEL_POWER_PROFILE: + default: + phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs); } + + if (phoneOnPower == 0.0) return; + + builder.getAggregateBatteryConsumerBuilder( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower, powerModel) + .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs); + } } diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java index 7fb8696a217d..5bfdd62592c8 100644 --- a/core/java/com/android/internal/power/MeasuredEnergyStats.java +++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java @@ -59,7 +59,9 @@ public class MeasuredEnergyStats { public static final int POWER_BUCKET_BLUETOOTH = 5; public static final int POWER_BUCKET_GNSS = 6; public static final int POWER_BUCKET_MOBILE_RADIO = 7; - public static final int NUMBER_STANDARD_POWER_BUCKETS = 8; // Buckets above this are custom. + public static final int POWER_BUCKET_CAMERA = 8; + public static final int POWER_BUCKET_PHONE = 9; + public static final int NUMBER_STANDARD_POWER_BUCKETS = 10; // Buckets above this are custom. @IntDef(prefix = {"POWER_BUCKET_"}, value = { POWER_BUCKET_UNKNOWN, diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index fe08083282c5..c8a8b586590b 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -471,7 +471,7 @@ public class LatencyTracker { */ public void onActionStart(@Action int action, String tag) { synchronized (mLock) { - if (!isEnabled()) { + if (!isEnabled(action)) { return; } // skip if the action is already instrumenting. @@ -495,7 +495,7 @@ public class LatencyTracker { */ public void onActionEnd(@Action int action) { synchronized (mLock) { - if (!isEnabled()) { + if (!isEnabled(action)) { return; } Session session = mSessions.get(action); @@ -605,23 +605,27 @@ public class LatencyTracker { void begin(@NonNull Runnable timeoutAction) { mStartRtc = SystemClock.elapsedRealtime(); - Trace.asyncTraceBegin(TRACE_TAG_APP, traceName(), 0); + Trace.asyncTraceForTrackBegin(TRACE_TAG_APP, traceName(), traceName(), 0); // start counting timeout. - mTimeoutRunnable = timeoutAction; + mTimeoutRunnable = () -> { + Trace.instantForTrack(TRACE_TAG_APP, traceName(), "timeout"); + timeoutAction.run(); + }; BackgroundThread.getHandler() .postDelayed(mTimeoutRunnable, TimeUnit.SECONDS.toMillis(15)); } void end() { mEndRtc = SystemClock.elapsedRealtime(); - Trace.asyncTraceEnd(TRACE_TAG_APP, traceName(), 0); + Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), "end", 0); BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); mTimeoutRunnable = null; } void cancel() { - Trace.asyncTraceEnd(TRACE_TAG_APP, traceName(), 0); + Trace.instantForTrack(TRACE_TAG_APP, traceName(), "cancel"); + Trace.asyncTraceForTrackEnd(TRACE_TAG_APP, traceName(), "cancel", 0); BackgroundThread.getHandler().removeCallbacks(mTimeoutRunnable); mTimeoutRunnable = null; } diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index a8abe50a9755..2a670e865ced 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -556,7 +556,8 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jin // connect to camera service static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jint cameraId, jstring clientPackageName, - jboolean overrideToPortrait) { + jboolean overrideToPortrait, + jboolean forceSlowJpegMode) { // Convert jstring to String16 const char16_t *rawClientName = reinterpret_cast<const char16_t*>( env->GetStringChars(clientPackageName, NULL)); @@ -568,7 +569,7 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj int targetSdkVersion = android_get_application_target_sdk_version(); sp<Camera> camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID, - targetSdkVersion, overrideToPortrait); + targetSdkVersion, overrideToPortrait, forceSlowJpegMode); if (camera == NULL) { return -EACCES; } @@ -1054,7 +1055,7 @@ static const JNINativeMethod camMethods[] = { {"getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras}, {"_getCameraInfo", "(IZLandroid/hardware/Camera$CameraInfo;)V", (void *)android_hardware_Camera_getCameraInfo}, - {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;Z)I", + {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;ZZ)I", (void *)android_hardware_Camera_native_setup}, {"native_release", "()V", (void *)android_hardware_Camera_release}, {"setPreviewSurface", "(Landroid/view/Surface;)V", diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 16382abad181..05e777e3bcb9 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -577,7 +577,7 @@ <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilitza la biometria"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Fes servir la biometria o el bloqueig de pantalla"</string> - <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que ets tu"</string> + <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la teva identitat"</string> <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Utilitza la teva biometria per continuar"</string> <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Utilitza la biometria o el bloqueig de pantalla per continuar"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Maquinari biomètric no disponible"</string> @@ -1232,7 +1232,7 @@ <string name="screen_compat_mode_scale" msgid="8627359598437527726">"Escala"</string> <string name="screen_compat_mode_show" msgid="5080361367584709857">"Mostra sempre"</string> <string name="screen_compat_mode_hint" msgid="4032272159093750908">"Torna a activar-ho a Configuració del sistema > Aplicacions > Baixades."</string> - <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de pantalla actual i és possible que funcioni de manera inesperada."</string> + <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet la mida de visualització actual i és possible que funcioni de manera inesperada."</string> <string name="unsupported_display_size_show" msgid="980129850974919375">"Mostra sempre"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va crear per a una versió incompatible del sistema operatiu Android i pot funcionar de manera inesperada. És possible que hi hagi disponible una versió actualitzada de l\'aplicació."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Mostra sempre"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 05f7ca0dfbc8..02bee7e5d31f 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1255,7 +1255,7 @@ <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du har trykket på afbryderknappen, hvilket som regel slukker skærmen.\n\nPrøv at trykke let på knappen, mens du konfigurerer dit fingeraftryk."</string> <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Sluk skærmen for at afslutte konfigurationen"</string> <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Deaktiver"</string> - <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vil du bekræfte dit fingeraftryk?"</string> + <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vil du verificere dit fingeraftryk?"</string> <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du har trykket på afbryderknappen, hvilket som regel slukker skærmen.\n\nPrøv at trykke let på knappen for at bekræfte dit fingeraftryk."</string> <string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Sluk skærm"</string> <string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"Fortsæt"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 8c6285c5ca53..2227f6eea7ef 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1693,7 +1693,7 @@ <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"View and control screen"</string> <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"It can read all content on the screen and display content over other apps."</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"View and perform actions"</string> - <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"It can track your interactions with an app or a hardware sensor, and interact with apps on your behalf."</string> + <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"It can track your interactions with an app or a hardware sensor and interact with apps on your behalf."</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Allow"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Deny"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tap a feature to start using it:"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index a20714d528be..dff96b72e96e 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1691,7 +1691,7 @@ <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> को अपना डिवाइस पूरी तरह कंट्रोल करने की मंज़ूरी दें?"</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"पूरी तरह कंट्रोल करने की अनुमति उन ऐप्लिकेशन के लिए ठीक है जो सुलभता से जुड़ी ज़रूरतों के लिए बने हैं, लेकिन ज़्यादातर ऐप्लिकेशन के लिए यह ठीक नहीं है."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रीन को देखें और कंट्रोल करें"</string> - <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यह स्क्रीन पर दिखने वाली हर तरह के कॉन्टेंट को पढ़ सकता है और उसे दूसरे ऐप्लिकेशन पर दिखा सकता है."</string> + <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यह स्क्रीन पर दिखने वाले कॉन्टेंट को पढ़ सकता है और उसे दूसरे ऐप्लिकेशन के ऊपर दिखा सकता है."</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"देखें और कार्रवाई करें"</string> <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"यह आपके और किसी ऐप्लिकेशन या हार्डवेयर सेंसर के बीच होने वाले इंटरैक्शन को ट्रैक कर सकता है और आपकी तरफ़ से ऐप्लिकेशन के साथ इंटरैक्ट कर सकता है."</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"अनुमति दें"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index eabe2bdf64b9..daad65f94e09 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1692,7 +1692,7 @@ <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Vuoi consentire a <xliff:g id="SERVICE">%1$s</xliff:g> di avere il controllo totale del tuo dispositivo?"</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"Il controllo totale è appropriato per le app che rispondono alle tue esigenze di accessibilità, ma non per gran parte delle app."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Visualizzare e controllare lo schermo"</string> - <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Può leggere i contenuti presenti sullo schermo e mostrare i contenuti su altre app."</string> + <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Può leggere tutti i contenuti presenti sullo schermo e mostrare i contenuti sopra altre app."</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Visualizzare ed eseguire azioni"</string> <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Può tenere traccia delle tue interazioni con un\'app o un sensore hardware e interagire con app per tuo conto."</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Consenti"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 1e08228b4fac..513be119318b 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -587,11 +587,11 @@ <string name="biometric_error_generic" msgid="6784371929985434439">"एरर ऑथेंटिकेट करत आहे"</string> <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रीन लॉक वापरा"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"पुढे सुरू ठेवण्यासाठी तुमचे स्क्रीन लॉक एंटर करा"</string> - <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरवर जोरात दाबा"</string> + <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरवर जोरात प्रेस करा"</string> <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"फिंगरप्रिंट ओळखता आली नाही. पुन्हा प्रयत्न करा."</string> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिंट सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string> - <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात दाबा"</string> + <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात प्रेस करा"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"बोट खूप सावकाश हलविले. कृपया पुन्हा प्रयत्न करा."</string> <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पहा"</string> <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"खूप प्रखर"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index dca9de618071..ccf74a4d5460 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -2014,7 +2014,7 @@ <string name="autofill_update_title_with_2types" msgid="1797514386321086273">"Kemas kini <xliff:g id="TYPE_0">%1$s</xliff:g> dan <xliff:g id="TYPE_1">%2$s</xliff:g> dalam "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string> <string name="autofill_update_title_with_3types" msgid="1312232153076212291">"Kemas kini item ini dalam "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>": <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> dan <xliff:g id="TYPE_2">%3$s</xliff:g> ?"</string> <string name="autofill_save_yes" msgid="8035743017382012850">"Simpan"</string> - <string name="autofill_save_no" msgid="9212826374207023544">"Tidak, terima kasih"</string> + <string name="autofill_save_no" msgid="9212826374207023544">"Tidak perlu"</string> <string name="autofill_save_notnow" msgid="2853932672029024195">"Bukan sekarang"</string> <string name="autofill_save_never" msgid="6821841919831402526">"Jangan"</string> <string name="autofill_update_yes" msgid="4608662968996874445">"Kemas kini"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index ba43d799f371..42afe18d2c51 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1691,9 +1691,9 @@ <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Toestaan dat <xliff:g id="SERVICE">%1$s</xliff:g> volledige controle over je apparaat heeft?"</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"Volledige controle is gepast voor apps die je helpen met toegankelijkheid, maar niet voor de meeste apps."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Scherm bekijken en bedienen"</string> - <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"De functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string> + <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Deze functie kan alle content op het scherm lezen en content bovenop andere apps weergeven."</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Acties bekijken en uitvoeren"</string> - <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"De functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string> + <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Deze functie kan je interacties met een app of een hardwaresensor bijhouden en namens jou met apps communiceren."</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Toestaan"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Weigeren"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Tik op een functie om deze te gebruiken:"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 33f9219dc2fd..46aaa1f53a20 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -771,6 +771,11 @@ we rely on gravity to determine the effective orientation. --> <bool name="config_deskDockEnablesAccelerometer">true</bool> + <!-- Control whether nosensor and locked orientation requests are respected from the app when + config_deskDockEnablesAccelerometer is set to false. + TODO(b/274763533): Consider making true by default and removing this. --> + <bool name="config_deskRespectsNoSensorAndLockedWithoutAccelerometer">false</bool> + <!-- Car dock behavior --> <!-- The number of degrees to rotate the display when the device is in a car dock. @@ -5045,6 +5050,11 @@ of known compatibility issues. --> <string-array name="config_highRefreshRateBlacklist"></string-array> + <!-- The list of packages to force slowJpegMode for Apps using Camera API1 --> + <string-array name="config_forceSlowJpegModeList" translatable="false"> + <!-- Add packages here --> + </string-array> + <!-- Whether or not to hide the navigation bar when the soft keyboard is visible in order to create additional screen real estate outside beyond the keyboard. Note that the user needs to have a confirmed way to dismiss the keyboard when desired. --> @@ -5333,6 +5343,10 @@ <!-- Whether vertical reachability repositioning is allowed for letterboxed fullscreen apps. --> <bool name="config_letterboxIsVerticalReachabilityEnabled">false</bool> + <!-- Whether book mode automatic horizontal reachability positioning is allowed for letterboxed + fullscreen apps --> + <bool name="config_letterboxIsAutomaticReachabilityInBookModeEnabled">false</bool> + <!-- Default horizontal 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 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a0d69e22e2c5..1a3feb8b7c67 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1739,6 +1739,7 @@ <java-symbol type="bool" name="config_carDockEnablesAccelerometer" /> <java-symbol type="bool" name="config_customUserSwitchUi" /> <java-symbol type="bool" name="config_deskDockEnablesAccelerometer" /> + <java-symbol type="bool" name="config_deskRespectsNoSensorAndLockedWithoutAccelerometer" /> <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" /> <java-symbol type="bool" name="config_enableCarDockHomeLaunch" /> <java-symbol type="bool" name="config_enableLockBeforeUnlockScreen" /> @@ -4215,6 +4216,7 @@ <java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" /> + <java-symbol type="array" name="config_forceSlowJpegModeList" /> <java-symbol type="layout" name="chooser_dialog" /> <java-symbol type="layout" name="chooser_dialog_item" /> @@ -4475,6 +4477,7 @@ <java-symbol type="dimen" name="config_letterboxTabletopModePositionMultiplier" /> <java-symbol type="bool" name="config_letterboxIsHorizontalReachabilityEnabled" /> <java-symbol type="bool" name="config_letterboxIsVerticalReachabilityEnabled" /> + <java-symbol type="bool" name="config_letterboxIsAutomaticReachabilityInBookModeEnabled" /> <java-symbol type="integer" name="config_letterboxDefaultPositionForHorizontalReachability" /> <java-symbol type="integer" name="config_letterboxDefaultPositionForVerticalReachability" /> <java-symbol type="integer" name="config_letterboxDefaultPositionForBookModeReachability" /> diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java index eae1bbc930d4..17ed4c478350 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java @@ -15,6 +15,8 @@ */ package android.view.contentcapture; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.testng.Assert.assertThrows; @@ -54,4 +56,19 @@ public class ContentCaptureManagerTest { assertThrows(NullPointerException.class, () -> manager.removeData(null)); } + + @Test + @SuppressWarnings("GuardedBy") + public void testFlushViewTreeAppearingEventDisabled_setAndGet() { + final IContentCaptureManager mockService = mock(IContentCaptureManager.class); + final ContentCaptureOptions options = new ContentCaptureOptions(null); + final ContentCaptureManager manager = + new ContentCaptureManager(mMockContext, mockService, options); + + assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse(); + manager.setFlushViewTreeAppearingEventDisabled(true); + assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isTrue(); + manager.setFlushViewTreeAppearingEventDisabled(false); + assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse(); + } } diff --git a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java index d4276efe39c2..61899143b9c5 100644 --- a/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/app/procstats/ProcessStatsTest.java @@ -186,4 +186,19 @@ public class ProcessStatsTest extends TestCase { eq(0), eq(APP_1_PROCESS_NAME)); } + + @SmallTest + public void testSafelyResetClearsProcessInUidState() throws Exception { + ProcessStats processStats = new ProcessStats(); + ProcessState processState = + processStats.getProcessStateLocked( + APP_1_PACKAGE_NAME, APP_1_UID, APP_1_VERSION, APP_1_PROCESS_NAME); + processState.makeActive(); + UidState uidState = processStats.mUidStates.get(APP_1_UID); + assertTrue(uidState.isInUse()); + processState.makeInactive(); + uidState.resetSafely(NOW_MS); + processState.makeActive(); + assertFalse(uidState.isInUse()); + } } diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java index 00ac1985f897..0bdf491e6377 100644 --- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java @@ -245,6 +245,8 @@ public class MobileRadioPowerCalculatorTest { stats.noteNetworkInterfaceForTransports("cellular", new int[]{NetworkCapabilities.TRANSPORT_CELLULAR}); + stats.notePhoneOnLocked(9800, 9800); + // Note application network activity NetworkStats networkStats = new NetworkStats(10000, 1) .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0, @@ -257,27 +259,33 @@ public class MobileRadioPowerCalculatorTest { mStatsRule.setTime(12_000, 12_000); - MobileRadioPowerCalculator calculator = + MobileRadioPowerCalculator mobileRadioPowerCalculator = new MobileRadioPowerCalculator(mStatsRule.getPowerProfile()); - - mStatsRule.apply(calculator); + PhonePowerCalculator phonePowerCalculator = + new PhonePowerCalculator(mStatsRule.getPowerProfile()); + mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator); UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID); assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) - .isWithin(PRECISION).of(1.53934); + .isWithin(PRECISION).of(1.38541); assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer(); // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) - .isWithin(PRECISION).of(2.77778); + .isWithin(PRECISION).of(2.5); assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE)) + .isWithin(PRECISION).of(0.27778); + assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE)) + .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); + BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer(); assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) - .isWithin(PRECISION).of(1.53934); + .isWithin(PRECISION).of(1.38541); assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO)) .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY); } diff --git a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml index 9473cdd607d6..01df006f1bd2 100644 --- a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml +++ b/libs/WindowManager/Shell/res/color-night/taskbar_background.xml @@ -16,5 +16,5 @@ --> <!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@android:color/system_neutral1_500" android:lStar="15" /> + <item android:color="@android:color/system_neutral1_500" android:lStar="20" /> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml index 0e165fca4fd3..876ee02a8adf 100644 --- a/libs/WindowManager/Shell/res/color/taskbar_background.xml +++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml @@ -16,5 +16,5 @@ --> <!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@android:color/system_neutral1_500" android:lStar="95" /> + <item android:color="@android:color/system_neutral1_500" android:lStar="98" /> </selector>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/drawable/reachability_education_ic_left_hand.xml b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_left_hand.xml new file mode 100644 index 000000000000..c400dc676325 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_left_hand.xml @@ -0,0 +1,699 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 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. + --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector android:height="30dp" android:width="30dp" android:viewportHeight="30" + android:viewportWidth="30"> + <group android:name="_R_G" android:scaleX="-1" android:translateX="30"> + <group android:name="_R_G_L_0_G" android:translateX="-135" android:translateY="-135" + android:pivotX="150" android:pivotY="150" android:scaleX="0.1" + android:scaleY="0.1"> + <group android:name="_R_G_L_0_G_L_1_G" android:translateX="134.624" + android:translateY="87.514" android:pivotX="11.625" android:pivotY="6.39" + android:scaleX="10" android:scaleY="10"> + <group android:name="_R_G_L_0_G_L_1_G_D_0_P_0_G_0_T_0" + android:translateX="11.625" android:translateY="6.464" + android:scaleX="1" android:scaleY="1"> + <path android:name="_R_G_L_0_G_L_1_G_D_0_P_0" + android:fillColor="@color/letterbox_reachability_education_item_color" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M-1.54 5.39 C-3.87,4.71 -5.49,2.54 -5.49,0.11 C-5.49,-2.92 -3.03,-5.38 0,-5.38 C3.03,-5.38 5.49,-2.92 5.49,0.11 C5.49,2.11 4.41,3.95 2.66,4.92 C2.66,4.92 1.69,3.17 1.69,3.17 C2.8,2.55 3.49,1.38 3.49,0.11 C3.49,-1.82 1.93,-3.38 0,-3.38 C-1.93,-3.38 -3.49,-1.82 -3.49,0.11 C-3.49,1.65 -2.46,3.03 -0.98,3.47 C-0.98,3.47 -1.54,5.39 -1.54,5.39c "/> + </group> + </group> + <group android:name="_R_G_L_0_G_L_0_G" android:translateX="138" + android:translateY="138" android:pivotX="12" android:pivotY="12" + android:scaleX="10" android:scaleY="10"> + <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" + android:fillColor="@color/letterbox_reachability_education_item_color" + android:fillAlpha="1" android:fillType="nonZero" + android:pathData=" M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c "/> + </group> + </group> + </group> + <group android:name="time_group"/> + </vector> + </aapt:attr> + <target android:name="_R_G_L_0_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="fillAlpha" android:duration="500" + android:startOffset="0" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="500" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="750" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="833" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="1083" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="833" + android:startOffset="1167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="2000" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="2250" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="2333" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="2583" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="833" + android:startOffset="2667" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="3500" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="3750" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="3833" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="4083" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="833" + android:startOffset="4167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="5000" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="5250" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="5333" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="5583" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_L_1_G_D_0_P_0_G_0_T_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="scaleX" android:duration="500" + android:startOffset="0" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="500" + android:startOffset="0" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="1083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="1083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="833" + android:startOffset="1167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="833" + android:startOffset="1167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="2000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="2000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="2250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="2250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="2333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="2333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="2583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="2583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="833" + android:startOffset="2667" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="833" + android:startOffset="2667" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="3500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="3500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="3750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="3750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="3833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="3833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="4083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="4083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="833" + android:startOffset="4167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="833" + android:startOffset="4167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="5000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="5000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="5250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="5250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="5333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="5333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="5583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="5583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="500" + android:startOffset="0" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="500" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="750" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="833" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="1083" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="833" + android:startOffset="1167" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="2000" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="2250" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="2333" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="2583" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="833" + android:startOffset="2667" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="3500" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="3750" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="3833" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="4083" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="833" + android:startOffset="4167" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="5000" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="5250" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="5333" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="5583" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" android:duration="6000" + android:startOffset="0" android:valueFrom="0" android:valueTo="1" + android:valueType="floatType"/> + </set> + </aapt:attr> + </target> +</animated-vector> diff --git a/libs/WindowManager/Shell/res/drawable/reachability_education_ic_right_hand.xml b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_right_hand.xml new file mode 100644 index 000000000000..a807a770aa22 --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/reachability_education_ic_right_hand.xml @@ -0,0 +1,699 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 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. + --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector android:height="30dp" android:width="30dp" android:viewportHeight="30" + android:viewportWidth="30"> + <group android:name="_R_G"> + <group android:name="_R_G_L_0_G" android:translateX="-135" android:translateY="-135" + android:pivotX="150" android:pivotY="150" android:scaleX="0.1" + android:scaleY="0.1"> + <group android:name="_R_G_L_0_G_L_1_G" android:translateX="134.624" + android:translateY="87.514" android:pivotX="11.625" android:pivotY="6.39" + android:scaleX="10" android:scaleY="10"> + <group android:name="_R_G_L_0_G_L_1_G_D_0_P_0_G_0_T_0" + android:translateX="11.625" android:translateY="6.464" + android:scaleX="1" android:scaleY="1"> + <path android:name="_R_G_L_0_G_L_1_G_D_0_P_0" + android:fillColor="@color/letterbox_reachability_education_item_color" + android:fillAlpha="1" + android:fillType="nonZero" + android:pathData=" M-1.54 5.39 C-3.87,4.71 -5.49,2.54 -5.49,0.11 C-5.49,-2.92 -3.03,-5.38 0,-5.38 C3.03,-5.38 5.49,-2.92 5.49,0.11 C5.49,2.11 4.41,3.95 2.66,4.92 C2.66,4.92 1.69,3.17 1.69,3.17 C2.8,2.55 3.49,1.38 3.49,0.11 C3.49,-1.82 1.93,-3.38 0,-3.38 C-1.93,-3.38 -3.49,-1.82 -3.49,0.11 C-3.49,1.65 -2.46,3.03 -0.98,3.47 C-0.98,3.47 -1.54,5.39 -1.54,5.39c "/> + </group> + </group> + <group android:name="_R_G_L_0_G_L_0_G" android:translateX="138" + android:translateY="138" android:pivotX="12" android:pivotY="12" + android:scaleX="10" android:scaleY="10"> + <path android:name="_R_G_L_0_G_L_0_G_D_0_P_0" + android:fillColor="@color/letterbox_reachability_education_item_color" + android:fillAlpha="1" android:fillType="nonZero" + android:pathData=" M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c "/> + </group> + </group> + </group> + <group android:name="time_group"/> + </vector> + </aapt:attr> + <target android:name="_R_G_L_0_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="fillAlpha" android:duration="500" + android:startOffset="0" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="500" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="750" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="833" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="1083" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="833" + android:startOffset="1167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="2000" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="2250" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="2333" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="2583" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="833" + android:startOffset="2667" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="3500" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="3750" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="3833" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="4083" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="833" + android:startOffset="4167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="5000" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="5250" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="250" + android:startOffset="5333" android:valueFrom="1" + android:valueTo="0.1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="fillAlpha" android:duration="83" + android:startOffset="5583" android:valueFrom="0.1" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator + android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_L_1_G_D_0_P_0_G_0_T_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="scaleX" android:duration="500" + android:startOffset="0" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="500" + android:startOffset="0" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="1083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="1083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="833" + android:startOffset="1167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="833" + android:startOffset="1167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="2000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="2000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="2250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="2250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="2333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="2333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="2583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="2583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="833" + android:startOffset="2667" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="833" + android:startOffset="2667" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="3500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="3500" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="3750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="3750" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="3833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="3833" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="4083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="4083" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="833" + android:startOffset="4167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="833" + android:startOffset="4167" android:valueFrom="1" android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="5000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="5000" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="5250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="5250" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="250" + android:startOffset="5333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="250" + android:startOffset="5333" android:valueFrom="1" + android:valueTo="1.4000000000000001" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleX" android:duration="83" + android:startOffset="5583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="scaleY" android:duration="83" + android:startOffset="5583" android:valueFrom="1.4000000000000001" + android:valueTo="1" android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.3,0 0.999,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="pathData" android:duration="500" + android:startOffset="0" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="500" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="750" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="833" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="1083" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="833" + android:startOffset="1167" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="2000" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="2250" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="2333" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="2583" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="833" + android:startOffset="2667" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="3500" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="3750" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="3833" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="4083" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="833" + android:startOffset="4167" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0 0.833,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="5000" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="5250" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="250" + android:startOffset="5333" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + <objectAnimator android:propertyName="pathData" android:duration="83" + android:startOffset="5583" + android:valueFrom="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,8 14.13,8 C14.13,7.3 13.88,6.71 13.4,6.23 C12.92,5.74 12.33,5.5 11.63,5.5 C10.93,5.5 10.33,5.74 9.85,6.23 C9.37,6.71 9.13,7.3 9.13,8 C9.13,8 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,8 11.13,8 C11.13,7.85 11.17,7.73 11.26,7.64 C11.35,7.55 11.48,7.5 11.63,7.5 C11.78,7.5 11.9,7.55 11.99,7.64 C12.08,7.73 12.13,7.85 12.13,8 C12.13,8 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueTo="M19.81 13.64 C19.62,13.23 19.33,12.93 18.93,12.75 C18.93,12.75 15.23,10.95 15.23,10.95 C15.16,10.9 15.09,10.86 15.01,10.84 C14.99,10.83 14.96,10.83 14.94,10.83 C14.88,10.81 14.83,10.8 14.78,10.8 C14.78,10.8 14.13,10.8 14.13,10.8 C14.13,10.8 14.13,8.9 14.13,8.9 C14.13,8.9 14.13,6.5 14.13,6.5 C14.13,5.8 13.88,5.21 13.4,4.72 C12.92,4.24 12.33,4 11.63,4 C10.93,4 10.33,4.24 9.85,4.72 C9.37,5.21 9.13,5.8 9.13,6.5 C9.13,6.5 9.13,8.95 9.13,8.95 C9.13,8.95 9.13,11.4 9.13,11.4 C9.13,11.4 9.13,14.65 9.13,14.65 C9.13,14.65 7.18,14.2 7.18,14.2 C6.86,14.12 6.56,14.14 6.26,14.26 C5.97,14.39 5.71,14.57 5.48,14.8 C5.48,14.8 4.08,16.25 4.08,16.25 C4.08,16.25 9.23,21.4 9.23,21.4 C9.41,21.58 9.63,21.73 9.88,21.84 C10.13,21.95 10.39,22 10.68,22 C10.68,22 17.08,22 17.08,22 C17.56,22 17.99,21.85 18.38,21.54 C18.76,21.23 18.99,20.83 19.08,20.35 C19.08,20.35 19.98,14.9 19.98,14.9 C20.06,14.47 20,14.05 19.81,13.64c M17.08 20 C17.08,20 10.68,20 10.68,20 C10.68,20 6.88,16.2 6.88,16.2 C6.88,16.2 11.13,17.1 11.13,17.1 C11.13,17.1 11.13,6.5 11.13,6.5 C11.13,6.35 11.17,6.23 11.26,6.14 C11.35,6.05 11.48,6 11.63,6 C11.78,6 11.9,6.05 11.99,6.14 C12.08,6.23 12.13,6.35 12.13,6.5 C12.13,6.5 12.13,12.5 12.13,12.5 C12.13,12.5 13.88,12.5 13.88,12.5 C13.88,12.5 18.02,14.55 18.02,14.55 C18.02,14.55 17.08,20 17.08,20c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.001,0 0,1 1.0,1.0"/> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator android:propertyName="translateX" android:duration="6000" + android:startOffset="0" android:valueFrom="0" android:valueTo="1" + android:valueType="floatType"/> + </set> + </aapt:attr> + </target> +</animated-vector> diff --git a/libs/WindowManager/Shell/res/layout/reachability_ui_layout.xml b/libs/WindowManager/Shell/res/layout/reachability_ui_layout.xml new file mode 100644 index 000000000000..1e36fb62f8da --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/reachability_ui_layout.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 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. + --> +<com.android.wm.shell.compatui.ReachabilityEduLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:focusable="false" + android:focusableInTouchMode="false" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.android.wm.shell.compatui.ReachabilityEduHandLayout + style="@style/ReachabilityEduHandLayout" + android:text="@string/letterbox_reachability_reposition_text" + app:drawableTopCompat="@drawable/reachability_education_ic_right_hand" + android:layout_gravity="center_horizontal|top" + android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin" + android:id="@+id/reachability_move_up_button" + android:maxWidth="@dimen/letterbox_reachability_education_item_width" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <com.android.wm.shell.compatui.ReachabilityEduHandLayout + style="@style/ReachabilityEduHandLayout" + android:text="@string/letterbox_reachability_reposition_text" + app:drawableTopCompat="@drawable/reachability_education_ic_right_hand" + android:layout_gravity="center_vertical|right" + android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin" + android:id="@+id/reachability_move_right_button" + android:maxWidth="@dimen/letterbox_reachability_education_item_width" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + + <com.android.wm.shell.compatui.ReachabilityEduHandLayout + style="@style/ReachabilityEduHandLayout" + android:text="@string/letterbox_reachability_reposition_text" + app:drawableTopCompat="@drawable/reachability_education_ic_left_hand" + android:layout_gravity="center_vertical|left" + android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin" + android:id="@+id/reachability_move_left_button" + android:maxWidth="@dimen/letterbox_reachability_education_item_width" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <com.android.wm.shell.compatui.ReachabilityEduHandLayout + style="@style/ReachabilityEduHandLayout" + android:text="@string/letterbox_reachability_reposition_text" + app:drawableTopCompat="@drawable/reachability_education_ic_right_hand" + android:layout_gravity="center_horizontal|bottom" + android:layout_marginTop="@dimen/letterbox_reachability_education_dialog_margin" + android:id="@+id/reachability_move_down_button" + android:maxWidth="@dimen/letterbox_reachability_education_item_width" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + +</com.android.wm.shell.compatui.ReachabilityEduLayout> diff --git a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml index a9779b3a3e89..660212a66935 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings_tv.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings_tv.xml @@ -24,7 +24,7 @@ <string name="pip_move" msgid="158770205886688553">"हलवा"</string> <string name="pip_expand" msgid="1051966011679297308">"विस्तार करा"</string> <string name="pip_collapse" msgid="3903295106641385962">"कोलॅप्स करा"</string> - <string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा दाबा"</string> + <string name="pip_edu_text" msgid="3672999496647508701">" नियंत्रणांसाठी "<annotation icon="home_icon">" होम "</annotation>" दोनदा प्रेस करा"</string> <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"चित्रात-चित्र मेनू."</string> <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"डावीकडे हलवा"</string> <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"उजवीकडे हलवा"</string> diff --git a/libs/WindowManager/Shell/res/values/attrs.xml b/libs/WindowManager/Shell/res/values/attrs.xml index 2aad4c1c1805..fbb5caa508de 100644 --- a/libs/WindowManager/Shell/res/values/attrs.xml +++ b/libs/WindowManager/Shell/res/values/attrs.xml @@ -1,5 +1,5 @@ <!-- - ~ Copyright (C) 2022 The Android Open Source Project + ~ Copyright (C) 2023 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. diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index 6fb70006e67f..7d5760e47189 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -45,6 +45,9 @@ <!-- Letterbox Dialog --> <color name="letterbox_dialog_background">@android:color/system_neutral1_900</color> + <!-- Reachability Education color for hand icon and text--> + <color name="letterbox_reachability_education_item_color">#BFC8CC</color> + <!-- GM2 colors --> <color name="GM2_grey_200">#E8EAED</color> <color name="GM2_grey_700">#5F6368</color> diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 680ad5101366..04b53f266a09 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -327,6 +327,15 @@ <!-- The vertical padding for the buttons in the letterbox restart dialog --> <dimen name="letterbox_restart_dialog_vertical_padding">8dp</dimen> + <!-- The margin between the reachability dialog container and its parent. --> + <dimen name="letterbox_reachability_education_dialog_margin">16dp</dimen> + + <!-- The width of each item in the reachability education --> + <dimen name="letterbox_reachability_education_item_width">118dp</dimen> + + <!-- The size of the icon in the item of reachability education --> + <dimen name="letterbox_reachability_education_item_image_size">24dp</dimen> + <!-- The width of the brand image on staring surface. --> <dimen name="starting_surface_brand_image_width">200dp</dimen> diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml index 6399232919d2..523657b80317 100644 --- a/libs/WindowManager/Shell/res/values/strings.xml +++ b/libs/WindowManager/Shell/res/values/strings.xml @@ -214,6 +214,17 @@ <!-- Checkbox text for asking to not show the restart confirmation dialog again. [CHAR LIMIT=NONE] --> <string name="letterbox_restart_dialog_checkbox_title">Don\u2019t show again</string> + <!-- When an app is letterboxed, it is initially centered on the screen but the user can + double tap to move the app to a different position. With a double-tap on the right, + the app moves the right of the screen and with a double-tap on the left the app moves + on the left. The same happens if the app has space to be moved to the top or bottom of + the screen. This time the double-tap can happen on the top or bottom of the screen. + To teach the user about this feature, we display an education explaining how the double-tap + works and how the app can be moved on the screen. + This is the text we show to the user below an animated icon visualizing the double-tap + action. [CHAR LIMIT=NONE] --> + <string name="letterbox_reachability_reposition_text">Double-tap to move this app</string> + <!-- Freeform window caption strings --> <!-- Accessibility text for the maximize window button [CHAR LIMIT=NONE] --> <string name="maximize_button_text">Maximize</string> diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml index bc2e71d1c013..d0782ad9b37e 100644 --- a/libs/WindowManager/Shell/res/values/styles.xml +++ b/libs/WindowManager/Shell/res/values/styles.xml @@ -144,4 +144,20 @@ @*android:string/config_bodyFontFamily </item> </style> + + <style name="ReachabilityEduHandLayout" parent="Theme.AppCompat"> + <item name="android:focusable">false</item> + <item name="android:focusableInTouchMode">false</item> + <item name="android:background">@android:color/transparent</item> + <item name="android:contentDescription">@string/restart_button_description</item> + <item name="android:visibility">invisible</item> + <item name="android:lineSpacingExtra">-1sp</item> + <item name="android:textSize">12sp</item> + <item name="android:textAlignment">center</item> + <item name="android:textColor">@color/letterbox_reachability_education_item_color</item> + <item name="android:textAppearance"> + @*android:style/TextAppearance.DeviceDefault.Body2 + </item> + </style> + </resources> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java index cb1a6e7ace6b..ac6e4c2a6521 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java @@ -59,7 +59,7 @@ public class TabletopModeController implements */ private static final boolean ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP = SystemProperties.getBoolean( - "persist.wm.debug.enable_move_floating_window_in_tabletop", false); + "persist.wm.debug.enable_move_floating_window_in_tabletop", true); /** * Prefer the {@link #PREFERRED_TABLETOP_HALF_TOP} if this flag is enabled, 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 ffc56b6f6106..b4acd6046182 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 @@ -727,6 +727,10 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange getRefBounds2(mTempRect); t.setPosition(leash2, mTempRect.left, mTempRect.top) .setWindowCrop(leash2, mTempRect.width(), mTempRect.height()); + // Make right or bottom side surface always higher than left or top side to avoid weird + // animation when dismiss split. e.g. App surface fling above on decor surface. + t.setLayer(leash1, 1); + t.setLayer(leash2, 2); if (mImePositionProcessor.adjustSurfaceLayoutForIme( t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java index 06f0a70d3d0f..902c41c8fd2d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIConfiguration.java @@ -39,22 +39,41 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi "enable_letterbox_restart_confirmation_dialog"; private static final String KEY_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = - "enable_letterbox_reachability_education"; + "enable_letterbox_education_for_reachability"; private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_RESTART_DIALOG = true; - private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = false; + private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION = true; /** - * The name of the {@link SharedPreferences} that holds which user has seen the Restart - * confirmation dialog. + * The name of the {@link SharedPreferences} that holds information about compat ui. */ - private static final String DONT_SHOW_RESTART_DIALOG_PREF_NAME = "dont_show_restart_dialog"; + private static final String COMPAT_UI_SHARED_PREFERENCES = "dont_show_restart_dialog"; /** - * The {@link SharedPreferences} instance for {@link #DONT_SHOW_RESTART_DIALOG_PREF_NAME}. + * The name of the {@link SharedPreferences} that holds which user has seen the Letterbox + * Education dialog. */ - private final SharedPreferences mSharedPreferences; + private static final String HAS_SEEN_LETTERBOX_EDUCATION_SHARED_PREFERENCES = + "has_seen_letterbox_education"; + + /** + * Key prefix for the {@link SharedPreferences} entries related to the reachability + * education. + */ + private static final String HAS_SEEN_REACHABILITY_EDUCATION_KEY_PREFIX = + "has_seen_reachability_education"; + + /** + * The {@link SharedPreferences} instance for the restart dialog and the reachability + * education. + */ + private final SharedPreferences mCompatUISharedPreferences; + + /** + * The {@link SharedPreferences} instance for the letterbox education dialog. + */ + private final SharedPreferences mLetterboxEduSharedPreferences; // Whether the extended restart dialog is enabled private boolean mIsRestartDialogEnabled; @@ -88,8 +107,10 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi DEFAULT_VALUE_ENABLE_LETTERBOX_REACHABILITY_EDUCATION); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT, mainExecutor, this); - mSharedPreferences = context.getSharedPreferences(DONT_SHOW_RESTART_DIALOG_PREF_NAME, + mCompatUISharedPreferences = context.getSharedPreferences(getCompatUISharedPreferenceName(), Context.MODE_PRIVATE); + mLetterboxEduSharedPreferences = context.getSharedPreferences( + getHasSeenLetterboxEducationSharedPreferencedName(), Context.MODE_PRIVATE); } /** @@ -122,20 +143,53 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi mIsReachabilityEducationOverrideEnabled = enabled; } - boolean getDontShowRestartDialogAgain(TaskInfo taskInfo) { - final int userId = taskInfo.userId; - final String packageName = taskInfo.topActivity.getPackageName(); - return mSharedPreferences.getBoolean( - getDontShowAgainRestartKey(userId, packageName), /* default= */ false); + void setDontShowRestartDialogAgain(TaskInfo taskInfo) { + mCompatUISharedPreferences.edit().putBoolean( + getDontShowAgainRestartKey(taskInfo.userId, taskInfo.topActivity.getPackageName()), + true).apply(); } - void setDontShowRestartDialogAgain(TaskInfo taskInfo) { - final int userId = taskInfo.userId; - final String packageName = taskInfo.topActivity.getPackageName(); - mSharedPreferences.edit().putBoolean(getDontShowAgainRestartKey(userId, packageName), + boolean shouldShowRestartDialogAgain(TaskInfo taskInfo) { + return !mCompatUISharedPreferences.getBoolean(getDontShowAgainRestartKey(taskInfo.userId, + taskInfo.topActivity.getPackageName()), /* default= */ false); + } + + void setDontShowReachabilityEducationAgain(TaskInfo taskInfo) { + mCompatUISharedPreferences.edit().putBoolean( + getDontShowAgainReachabilityEduKey(taskInfo.userId, + taskInfo.topActivity.getPackageName()), true).apply(); + } + + boolean shouldShowReachabilityEducation(@NonNull TaskInfo taskInfo) { + return getHasSeenLetterboxEducation(taskInfo.userId) + && !mCompatUISharedPreferences.getBoolean( + getDontShowAgainReachabilityEduKey(taskInfo.userId, + taskInfo.topActivity.getPackageName()), /* default= */false); + } + + boolean getHasSeenLetterboxEducation(int userId) { + return mLetterboxEduSharedPreferences + .getBoolean(getDontShowLetterboxEduKey(userId), /* default= */ false); + } + + void setSeenLetterboxEducation(int userId) { + mLetterboxEduSharedPreferences.edit().putBoolean(getDontShowLetterboxEduKey(userId), true).apply(); } + protected String getCompatUISharedPreferenceName() { + return COMPAT_UI_SHARED_PREFERENCES; + } + + protected String getHasSeenLetterboxEducationSharedPreferencedName() { + return HAS_SEEN_LETTERBOX_EDUCATION_SHARED_PREFERENCES; + } + + /** + * Updates the {@link DeviceConfig} state for the CompatUI + * @param properties Contains the complete collection of properties which have changed for a + * single namespace. This includes only those which were added, updated, + */ @Override public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { if (properties.getKeyset().contains(KEY_ENABLE_LETTERBOX_RESTART_DIALOG)) { @@ -152,6 +206,14 @@ public class CompatUIConfiguration implements DeviceConfig.OnPropertiesChangedLi } } + private static String getDontShowAgainReachabilityEduKey(int userId, String packageName) { + return HAS_SEEN_REACHABILITY_EDUCATION_KEY_PREFIX + "_" + packageName + "@" + userId; + } + + private static String getDontShowLetterboxEduKey(int userId) { + return String.valueOf(userId); + } + private String getDontShowAgainRestartKey(int userId, String packageName) { return packageName + "@" + userId; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index 6950f24512b1..4d83247e5c03 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -112,6 +112,12 @@ public class CompatUIController implements OnDisplaysChangedListener, @Nullable private LetterboxEduWindowManager mActiveLetterboxEduLayout; + /** + * The active Reachability UI layout. + */ + @Nullable + private ReachabilityEduWindowManager mActiveReachabilityEduLayout; + /** Avoid creating display context frequently for non-default display. */ private final SparseArray<WeakReference<Context>> mDisplayContextCache = new SparseArray<>(0); @@ -195,6 +201,7 @@ public class CompatUIController implements OnDisplaysChangedListener, createOrUpdateCompatLayout(taskInfo, taskListener); createOrUpdateLetterboxEduLayout(taskInfo, taskListener); createOrUpdateRestartDialogLayout(taskInfo, taskListener); + createOrUpdateReachabilityEduLayout(taskInfo, taskListener, false); } @Override @@ -308,7 +315,7 @@ public class CompatUIController implements OnDisplaysChangedListener, private void onRestartButtonClicked( Pair<TaskInfo, ShellTaskOrganizer.TaskListener> taskInfoState) { if (mCompatUIConfiguration.isRestartDialogEnabled() - && !mCompatUIConfiguration.getDontShowRestartDialogAgain( + && mCompatUIConfiguration.shouldShowRestartDialogAgain( taskInfoState.first)) { // We need to show the dialog mSetOfTaskIdsShowingRestartDialog.add(taskInfoState.first.taskId); @@ -355,13 +362,15 @@ public class CompatUIController implements OnDisplaysChangedListener, ShellTaskOrganizer.TaskListener taskListener) { return new LetterboxEduWindowManager(context, taskInfo, mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), - mTransitionsLazy.get(), - this::onLetterboxEduDismissed, - mDockStateReader); + mTransitionsLazy.get(), this::onLetterboxEduDismissed, mDockStateReader, + mCompatUIConfiguration); } - private void onLetterboxEduDismissed() { + private void onLetterboxEduDismissed( + Pair<TaskInfo, ShellTaskOrganizer.TaskListener> stateInfo) { mActiveLetterboxEduLayout = null; + // We need to update the UI + createOrUpdateReachabilityEduLayout(stateInfo.first, stateInfo.second, true); } private void createOrUpdateRestartDialogLayout(TaskInfo taskInfo, @@ -419,6 +428,47 @@ public class CompatUIController implements OnDisplaysChangedListener, onCompatInfoChanged(stateInfo.first, stateInfo.second); } + private void createOrUpdateReachabilityEduLayout(TaskInfo taskInfo, + ShellTaskOrganizer.TaskListener taskListener, boolean forceUpdate) { + if (mActiveReachabilityEduLayout != null) { + mActiveReachabilityEduLayout.forceUpdate(forceUpdate); + // UI already exists, update the UI layout. + if (!mActiveReachabilityEduLayout.updateCompatInfo(taskInfo, taskListener, + showOnDisplay(mActiveReachabilityEduLayout.getDisplayId()))) { + // The layout is no longer eligible to be shown, remove from active layouts. + mActiveReachabilityEduLayout = null; + } + return; + } + // Create a new UI layout. + final Context context = getOrCreateDisplayContext(taskInfo.displayId); + if (context == null) { + return; + } + ReachabilityEduWindowManager newLayout = createReachabilityEduWindowManager(context, + taskInfo, taskListener); + if (newLayout.createLayout(showOnDisplay(taskInfo.displayId))) { + // The new layout is eligible to be shown, make it the active layout. + if (mActiveReachabilityEduLayout != null) { + // Release the previous layout since at most one can be active. + // Since letterbox reachability education is only shown once to the user, + // releasing the previous layout is only a precaution. + mActiveReachabilityEduLayout.release(); + } + mActiveReachabilityEduLayout = newLayout; + } + } + + @VisibleForTesting + ReachabilityEduWindowManager createReachabilityEduWindowManager(Context context, + TaskInfo taskInfo, + ShellTaskOrganizer.TaskListener taskListener) { + return new ReachabilityEduWindowManager(context, taskInfo, mSyncQueue, mCallback, + taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId), + mCompatUIConfiguration, mMainExecutor); + } + + private void removeLayouts(int taskId) { final CompatUIWindowManager layout = mActiveCompatLayouts.get(taskId); if (layout != null) { @@ -438,6 +488,11 @@ public class CompatUIController implements OnDisplaysChangedListener, mTaskIdToRestartDialogWindowManagerMap.remove(taskId); mSetOfTaskIdsShowingRestartDialog.remove(taskId); } + if (mActiveReachabilityEduLayout != null + && mActiveReachabilityEduLayout.getTaskId() == taskId) { + mActiveReachabilityEduLayout.release(); + mActiveReachabilityEduLayout = null; + } } private Context getOrCreateDisplayContext(int displayId) { @@ -490,6 +545,9 @@ public class CompatUIController implements OnDisplaysChangedListener, callback.accept(layout); } } + if (mActiveReachabilityEduLayout != null && condition.test(mActiveReachabilityEduLayout)) { + callback.accept(mActiveReachabilityEduLayout); + } } /** An implementation of {@link OnInsetsChangedListener} for a given display id. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java index cfb2accbcecd..346cd940e678 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java @@ -384,7 +384,7 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana // Cannot be wrap_content as this determines the actual window size width, height, TYPE_APPLICATION_OVERLAY, - FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL, + getWindowManagerLayoutParamsFlags(), PixelFormat.TRANSLUCENT); winParams.token = new Binder(); winParams.setTitle(getClass().getSimpleName() + mTaskId); @@ -392,6 +392,13 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana return winParams; } + /** + * @return Flags to use for the {@link WindowManager} layout + */ + protected int getWindowManagerLayoutParamsFlags() { + return FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL; + } + protected final String getTag() { return getClass().getSimpleName(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java index bfdbfe3d6ea0..0c21c8ccd686 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/LetterboxEduWindowManager.java @@ -18,12 +18,13 @@ package com.android.wm.shell.compatui; import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.TaskInfo; import android.content.Context; -import android.content.SharedPreferences; import android.graphics.Rect; import android.provider.Settings; +import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.MarginLayoutParams; @@ -38,10 +39,12 @@ import com.android.wm.shell.common.DockStateReader; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.transition.Transitions; +import java.util.function.Consumer; + /** * Window manager for the Letterbox Education. */ -public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { +class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { /** * The Letterbox Education should be the topmost child of the Task in case there can be more @@ -49,19 +52,6 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { */ public static final int Z_ORDER = Integer.MAX_VALUE; - /** - * The name of the {@link SharedPreferences} that holds which user has seen the Letterbox - * Education dialog. - */ - @VisibleForTesting - static final String HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME = - "has_seen_letterbox_education"; - - /** - * The {@link SharedPreferences} instance for {@link #HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME}. - */ - private final SharedPreferences mSharedPreferences; - private final DialogAnimationController<LetterboxEduDialogLayout> mAnimationController; private final Transitions mTransitions; @@ -73,6 +63,10 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { */ private final int mUserId; + private final Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnDismissCallback; + + private final CompatUIConfiguration mCompatUIConfiguration; + // Remember the last reported state in case visibility changes due to keyguard or IME updates. private boolean mEligibleForLetterboxEducation; @@ -80,7 +74,8 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { @VisibleForTesting LetterboxEduDialogLayout mLayout; - private final Runnable mOnDismissCallback; + @NonNull + private TaskInfo mTaskInfo; /** * The vertical margin between the dialog container and the task stable bounds (excluding @@ -90,33 +85,35 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { private final DockStateReader mDockStateReader; - public LetterboxEduWindowManager(Context context, TaskInfo taskInfo, + LetterboxEduWindowManager(Context context, TaskInfo taskInfo, SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, Transitions transitions, - Runnable onDismissCallback, DockStateReader dockStateReader) { + Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onDismissCallback, + DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration) { this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions, onDismissCallback, new DialogAnimationController<>(context, /* tag */ "LetterboxEduWindowManager"), - dockStateReader); + dockStateReader, compatUIConfiguration); } @VisibleForTesting LetterboxEduWindowManager(Context context, TaskInfo taskInfo, SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener, - DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback, + DisplayLayout displayLayout, Transitions transitions, + Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> onDismissCallback, DialogAnimationController<LetterboxEduDialogLayout> animationController, - DockStateReader dockStateReader) { + DockStateReader dockStateReader, CompatUIConfiguration compatUIConfiguration) { super(context, taskInfo, syncQueue, taskListener, displayLayout); + mTaskInfo = taskInfo; mTransitions = transitions; mOnDismissCallback = onDismissCallback; mAnimationController = animationController; mUserId = taskInfo.userId; - mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation; - mSharedPreferences = mContext.getSharedPreferences(HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME, - Context.MODE_PRIVATE); mDialogVerticalMargin = (int) mContext.getResources().getDimension( R.dimen.letterbox_education_dialog_margin); mDockStateReader = dockStateReader; + mCompatUIConfiguration = compatUIConfiguration; + mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation; } @Override @@ -142,8 +139,8 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { // the controller will create a new instance of this class since this one isn't eligible). // - If the layout isn't null then it was previously showing, and we shouldn't check if the // user has seen the letterbox education before. - return mEligibleForLetterboxEducation && !isTaskbarEduShowing() - && (mLayout != null || !getHasSeenLetterboxEducation()) + return mEligibleForLetterboxEducation && !isTaskbarEduShowing() && (mLayout != null + || !mCompatUIConfiguration.getHasSeenLetterboxEducation(mUserId)) && !mDockStateReader.isDocked(); } @@ -192,7 +189,6 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { // Dialog has already been released. return; } - setSeenLetterboxEducation(); mLayout.setDismissOnClickListener(this::onDismiss); // Focus on the dialog title for accessibility. mLayout.getDialogTitle().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); @@ -202,10 +198,11 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { if (mLayout == null) { return; } + mCompatUIConfiguration.setSeenLetterboxEducation(mUserId); mLayout.setDismissOnClickListener(null); mAnimationController.startExitAnimation(mLayout, () -> { release(); - mOnDismissCallback.run(); + mOnDismissCallback.accept(Pair.create(mTaskInfo, getTaskListener())); }); } @@ -218,6 +215,7 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { @Override public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener, boolean canShow) { + mTaskInfo = taskInfo; mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation; return super.updateCompatInfo(taskInfo, taskListener, canShow); @@ -248,18 +246,6 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { taskBounds.height()); } - private boolean getHasSeenLetterboxEducation() { - return mSharedPreferences.getBoolean(getPrefKey(), /* default= */ false); - } - - private void setSeenLetterboxEducation() { - mSharedPreferences.edit().putBoolean(getPrefKey(), true).apply(); - } - - private String getPrefKey() { - return String.valueOf(mUserId); - } - @VisibleForTesting boolean isTaskbarEduShowing() { return Settings.Secure.getInt(mContext.getContentResolver(), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduHandLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduHandLayout.java new file mode 100644 index 000000000000..6081ef1ca307 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduHandLayout.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2023 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.compatui; + +import android.content.Context; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; + +import androidx.appcompat.widget.AppCompatTextView; + +/** + * Custom layout for Reachability Education hand. + */ +public class ReachabilityEduHandLayout extends AppCompatTextView { + + private Drawable mHandDrawable; + + public ReachabilityEduHandLayout(Context context) { + this(context, null); + } + + public ReachabilityEduHandLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ReachabilityEduHandLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mHandDrawable = getCompoundDrawables()[/* top */ 1]; + } + + void hide() { + stopAnimation(); + setAlpha(0); + setVisibility(View.INVISIBLE); + } + + void startAnimation() { + if (mHandDrawable instanceof Animatable) { + final Animatable animatedBg = (Animatable) mHandDrawable; + animatedBg.start(); + } + } + + void stopAnimation() { + if (mHandDrawable instanceof Animatable) { + final Animatable animatedBg = (Animatable) mHandDrawable; + animatedBg.stop(); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduLayout.java new file mode 100644 index 000000000000..6a72d28521b8 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduLayout.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2023 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.compatui; + +import android.animation.Animator; +import android.animation.ValueAnimator; +import android.app.TaskInfo; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.widget.FrameLayout; + +import com.android.wm.shell.R; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * Container for reachability education which handles all the show/hide animations. + */ +public class ReachabilityEduLayout extends FrameLayout { + + private static final float ALPHA_FULL_TRANSPARENT = 0f; + + private static final float ALPHA_FULL_OPAQUE = 1f; + + private static final long VISIBILITY_SHOW_ANIMATION_DURATION_MS = 167; + + private static final long VISIBILITY_SHOW_ANIMATION_DELAY_MS = 250; + + private static final long VISIBILITY_SHOW_DOUBLE_TAP_ANIMATION_DELAY_MS = 80; + + private static final long MARGINS_ANIMATION_DURATION_MS = 250; + + private ReachabilityEduWindowManager mWindowManager; + + private ReachabilityEduHandLayout mMoveLeftButton; + private ReachabilityEduHandLayout mMoveRightButton; + private ReachabilityEduHandLayout mMoveUpButton; + private ReachabilityEduHandLayout mMoveDownButton; + + private int mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET; + private int mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET; + private int mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET; + private int mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET; + + private boolean mIsLayoutActive; + + public ReachabilityEduLayout(Context context) { + this(context, null); + } + + public ReachabilityEduLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ReachabilityEduLayout(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public ReachabilityEduLayout(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + void inject(ReachabilityEduWindowManager windowManager) { + mWindowManager = windowManager; + } + + void handleVisibility(boolean isActivityLetterboxed, int letterboxVerticalPosition, + int letterboxHorizontalPosition, int availableWidth, int availableHeight, + boolean isDoubleTap) { + // If the app is not letterboxed we hide all the buttons. + if (!mIsLayoutActive || !isActivityLetterboxed || ( + letterboxHorizontalPosition == TaskInfo.PROPERTY_VALUE_UNSET + && letterboxVerticalPosition == TaskInfo.PROPERTY_VALUE_UNSET)) { + hideAllImmediately(); + } else if (letterboxHorizontalPosition != TaskInfo.PROPERTY_VALUE_UNSET) { + handleLetterboxHorizontalPosition(availableWidth, letterboxHorizontalPosition, + isDoubleTap); + } else { + handleLetterboxVerticalPosition(availableHeight, letterboxVerticalPosition, + isDoubleTap); + } + } + + void hideAllImmediately() { + mMoveLeftButton.hide(); + mMoveRightButton.hide(); + mMoveUpButton.hide(); + mMoveDownButton.hide(); + mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET; + mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET; + mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET; + mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET; + } + + void setIsLayoutActive(boolean isLayoutActive) { + this.mIsLayoutActive = isLayoutActive; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mMoveLeftButton = findViewById(R.id.reachability_move_left_button); + mMoveRightButton = findViewById(R.id.reachability_move_right_button); + mMoveUpButton = findViewById(R.id.reachability_move_up_button); + mMoveDownButton = findViewById(R.id.reachability_move_down_button); + mMoveLeftButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + mMoveRightButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + mMoveUpButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + mMoveDownButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + } + + private Animator marginAnimator(View view, Function<LayoutParams, Integer> marginSupplier, + BiConsumer<LayoutParams, Integer> marginConsumer, int from, int to) { + final LayoutParams layoutParams = ((LayoutParams) view.getLayoutParams()); + ValueAnimator animator = ValueAnimator.ofInt(marginSupplier.apply(layoutParams), from, to); + animator.addUpdateListener(valueAnimator -> { + marginConsumer.accept(layoutParams, (Integer) valueAnimator.getAnimatedValue()); + view.requestLayout(); + }); + animator.setDuration(MARGINS_ANIMATION_DURATION_MS); + return animator; + } + + private void handleLetterboxHorizontalPosition(int availableWidth, + int letterboxHorizontalPosition, boolean isDoubleTap) { + mMoveUpButton.hide(); + mMoveDownButton.hide(); + mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET; + mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET; + // We calculate the available space on the left and right + final int horizontalGap = availableWidth / 2; + final int leftAvailableSpace = letterboxHorizontalPosition * horizontalGap; + final int rightAvailableSpace = availableWidth - leftAvailableSpace; + // We show the button if we have enough space + if (leftAvailableSpace >= mMoveLeftButton.getMeasuredWidth()) { + int newLeftMargin = (horizontalGap - mMoveLeftButton.getMeasuredWidth()) / 2; + if (mLastLeftMargin == TaskInfo.PROPERTY_VALUE_UNSET) { + mLastLeftMargin = newLeftMargin; + } + if (mLastLeftMargin != newLeftMargin) { + marginAnimator(mMoveLeftButton, layoutParams -> layoutParams.leftMargin, + (layoutParams, margin) -> layoutParams.leftMargin = margin, + mLastLeftMargin, newLeftMargin).start(); + } else { + final LayoutParams leftParams = ((LayoutParams) mMoveLeftButton.getLayoutParams()); + leftParams.leftMargin = mLastLeftMargin; + mMoveLeftButton.setLayoutParams(leftParams); + } + showItem(mMoveLeftButton, isDoubleTap); + } else { + mMoveLeftButton.hide(); + mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET; + } + if (rightAvailableSpace >= mMoveRightButton.getMeasuredWidth()) { + int newRightMargin = (horizontalGap - mMoveRightButton.getMeasuredWidth()) / 2; + if (mLastRightMargin == TaskInfo.PROPERTY_VALUE_UNSET) { + mLastRightMargin = newRightMargin; + } + if (mLastRightMargin != newRightMargin) { + marginAnimator(mMoveRightButton, layoutParams -> layoutParams.rightMargin, + (layoutParams, margin) -> layoutParams.rightMargin = margin, + mLastRightMargin, newRightMargin).start(); + } else { + final LayoutParams rightParams = + ((LayoutParams) mMoveRightButton.getLayoutParams()); + rightParams.rightMargin = mLastRightMargin; + mMoveRightButton.setLayoutParams(rightParams); + } + showItem(mMoveRightButton, isDoubleTap); + } else { + mMoveRightButton.hide(); + mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET; + } + } + + private void handleLetterboxVerticalPosition(int availableHeight, + int letterboxVerticalPosition, boolean isDoubleTap) { + mMoveLeftButton.hide(); + mMoveRightButton.hide(); + mLastLeftMargin = TaskInfo.PROPERTY_VALUE_UNSET; + mLastRightMargin = TaskInfo.PROPERTY_VALUE_UNSET; + // We calculate the available space on the left and right + final int verticalGap = availableHeight / 2; + final int topAvailableSpace = letterboxVerticalPosition * verticalGap; + final int bottomAvailableSpace = availableHeight - topAvailableSpace; + if (topAvailableSpace >= mMoveUpButton.getMeasuredHeight()) { + int newTopMargin = (verticalGap - mMoveUpButton.getMeasuredHeight()) / 2; + if (mLastTopMargin == TaskInfo.PROPERTY_VALUE_UNSET) { + mLastTopMargin = newTopMargin; + } + if (mLastTopMargin != newTopMargin) { + marginAnimator(mMoveUpButton, layoutParams -> layoutParams.topMargin, + (layoutParams, margin) -> layoutParams.topMargin = margin, + mLastTopMargin, newTopMargin).start(); + } else { + final LayoutParams topParams = ((LayoutParams) mMoveUpButton.getLayoutParams()); + topParams.topMargin = mLastTopMargin; + mMoveUpButton.setLayoutParams(topParams); + } + showItem(mMoveUpButton, isDoubleTap); + } else { + mMoveUpButton.hide(); + mLastTopMargin = TaskInfo.PROPERTY_VALUE_UNSET; + } + if (bottomAvailableSpace >= mMoveDownButton.getMeasuredHeight()) { + int newBottomMargin = (verticalGap - mMoveDownButton.getMeasuredHeight()) / 2; + if (mLastBottomMargin == TaskInfo.PROPERTY_VALUE_UNSET) { + mLastBottomMargin = newBottomMargin; + } + if (mLastBottomMargin != newBottomMargin) { + marginAnimator(mMoveDownButton, layoutParams -> layoutParams.bottomMargin, + (layoutParams, margin) -> layoutParams.bottomMargin = margin, + mLastBottomMargin, newBottomMargin).start(); + } else { + final LayoutParams bottomParams = + ((LayoutParams) mMoveDownButton.getLayoutParams()); + bottomParams.bottomMargin = mLastBottomMargin; + mMoveDownButton.setLayoutParams(bottomParams); + } + showItem(mMoveDownButton, isDoubleTap); + } else { + mMoveDownButton.hide(); + mLastBottomMargin = TaskInfo.PROPERTY_VALUE_UNSET; + } + } + + private void showItem(ReachabilityEduHandLayout view, boolean fromDoubleTap) { + if (view.getVisibility() == View.VISIBLE) { + // Already visible we just start animation + view.startAnimation(); + return; + } + view.setVisibility(View.VISIBLE); + final long delay = fromDoubleTap ? VISIBILITY_SHOW_DOUBLE_TAP_ANIMATION_DELAY_MS + : VISIBILITY_SHOW_ANIMATION_DELAY_MS; + AlphaAnimation alphaAnimation = new AlphaAnimation(ALPHA_FULL_TRANSPARENT, + ALPHA_FULL_OPAQUE); + alphaAnimation.setDuration(VISIBILITY_SHOW_ANIMATION_DURATION_MS); + alphaAnimation.setStartOffset(delay); + alphaAnimation.setFillAfter(true); + alphaAnimation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + // We trigger the hand animation + view.setAlpha(ALPHA_FULL_OPAQUE); + view.startAnimation(); + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + view.startAnimation(alphaAnimation); + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java new file mode 100644 index 000000000000..6223efa831b1 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/ReachabilityEduWindowManager.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2023 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.compatui; + +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.TaskInfo; +import android.content.Context; +import android.graphics.Rect; +import android.os.SystemClock; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.wm.shell.R; +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.compatui.CompatUIController.CompatUICallback; + +/** + * Window manager for the reachability education + */ +class ReachabilityEduWindowManager extends CompatUIWindowManagerAbstract { + + /** + * The Compat UI should be below the Letterbox Education. + */ + private static final int Z_ORDER = LetterboxEduWindowManager.Z_ORDER - 1; + + // The time to wait before hiding the education + private static final long DISAPPEAR_DELAY_MS = 4000L; + + private final CompatUICallback mCallback; + + private final CompatUIConfiguration mCompatUIConfiguration; + + private final ShellExecutor mMainExecutor; + + @NonNull + private TaskInfo mTaskInfo; + + private boolean mIsActivityLetterboxed; + + private int mLetterboxVerticalPosition; + + private int mLetterboxHorizontalPosition; + + private int mTopActivityLetterboxWidth; + + private int mTopActivityLetterboxHeight; + + private long mNextHideTime = -1L; + + private boolean mForceUpdate = false; + + // We decided to force the visualization of the double-tap animated icons every time the user + // double-taps. We detect a double-tap checking the previous and current state of + // mLetterboxVerticalPosition and mLetterboxHorizontalPosition saving the result in this + // variable. + private boolean mHasUserDoubleTapped; + + // When the size of the letterboxed app changes and the icons are visible + // we need to animate them. + private boolean mHasLetterboxSizeChanged; + + @Nullable + @VisibleForTesting + ReachabilityEduLayout mLayout; + + ReachabilityEduWindowManager(Context context, TaskInfo taskInfo, + SyncTransactionQueue syncQueue, CompatUICallback callback, + ShellTaskOrganizer.TaskListener taskListener, DisplayLayout displayLayout, + CompatUIConfiguration compatUIConfiguration, ShellExecutor mainExecutor) { + super(context, taskInfo, syncQueue, taskListener, displayLayout); + mCallback = callback; + mTaskInfo = taskInfo; + mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled; + mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition; + mLetterboxHorizontalPosition = taskInfo.topActivityLetterboxHorizontalPosition; + mTopActivityLetterboxWidth = taskInfo.topActivityLetterboxWidth; + mTopActivityLetterboxHeight = taskInfo.topActivityLetterboxHeight; + mCompatUIConfiguration = compatUIConfiguration; + mMainExecutor = mainExecutor; + } + + @Override + protected int getZOrder() { + return Z_ORDER; + } + + @Override + protected @Nullable View getLayout() { + return mLayout; + } + + @Override + protected void removeLayout() { + mLayout = null; + } + + @Override + protected boolean eligibleToShowLayout() { + return mCompatUIConfiguration.isReachabilityEducationEnabled() + && mIsActivityLetterboxed + && (mLetterboxVerticalPosition != -1 || mLetterboxHorizontalPosition != -1); + } + + @Override + protected View createLayout() { + mLayout = inflateLayout(); + mLayout.inject(this); + + updateVisibilityOfViews(); + + return mLayout; + } + + @VisibleForTesting + ReachabilityEduLayout inflateLayout() { + return (ReachabilityEduLayout) LayoutInflater.from(mContext).inflate( + R.layout.reachability_ui_layout, null); + } + + @Override + public boolean updateCompatInfo(TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener, + boolean canShow) { + mTaskInfo = taskInfo; + final boolean prevIsActivityLetterboxed = mIsActivityLetterboxed; + final int prevLetterboxVerticalPosition = mLetterboxVerticalPosition; + final int prevLetterboxHorizontalPosition = mLetterboxHorizontalPosition; + final int prevTopActivityLetterboxWidth = mTopActivityLetterboxWidth; + final int prevTopActivityLetterboxHeight = mTopActivityLetterboxHeight; + mIsActivityLetterboxed = taskInfo.isLetterboxDoubleTapEnabled; + mLetterboxVerticalPosition = taskInfo.topActivityLetterboxVerticalPosition; + mLetterboxHorizontalPosition = taskInfo.topActivityLetterboxHorizontalPosition; + mTopActivityLetterboxWidth = taskInfo.topActivityLetterboxWidth; + mTopActivityLetterboxHeight = taskInfo.topActivityLetterboxHeight; + + mHasUserDoubleTapped = + mLetterboxVerticalPosition != prevLetterboxVerticalPosition + || prevLetterboxHorizontalPosition != mLetterboxHorizontalPosition; + if (mHasUserDoubleTapped) { + // In this case we disable the reachability for the following launch of + // the current application. Anyway because a double tap event happened, + // the reachability education is displayed + mCompatUIConfiguration.setDontShowReachabilityEducationAgain(taskInfo); + } + if (!super.updateCompatInfo(taskInfo, taskListener, canShow)) { + return false; + } + + mHasLetterboxSizeChanged = prevTopActivityLetterboxWidth != mTopActivityLetterboxWidth + || prevTopActivityLetterboxHeight != mTopActivityLetterboxHeight; + + if (mForceUpdate || prevIsActivityLetterboxed != mIsActivityLetterboxed + || prevLetterboxVerticalPosition != mLetterboxVerticalPosition + || prevLetterboxHorizontalPosition != mLetterboxHorizontalPosition + || prevTopActivityLetterboxWidth != mTopActivityLetterboxWidth + || prevTopActivityLetterboxHeight != mTopActivityLetterboxHeight) { + updateVisibilityOfViews(); + mForceUpdate = false; + } + + return true; + } + + void forceUpdate(boolean forceUpdate) { + mForceUpdate = forceUpdate; + } + + @Override + protected void onParentBoundsChanged() { + if (mLayout == null) { + return; + } + // Both the layout dimensions and dialog margins depend on the parent bounds. + WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams(); + mLayout.setLayoutParams(windowLayoutParams); + relayout(windowLayoutParams); + } + + /** Gets the layout params. */ + protected WindowManager.LayoutParams getWindowLayoutParams() { + View layout = getLayout(); + if (layout == null) { + return new WindowManager.LayoutParams(); + } + // Measure how big the hint is since its size depends on the text size. + final Rect taskBounds = getTaskBounds(); + layout.measure(View.MeasureSpec.makeMeasureSpec(taskBounds.width(), + View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(taskBounds.height(), + View.MeasureSpec.EXACTLY)); + return getWindowLayoutParams(layout.getMeasuredWidth(), layout.getMeasuredHeight()); + } + + /** + * @return Flags to use for the WindowManager layout + */ + @Override + protected int getWindowManagerLayoutParamsFlags() { + return FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCHABLE; + } + + @Override + @VisibleForTesting + public void updateSurfacePosition() { + if (mLayout == null) { + return; + } + updateSurfacePosition(0, 0); + } + + void updateHideTime() { + mNextHideTime = SystemClock.uptimeMillis() + DISAPPEAR_DELAY_MS; + } + + private void updateVisibilityOfViews() { + if (mLayout == null) { + return; + } + if (shouldUpdateEducation()) { + if (!mHasLetterboxSizeChanged) { + mLayout.setIsLayoutActive(true); + } + int availableWidth = getTaskBounds().width() - mTopActivityLetterboxWidth; + int availableHeight = getTaskBounds().height() - mTopActivityLetterboxHeight; + mLayout.handleVisibility(mIsActivityLetterboxed, mLetterboxVerticalPosition, + mLetterboxHorizontalPosition, availableWidth, availableHeight, + mHasUserDoubleTapped); + if (!mHasLetterboxSizeChanged) { + updateHideTime(); + mMainExecutor.executeDelayed(this::hideReachability, DISAPPEAR_DELAY_MS); + } + mHasUserDoubleTapped = false; + } else { + hideReachability(); + } + } + + private void hideReachability() { + if (mLayout != null) { + mLayout.setIsLayoutActive(false); + } + if (mLayout == null || !shouldHideEducation()) { + return; + } + mLayout.hideAllImmediately(); + // We need this in case the icons disappear after the timeout without an explicit + // double tap of the user. + mCompatUIConfiguration.setDontShowReachabilityEducationAgain(mTaskInfo); + } + + private boolean shouldUpdateEducation() { + return mForceUpdate || mHasUserDoubleTapped || mHasLetterboxSizeChanged + || mCompatUIConfiguration.shouldShowReachabilityEducation(mTaskInfo); + } + + private boolean shouldHideEducation() { + return SystemClock.uptimeMillis() >= mNextHideTime; + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java index 2440838844c4..aab123a843ea 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/RestartDialogWindowManager.java @@ -130,7 +130,7 @@ class RestartDialogWindowManager extends CompatUIWindowManagerAbstract { protected boolean eligibleToShowLayout() { // We don't show this dialog if the user has explicitly selected so clicking on a checkbox. return mRequestRestartDialog && !isTaskbarEduShowing() && (mLayout != null - || !mCompatUIConfiguration.getDontShowRestartDialogAgain(mTaskInfo)); + || mCompatUIConfiguration.shouldShowRestartDialogAgain(mTaskInfo)); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index b59f95ce54c9..9807320afb03 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -161,6 +161,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb this::onKeepClearAreasChangedCallback; private void onKeepClearAreasChangedCallback() { + if (mIsKeyguardShowingOrAnimating) { + // early bail out if the change was caused by keyguard showing up + return; + } if (!mEnablePipKeepClearAlgorithm) { // early bail out if the keep clear areas feature is disabled return; @@ -186,6 +190,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb // early bail out if the keep clear areas feature is disabled return; } + if (mIsKeyguardShowingOrAnimating) { + // early bail out if the change was caused by keyguard showing up + return; + } // only move if we're in PiP or transitioning into PiP if (!mPipTransitionState.shouldBlockResizeRequest()) { Rect destBounds = mPipKeepClearAlgorithm.adjust(mPipBoundsState, @@ -635,9 +643,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb DisplayLayout pendingLayout = mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()); if (mIsInFixedRotation + || mIsKeyguardShowingOrAnimating || pendingLayout.rotation() != mPipBoundsState.getDisplayLayout().rotation()) { - // bail out if there is a pending rotation or fixed rotation change + // bail out if there is a pending rotation or fixed rotation change or + // there's a keyguard present return; } int oldMaxMovementBound = mPipBoundsState.getMovementBounds().bottom; @@ -931,10 +941,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState.getDisplayBounds().right, mPipBoundsState.getDisplayBounds().bottom); mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG, rect); - updatePipPositionForKeepClearAreas(); } else { mPipBoundsState.removeNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG); } + updatePipPositionForKeepClearAreas(); } private void setLauncherAppIconSize(int iconSizePx) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java index d03d075b38af..ff5138d4bb91 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java @@ -212,24 +212,25 @@ public class PipSizeSpecHandler { */ @Override public Size getSizeForAspectRatio(Size size, float aspectRatio) { - // getting the percentage of the max size that current size takes float currAspectRatio = (float) size.getWidth() / size.getHeight(); + + // getting the percentage of the max size that current size takes Size currentMaxSize = getMaxSize(currAspectRatio); float currentPercent = (float) size.getWidth() / currentMaxSize.getWidth(); // getting the max size for the target aspect ratio Size updatedMaxSize = getMaxSize(aspectRatio); - int width = (int) (updatedMaxSize.getWidth() * currentPercent); - int height = (int) (updatedMaxSize.getHeight() * currentPercent); + int width = Math.round(updatedMaxSize.getWidth() * currentPercent); + int height = Math.round(updatedMaxSize.getHeight() * currentPercent); // adjust the dimensions if below allowed min edge size if (width < getMinEdgeSize() && aspectRatio <= 1) { width = getMinEdgeSize(); - height = (int) (width / aspectRatio); + height = Math.round(width / aspectRatio); } else if (height < getMinEdgeSize() && aspectRatio > 1) { height = getMinEdgeSize(); - width = (int) (height * aspectRatio); + width = Math.round(height * aspectRatio); } // reduce the dimensions of the updated size to the calculated percentage @@ -365,7 +366,7 @@ public class PipSizeSpecHandler { mContext = context; boolean enablePipSizeLargeScreen = SystemProperties - .getBoolean("persist.wm.debug.enable_pip_size_large_screen", false); + .getBoolean("persist.wm.debug.enable_pip_size_large_screen", true); // choose between two implementations of size spec logic if (enablePipSizeLargeScreen) { 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 e2d7a7764808..f159f54aa825 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 @@ -1354,7 +1354,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mMainStage.deactivate(finishedWCT, childrenToTop == mMainStage /* toTop */); mSideStage.removeAllTasks(finishedWCT, childrenToTop == mSideStage /* toTop */); finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */); - setRootForceTranslucent(true, wct); + setRootForceTranslucent(true, finishedWCT); finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1); mSyncQueue.queue(finishedWCT); mSyncQueue.runInSync(at -> { 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 a841b7f96d3c..d6f4d6daaa83 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 @@ -220,12 +220,20 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { mCallbacks.onNoLongerSupportMultiWindow(); return; } - mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); + if (taskInfo.topActivity == null && mChildrenTaskInfo.contains(taskInfo.taskId) + && mChildrenTaskInfo.get(taskInfo.taskId).topActivity != null) { + // If top activity become null, it means the task is about to vanish, we use this + // signal to remove it from children list earlier for smooth dismiss transition. + mChildrenTaskInfo.remove(taskInfo.taskId); + mChildrenLeashes.remove(taskInfo.taskId); + } else { + mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); + } mCallbacks.onChildTaskStatusChanged(taskInfo.taskId, true /* present */, taskInfo.isVisible); - if (!ENABLE_SHELL_TRANSITIONS) { - updateChildTaskSurface( - taskInfo, mChildrenLeashes.get(taskInfo.taskId), false /* firstAppeared */); + if (!ENABLE_SHELL_TRANSITIONS && mChildrenLeashes.contains(taskInfo.taskId)) { + updateChildTaskSurface(taskInfo, mChildrenLeashes.get(taskInfo.taskId), + false /* firstAppeared */); } } else { throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java index 47c9e06e8681..3f79df6a82c8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/LetterboxEduWindowManagerTest.java @@ -31,14 +31,12 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import android.annotation.Nullable; import android.app.ActivityManager; import android.app.TaskInfo; -import android.content.Context; -import android.content.SharedPreferences; import android.graphics.Insets; import android.graphics.Rect; import android.testing.AndroidTestingRunner; +import android.util.Pair; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.SurfaceControlViewHost; @@ -53,6 +51,7 @@ import androidx.test.filters.SmallTest; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.DockStateReader; import com.android.wm.shell.common.SyncTransactionQueue; @@ -67,6 +66,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.function.Consumer; + /** * Tests for {@link LetterboxEduWindowManager}. * @@ -80,8 +81,10 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { private static final int USER_ID_1 = 1; private static final int USER_ID_2 = 2; - private static final String PREF_KEY_1 = String.valueOf(USER_ID_1); - private static final String PREF_KEY_2 = String.valueOf(USER_ID_2); + private static final String TEST_COMPAT_UI_SHARED_PREFERENCES = "test_compat_ui_configuration"; + + private static final String TEST_HAS_SEEN_LETTERBOX_SHARED_PREFERENCES = + "test_has_seen_letterbox"; private static final int TASK_ID = 1; @@ -103,46 +106,34 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Mock private ShellTaskOrganizer.TaskListener mTaskListener; @Mock private SurfaceControlViewHost mViewHost; @Mock private Transitions mTransitions; - @Mock private Runnable mOnDismissCallback; + @Mock private Consumer<Pair<TaskInfo, ShellTaskOrganizer.TaskListener>> mOnDismissCallback; @Mock private DockStateReader mDockStateReader; - private SharedPreferences mSharedPreferences; - @Nullable - private Boolean mInitialPrefValue1 = null; - @Nullable - private Boolean mInitialPrefValue2 = null; + private CompatUIConfiguration mCompatUIConfiguration; + private TestShellExecutor mExecutor; @Before public void setUp() { MockitoAnnotations.initMocks(this); - - mSharedPreferences = mContext.getSharedPreferences( - LetterboxEduWindowManager.HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME, - Context.MODE_PRIVATE); - if (mSharedPreferences.contains(PREF_KEY_1)) { - mInitialPrefValue1 = mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false); - mSharedPreferences.edit().remove(PREF_KEY_1).apply(); - } - if (mSharedPreferences.contains(PREF_KEY_2)) { - mInitialPrefValue2 = mSharedPreferences.getBoolean(PREF_KEY_2, /* default= */ false); - mSharedPreferences.edit().remove(PREF_KEY_2).apply(); - } + mExecutor = new TestShellExecutor(); + mCompatUIConfiguration = new CompatUIConfiguration(mContext, mExecutor) { + + @Override + protected String getCompatUISharedPreferenceName() { + return TEST_COMPAT_UI_SHARED_PREFERENCES; + } + + @Override + protected String getHasSeenLetterboxEducationSharedPreferencedName() { + return TEST_HAS_SEEN_LETTERBOX_SHARED_PREFERENCES; + } + }; } @After public void tearDown() { - SharedPreferences.Editor editor = mSharedPreferences.edit(); - if (mInitialPrefValue1 == null) { - editor.remove(PREF_KEY_1); - } else { - editor.putBoolean(PREF_KEY_1, mInitialPrefValue1); - } - if (mInitialPrefValue2 == null) { - editor.remove(PREF_KEY_2); - } else { - editor.putBoolean(PREF_KEY_2, mInitialPrefValue2); - } - editor.apply(); + mContext.deleteSharedPreferences(TEST_COMPAT_UI_SHARED_PREFERENCES); + mContext.deleteSharedPreferences(TEST_HAS_SEEN_LETTERBOX_SHARED_PREFERENCES); } @Test @@ -166,8 +157,8 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { @Test public void testCreateLayout_taskBarEducationIsShowing_doesNotCreateLayout() { - LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ - true, USER_ID_1, /* isTaskbarEduShowing= */ true); + LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true, + USER_ID_1, /* isTaskbarEduShowing= */ true); assertFalse(windowManager.createLayout(/* canShow= */ true)); @@ -180,7 +171,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { assertTrue(windowManager.createLayout(/* canShow= */ false)); - assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false)); + assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1)); assertNull(windowManager.mLayout); } @@ -201,7 +192,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { spyOn(dialogTitle); // The education shouldn't be marked as seen until enter animation is done. - assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false)); + assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1)); // Clicking the layout does nothing until enter animation is done. layout.performClick(); verify(mAnimationController, never()).startExitAnimation(any(), any()); @@ -210,7 +201,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { verifyAndFinishEnterAnimation(layout); - assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false)); + assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1)); verify(dialogTitle).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); // Exit animation should start following a click on the layout. layout.performClick(); @@ -218,13 +209,16 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { // Window manager isn't released until exit animation is done. verify(windowManager, never()).release(); + // After dismissed the user has seen the dialog + assertTrue(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1)); + // Verify multiple clicks are ignored. layout.performClick(); verifyAndFinishExitAnimation(layout); verify(windowManager).release(); - verify(mOnDismissCallback).run(); + verify(mOnDismissCallback).accept(any()); } @Test @@ -236,7 +230,10 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { assertNotNull(windowManager.mLayout); verifyAndFinishEnterAnimation(windowManager.mLayout); - assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false)); + + // We dismiss + windowManager.mLayout.findViewById(R.id.letterbox_education_dialog_dismiss_button) + .performClick(); windowManager.release(); windowManager = createWindowManager(/* eligible= */ true, @@ -254,7 +251,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { assertNotNull(windowManager.mLayout); verifyAndFinishEnterAnimation(windowManager.mLayout); - assertTrue(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false)); + assertTrue(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1)); } @Test @@ -271,7 +268,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { mRunOnIdleCaptor.getValue().run(); verify(mAnimationController, never()).startEnterAnimation(any(), any()); - assertFalse(mSharedPreferences.getBoolean(PREF_KEY_1, /* default= */ false)); + assertFalse(mCompatUIConfiguration.getHasSeenLetterboxEducation(USER_ID_1)); } @Test @@ -297,7 +294,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { mTaskListener, /* canShow= */ true)); verify(windowManager).release(); - verify(mOnDismissCallback, never()).run(); + verify(mOnDismissCallback, never()).accept(any()); verify(mAnimationController, never()).startExitAnimation(any(), any()); assertNull(windowManager.mLayout); } @@ -395,8 +392,7 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { } private LetterboxEduWindowManager createWindowManager(boolean eligible, boolean isDocked) { - return createWindowManager(eligible, USER_ID_1, /* isTaskbarEduShowing= */ - false, isDocked); + return createWindowManager(eligible, USER_ID_1, /* isTaskbarEduShowing= */ false, isDocked); } private LetterboxEduWindowManager createWindowManager(boolean eligible, int userId, @@ -410,9 +406,8 @@ public class LetterboxEduWindowManagerTest extends ShellTestCase { LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext, createTaskInfo(eligible, userId), mSyncTransactionQueue, mTaskListener, - createDisplayLayout(), mTransitions, mOnDismissCallback, - mAnimationController, mDockStateReader); - + createDisplayLayout(), mTransitions, mOnDismissCallback, mAnimationController, + mDockStateReader, mCompatUIConfiguration); spyOn(windowManager); doReturn(mViewHost).when(windowManager).createSurfaceViewHost(); doReturn(isTaskbarEduShowing).when(windowManager).isTaskbarEduShowing(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduLayoutTest.java new file mode 100644 index 000000000000..0be08ba74d86 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduLayoutTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 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.compatui; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; + +import android.testing.AndroidTestingRunner; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.R; +import com.android.wm.shell.ShellTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link LetterboxEduDialogLayout}. + * + * Build/Install/Run: + * atest WMShellUnitTests:ReachabilityEduLayoutTest + */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class ReachabilityEduLayoutTest extends ShellTestCase { + + private ReachabilityEduLayout mLayout; + private View mMoveUpButton; + private View mMoveDownButton; + private View mMoveLeftButton; + private View mMoveRightButton; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mLayout = (ReachabilityEduLayout) LayoutInflater.from(mContext) + .inflate(R.layout.reachability_ui_layout, null); + mMoveLeftButton = mLayout.findViewById(R.id.reachability_move_left_button); + mMoveRightButton = mLayout.findViewById(R.id.reachability_move_right_button); + mMoveUpButton = mLayout.findViewById(R.id.reachability_move_up_button); + mMoveDownButton = mLayout.findViewById(R.id.reachability_move_down_button); + } + + @Test + public void testOnFinishInflate() { + assertNotNull(mMoveUpButton); + assertNotNull(mMoveDownButton); + assertNotNull(mMoveLeftButton); + assertNotNull(mMoveRightButton); + } + + @Test + public void handleVisibility_activityNotLetterboxed_buttonsAreHidden() { + mLayout.handleVisibility(/* isActivityLetterboxed */ false, + /* letterboxVerticalPosition */ -1, /* letterboxHorizontalPosition */ -1, + /* availableWidth */ 0, /* availableHeight */ 0, /* fromDoubleTap */ false); + assertEquals(View.INVISIBLE, mMoveUpButton.getVisibility()); + assertEquals(View.INVISIBLE, mMoveDownButton.getVisibility()); + assertEquals(View.INVISIBLE, mMoveLeftButton.getVisibility()); + assertEquals(View.INVISIBLE, mMoveRightButton.getVisibility()); + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java new file mode 100644 index 000000000000..91e1e199719c --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/ReachabilityEduWindowManagerTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2023 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.compatui; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.verify; + +import android.app.ActivityManager; +import android.app.TaskInfo; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTaskOrganizer; +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.TestShellExecutor; +import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.SyncTransactionQueue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests for {@link ReachabilityEduWindowManager}. + * + * Build/Install/Run: + * atest WMShellUnitTests:ReachabilityEduWindowManagerTest + */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class ReachabilityEduWindowManagerTest extends ShellTestCase { + + private static final int USER_ID = 1; + private static final int TASK_ID = 1; + + @Mock + private SyncTransactionQueue mSyncTransactionQueue; + @Mock + private ShellTaskOrganizer.TaskListener mTaskListener; + @Mock + private CompatUIController.CompatUICallback mCallback; + @Mock + private CompatUIConfiguration mCompatUIConfiguration; + @Mock + private DisplayLayout mDisplayLayout; + + private TestShellExecutor mExecutor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mExecutor = new TestShellExecutor(); + } + + @After + public void tearDown() { + } + + @Test + public void testCreateLayout_notEligible_doesNotCreateLayout() { + final ReachabilityEduWindowManager windowManager = createReachabilityEduWindowManager( + createTaskInfo(/* userId= */ USER_ID, /*isLetterboxDoubleTapEnabled */ false)); + + assertFalse(windowManager.createLayout(/* canShow= */ true)); + + assertNull(windowManager.mLayout); + } + + @Test + public void testCreateLayout_letterboxPositionChanged_doubleTapIsDetected() { + // Initial left position + final TaskInfo initialTaskInfo = createTaskInfoForHorizontalTapping(USER_ID, 0, 1000); + final ReachabilityEduWindowManager windowManager = + createReachabilityEduWindowManager(initialTaskInfo); + // Move to the right + final TaskInfo newPositionTaskInfo = createTaskInfoForHorizontalTapping(USER_ID, 1, 1000); + windowManager.updateCompatInfo(newPositionTaskInfo, mTaskListener, /* canShow */ true); + + verify(mCompatUIConfiguration).setDontShowReachabilityEducationAgain(newPositionTaskInfo); + } + + + private ReachabilityEduWindowManager createReachabilityEduWindowManager(TaskInfo taskInfo) { + return new ReachabilityEduWindowManager(mContext, taskInfo, + mSyncTransactionQueue, mCallback, mTaskListener, mDisplayLayout, + mCompatUIConfiguration, mExecutor); + } + + private static TaskInfo createTaskInfo(int userId, boolean isLetterboxDoubleTapEnabled) { + return createTaskInfo(userId, /* isLetterboxDoubleTapEnabled */ isLetterboxDoubleTapEnabled, + /* topActivityLetterboxVerticalPosition */ -1, + /* topActivityLetterboxHorizontalPosition */ -1, + /* topActivityLetterboxWidth */ -1, + /* topActivityLetterboxHeight */ -1); + } + + private static TaskInfo createTaskInfoForHorizontalTapping(int userId, + int topActivityLetterboxHorizontalPosition, int topActivityLetterboxWidth) { + return createTaskInfo(userId, /* isLetterboxDoubleTapEnabled */ true, + /* topActivityLetterboxVerticalPosition */ -1, + topActivityLetterboxHorizontalPosition, topActivityLetterboxWidth, + /* topActivityLetterboxHeight */ -1); + } + + private static TaskInfo createTaskInfo(int userId, boolean isLetterboxDoubleTapEnabled, + int topActivityLetterboxVerticalPosition, int topActivityLetterboxHorizontalPosition, + int topActivityLetterboxWidth, int topActivityLetterboxHeight) { + ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); + taskInfo.userId = userId; + taskInfo.taskId = TASK_ID; + taskInfo.isLetterboxDoubleTapEnabled = isLetterboxDoubleTapEnabled; + taskInfo.topActivityLetterboxVerticalPosition = topActivityLetterboxVerticalPosition; + taskInfo.topActivityLetterboxHorizontalPosition = topActivityLetterboxHorizontalPosition; + taskInfo.topActivityLetterboxWidth = topActivityLetterboxWidth; + taskInfo.topActivityLetterboxHeight = topActivityLetterboxHeight; + return taskInfo; + } +} diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index a285462eef74..d101a1bdfb37 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -39,6 +39,9 @@ #include "VectorDrawable.h" #include "pipeline/skia/AnimatedDrawables.h" #include "pipeline/skia/FunctorDrawable.h" +#ifdef __ANDROID__ +#include "renderthread/CanvasContext.h" +#endif namespace android { namespace uirenderer { @@ -434,7 +437,19 @@ struct DrawPoints final : Op { size_t count; SkPaint paint; void draw(SkCanvas* c, const SkMatrix&) const { - c->drawPoints(mode, count, pod<SkPoint>(this), paint); + if (paint.isAntiAlias()) { + c->drawPoints(mode, count, pod<SkPoint>(this), paint); + } else { + c->save(); +#ifdef __ANDROID__ + auto pixelSnap = renderthread::CanvasContext::getActiveContext()->getPixelSnapMatrix(); + auto transform = c->getLocalToDevice(); + transform.postConcat(pixelSnap); + c->setMatrix(transform); +#endif + c->drawPoints(mode, count, pod<SkPoint>(this), paint); + c->restore(); + } } }; struct DrawVertices final : Op { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index a80c613697f2..fe414201094b 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -53,6 +53,14 @@ public: bool isSurfaceReady() override; bool isContextReady() override; + const SkM44& getPixelSnapMatrix() const override { + // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the + // desired fragment + static const SkScalar kOffset = 0.063f; + static const SkM44 sSnapMatrix = SkM44::Translate(kOffset, kOffset); + return sSnapMatrix; + } + static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); protected: diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index cc2565d88d5e..18e0b91f0253 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -180,6 +180,10 @@ void SkiaVulkanPipeline::onContextDestroyed() { } } +const SkM44& SkiaVulkanPipeline::getPixelSnapMatrix() const { + return mVkSurface->getPixelSnapMatrix(); +} + } /* namespace skiapipeline */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index a6e685d08aeb..7c8f65b87605 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -49,6 +49,7 @@ public: void onStop() override; bool isSurfaceReady() override; bool isContextReady() override; + const SkM44& getPixelSnapMatrix() const override; static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor); static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 602554ab82f3..f56d19bfcea0 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -793,6 +793,10 @@ SkISize CanvasContext::getNextFrameSize() const { return size; } +const SkM44& CanvasContext::getPixelSnapMatrix() const { + return mRenderPipeline->getPixelSnapMatrix(); +} + void CanvasContext::prepareAndDraw(RenderNode* node) { ATRACE_CALL(); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 951ee216ce35..d85e579e371c 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -195,6 +195,9 @@ public: SkISize getNextFrameSize() const; + // Returns the matrix to use to nudge non-AA'd points/lines towards the fragment center + const SkM44& getPixelSnapMatrix() const; + // Called when SurfaceStats are available. static void onSurfaceStatsAvailable(void* context, int32_t surfaceControlId, ASurfaceControlStats* stats); diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index ef58bc553c23..54adec2cf6f6 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -88,6 +88,8 @@ public: virtual void setPictureCapturedCallback( const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0; + virtual const SkM44& getPixelSnapMatrix() const = 0; + virtual ~IRenderPipeline() {} }; diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp index 7dd3561cb220..666f32939206 100644 --- a/libs/hwui/renderthread/VulkanSurface.cpp +++ b/libs/hwui/renderthread/VulkanSurface.cpp @@ -63,6 +63,18 @@ static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) { return SkMatrix::I(); } +static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) { + // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the + // desired fragment + static const SkScalar kOffset = 0.063f; + SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform); + SkMatrix invert; + LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert)); + return SkM44::Translate(kOffset, kOffset) + .postConcat(SkM44(preRotation)) + .preConcat(SkM44(invert)); +} + static bool ConnectAndSetWindowDefaults(ANativeWindow* window) { ATRACE_CALL(); @@ -178,6 +190,8 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode outWindowInfo->preTransform = GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform); + outWindowInfo->pixelSnapMatrix = + GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform); err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); if (err != 0 || query_value < 0) { @@ -406,6 +420,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() { } mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform); + mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform); } uint32_t idx; diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h index beb71b727f51..b8ccf7810b5d 100644 --- a/libs/hwui/renderthread/VulkanSurface.h +++ b/libs/hwui/renderthread/VulkanSurface.h @@ -45,6 +45,8 @@ public: } const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; } + const SkM44& getPixelSnapMatrix() const { return mWindowInfo.pixelSnapMatrix; } + private: /* * All structs/methods in this private section are specifically for use by the VulkanManager @@ -101,6 +103,7 @@ private: SkISize actualSize; // transform to be applied to the SkSurface to map the coordinates to the provided transform SkMatrix preTransform; + SkM44 pixelSnapMatrix; }; VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrDirectContext* grContext); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index 2b7bcbee79fd..cc7a7d5bb9dc 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -161,7 +161,8 @@ public class CameraBinderTest extends AndroidTestCase { ICameraService.USE_CALLING_UID, ICameraService.USE_CALLING_PID, getContext().getApplicationInfo().targetSdkVersion, - /*overrideToPortrait*/false); + /*overrideToPortrait*/false, + /*forceSlowJpegMode*/false); assertNotNull(String.format("Camera %s was null", cameraId), cameraUser); Log.v(TAG, String.format("Camera %s connected", cameraId)); diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 145dc5d997a5..8618438f560b 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -255,12 +255,12 @@ <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi-tilkoblingskode"</string> <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Tilkoblingen mislyktes"</string> <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sørg for at enheten er koblet til samme nettverk."</string> - <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via Wifi ved å skanne en QR-kode"</string> + <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via wifi ved å skanne en QR-kode"</string> <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Kobler til enheten …"</string> <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Kunne ikke koble til enheten. Enten var QR-koden feil, eller enheten er ikke koblet til samme nettverk."</string> <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skann QR-koden"</string> - <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via Wifi ved å skanne en QR-kode"</string> + <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via wifi ved å skanne en QR-kode"</string> <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et Wifi-nettverk"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, feilsøking, utvikler"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Snarvei til feilrapport"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index 9eafd1eaa77e..72f156cce233 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -223,7 +223,7 @@ <item msgid="581904787661470707">"Kasi zaidi"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Chagua wasifu"</string> - <string name="category_personal" msgid="6236798763159385225">"Ya Binafsi"</string> + <string name="category_personal" msgid="6236798763159385225">"Binafsi"</string> <string name="category_work" msgid="4014193632325996115">"Ya Kazini"</string> <string name="development_settings_title" msgid="140296922921597393">"Chaguo za wasanidi"</string> <string name="development_settings_enable" msgid="4285094651288242183">"Washa chaguo za wasanidi programu"</string> diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index aadc14061a61..cacf13326178 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -878,7 +878,7 @@ android:showForAllUsers="true" android:finishOnTaskLaunch="true" android:launchMode="singleInstance" - android:configChanges="screenLayout|keyboard|keyboardHidden|orientation" + android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|orientation" android:visibleToInstantApps="true"> </activity> diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml index dd7a5ce06c88..47e62c088791 100644 --- a/packages/SystemUI/res-product/values-en-rCA/strings.xml +++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml @@ -40,9 +40,9 @@ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string> - <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string> - <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string> - <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string> + <string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the tablet."</string> + <string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the device."</string> + <string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the phone."</string> <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Unlock your phone for more options"</string> <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Unlock your tablet for more options"</string> <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Unlock your device for more options"</string> diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back.xml b/packages/SystemUI/res/drawable/ic_sysbar_back.xml index ee402622d52b..6c34655733ed 100644 --- a/packages/SystemUI/res/drawable/ic_sysbar_back.xml +++ b/packages/SystemUI/res/drawable/ic_sysbar_back.xml @@ -15,13 +15,13 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="28dp" - android:height="28dp" + android:width="20dp" + android:height="20dp" android:autoMirrored="true" - android:viewportWidth="28" - android:viewportHeight="28"> + android:viewportWidth="20" + android:viewportHeight="20"> <path android:fillColor="?attr/singleToneColor" - android:pathData="M6.49,14.86c-0.66-0.39-0.66-1.34,0-1.73l6.02-3.53l5.89-3.46C19.11,5.73,20,6.26,20,7.1V14v6.9 c0,0.84-0.89,1.37-1.6,0.95l-5.89-3.46L6.49,14.86z" /> + android:pathData="M15.5417 1.66669C15.1833 1.66669 14.8417 1.76669 14.5333 1.94169L3.21667 8.74169C2.775 9.00002 2.5 9.48335 2.5 10C2.5 10.5167 2.775 11 3.21667 11.2584L14.5333 18.05C14.8417 18.2334 15.1833 18.325 15.5417 18.325C16.625 18.325 17.5 17.45 17.5 16.3667V3.62502C17.5 2.54169 16.625 1.66669 15.5417 1.66669Z" /> </vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_sysbar_home.xml b/packages/SystemUI/res/drawable/ic_sysbar_home.xml index da239372791f..8b2a58a50224 100644 --- a/packages/SystemUI/res/drawable/ic_sysbar_home.xml +++ b/packages/SystemUI/res/drawable/ic_sysbar_home.xml @@ -15,12 +15,12 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="28dp" - android:height="28dp" - android:viewportWidth="28" - android:viewportHeight="28"> + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> <path android:fillColor="?attr/singleToneColor" - android:pathData="M 14 7 C 17.8659932488 7 21 10.1340067512 21 14 C 21 17.8659932488 17.8659932488 21 14 21 C 10.1340067512 21 7 17.8659932488 7 14 C 7 10.1340067512 10.1340067512 7 14 7 Z" /> + android:pathData="M10.0001 18.3334C5.40008 18.3334 1.66675 14.6 1.66675 10C1.66675 5.40002 5.40008 1.66669 10.0001 1.66669C14.6001 1.66669 18.3334 5.40002 18.3334 10C18.3334 14.6 14.6001 18.3334 10.0001 18.3334Z" /> </vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_sysbar_recent.xml b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml index 6b038d179568..6ff3ec3f47f2 100644 --- a/packages/SystemUI/res/drawable/ic_sysbar_recent.xml +++ b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml @@ -15,12 +15,12 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="28dp" - android:height="28dp" - android:viewportWidth="28" - android:viewportHeight="28"> + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> <path android:fillColor="?attr/singleToneColor" - android:pathData="M19.9,21.5H8.1c-0.88,0-1.6-0.72-1.6-1.6V8.1c0-0.88,0.72-1.6,1.6-1.6h11.8c0.88,0,1.6,0.72,1.6,1.6v11.8 C21.5,20.78,20.78,21.5,19.9,21.5z" /> + android:pathData="M4.47634 2.5H15.5241C16.6164 2.5 17.5002 3.38382 17.5002 4.4761V15.5239C17.5002 16.6162 16.6164 17.5 15.5241 17.5H4.47634C3.38407 17.5 2.50024 16.6162 2.50024 15.5239V4.4761C2.50024 3.38382 3.38407 2.5 4.47634 2.5Z" /> </vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml index 8e83b4abe0dc..ae0a9374fd2c 100644 --- a/packages/SystemUI/res/layout/dream_overlay_container.xml +++ b/packages/SystemUI/res/layout/dream_overlay_container.xml @@ -25,11 +25,12 @@ android:id="@+id/dream_overlay_content" android:layout_width="match_parent" android:layout_height="0dp" - android:layout_marginTop="@dimen/dream_overlay_container_margin_top" - android:layout_marginEnd="@dimen/dream_overlay_container_margin_end" - android:layout_marginBottom="@dimen/dream_overlay_container_margin_bottom" - android:layout_marginStart="@dimen/dream_overlay_container_margin_start" - + android:paddingTop="@dimen/dream_overlay_container_padding_top" + android:paddingEnd="@dimen/dream_overlay_container_padding_end" + android:paddingBottom="@dimen/dream_overlay_container_padding_bottom" + android:paddingStart="@dimen/dream_overlay_container_padding_start" + android:clipToPadding="false" + android:clipChildren="false" app:layout_constraintTop_toBottomOf="@id/dream_overlay_status_bar" app:layout_constraintBottom_toBottomOf="parent" /> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 5dd7baebb298..789a5883c238 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrole bygevoeg.}other{# kontroles bygevoeg.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Verwyder"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Voeg <xliff:g id="APPNAME">%s</xliff:g> by?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan kies watter kontroles en inhoud hier gewys word."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Verwyder kontroles vir <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"As gunsteling gemerk"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"As gunsteling gemerk; posisie <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 76c628991815..0faf10cd7ec2 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ቁጥጥር ታክሏል።}one{# ቁጥጥር ታክሏል።}other{# ቁጥጥሮች ታክለዋል።}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ተወግዷል"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ይታከል?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> የትኛዎቹ መቆጣጠሪያዎች እና ይዘት እዚህ እንደሚታዩ መምረጥ ይችላል።"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"የ<xliff:g id="APPNAME">%s</xliff:g> መቆጣጠሪያዎች ይወገዱ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ተወዳጅ የተደረገ"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ተወዳጅ ተደርጓል፣ አቋም <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 7a22a054c7e2..dbd809636af6 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}one{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}other{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}}"</string> <string name="controls_removed" msgid="3731789252222856959">"আঁতৰোৱা হ’ল"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> যোগ দিবনে?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>এ ইয়াত কোনবোৰ নিয়ন্ত্ৰণ আৰু সমল দেখুওৱা হ’ব সেয়া বাছনি কৰিব পাৰে।"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g>ৰ নিয়ন্ত্ৰণ আঁতৰাবনে?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"প্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"প্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল, স্থান <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index eb724cf57013..684a13e1bec6 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# nizamlayıcı əlavə edilib.}other{# nizamlayıcı əlavə edilib.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Silinib"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> əlavə edilsin?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> burada göstəriləcək nizamlayıcı və kontenti seçə bilər."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> nizamlayıcıları silinsin?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Sevimlilərə əlavə edilib"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Sevimlilərə əlavə edilib, sıra: <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index c08e83828df7..7727d3a174cc 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrola je dodata.}one{# kontrola je dodata.}few{# kontrole su dodate.}other{# kontrola je dodato.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite li da dodate <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> može da odabere koje kontrole i sadržaj se prikazuju ovde."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Želite da uklonite kontrole za <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Označeno je kao omiljeno"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Označeno je kao omiljeno, <xliff:g id="NUMBER">%d</xliff:g>. pozicija"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 84c58c52103d..c9e6e991e0ef 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Добавена е # контрола.}other{Добавени са # контроли.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Премахнато"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Да се добави ли <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> може да избира съдържанието и контролите, които да се показват тук."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Да се премахнат ли контролите за <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Означено като любимо"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Означено като любимо – позиция <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index d5b7d665fa6b..35af7ec385be 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{#টি কন্ট্রোল যোগ করা হয়েছে।}one{#টি কন্ট্রোল যোগ করা হয়েছে।}other{#টি কন্ট্রোল যোগ করা হয়েছে।}}"</string> <string name="controls_removed" msgid="3731789252222856959">"সরানো হয়েছে"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> যোগ করবেন?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"এখানে কোন কন্ট্রোল ও কন্টেন্ট দেখানো হবে <xliff:g id="APPNAME">%s</xliff:g> তা বেছে নিতে পারবে।"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g>-এর জন্য নিয়ন্ত্রণ সরিয়ে দেবেন?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"পছন্দসই হিসেবে চিহ্নিত করেছেন"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"পছন্দসই হিসেবে চিহ্নিত করেছেন, অবস্থান <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index ab184743a3dd..5af4836e9758 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodana je # kontrola.}one{Dodana je # kontrola.}few{Dodane su # kontrole.}other{Dodano je # kontrola.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Dodati aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Aplikacija <xliff:g id="APPNAME">%s</xliff:g> može odabrati koje će kontrole i sadržaj prikazivati ovdje."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Ukloniti kontrole za aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano u omiljeno"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano u omiljeno, pozicija <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 75b51a7b1c75..02b4b38a6f34 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S\'ha afegit # control.}many{S\'han afegit # controls.}other{S\'han afegit # controls.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Suprimit"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vols afegir <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> pot triar quins controls i continguts es mostren aquí."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vols suprimir els controls per a <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Afegit als preferits"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Afegit als preferits, posició <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 933b72c05530..2fc7ddcd7a03 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# Steuerelement hinzugefügt.}other{# Steuerelemente hinzugefügt.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Entfernt"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> hinzufügen?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> darf auswählen, welche Einstellungen und Inhalte hier angezeigt werden."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Einstellungen für <xliff:g id="APPNAME">%s</xliff:g> entfernen?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Zu Favoriten hinzugefügt"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Zu Favoriten hinzugefügt, Position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 28e5e0c8b65b..fe2a23c70dcf 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Προστέθηκε # στοιχείο ελέγχου.}other{Προστέθηκαν # στοιχεία ελέγχου.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Καταργήθηκε"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Προσθήκη <xliff:g id="APPNAME">%s</xliff:g>;"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Η εφαρμογή <xliff:g id="APPNAME">%s</xliff:g> μπορεί να επιλέξει τα στοιχεία ελέγχου και το περιεχόμενο που θα εμφανίζεται εδώ."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Κατάργηση στοιχείων ελέγχου για την εφαρμογή <xliff:g id="APPNAME">%s</xliff:g>;"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Προστέθηκε στα αγαπημένα"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Προστέθηκε στα αγαπημένα, στη θέση <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index c308775227fb..1a1c202aaa3a 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removed"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index aacf3546a8e6..7b2eb277feae 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removed"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favorited"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorited, position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index c308775227fb..1a1c202aaa3a 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removed"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index c308775227fb..1a1c202aaa3a 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removed"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 4e9cb5fddc86..6b1fc66c2e19 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removed"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> can choose which controls and content show here."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remove controls for <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Favorited"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorited, position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index aff6b260864b..b3bc7daaccaf 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}many{Se agregaron # controles.}other{Se agregaron # controles.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Quitados"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"¿Quieres agregar <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> puede elegir qué controles y contenido mostrar aquí."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"¿Quieres quitar los controles para <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Está en favoritos"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está en favoritos en la posición <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 8355585c18e1..0fe2cdcf400a 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control añadido.}many{# controles añadidos.}other{# controles añadidos.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Quitado"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"¿Añadir <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> puede elegir qué controles y contenido se muestran aquí."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"¿Quitar los controles de <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Añadido a favoritos"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Añadido a favoritos (posición <xliff:g id="NUMBER">%d</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 709fcea43cd8..a1ccd82aabb6 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Lisati # juhtnupp.}other{Lisati # juhtnuppu.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Eemaldatud"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Kas lisada <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Rakendus <xliff:g id="APPNAME">%s</xliff:g> saab valida, millised juhtelemendid ja milline sisu siin kuvatakse."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Kas soovite rakenduse <xliff:g id="APPNAME">%s</xliff:g> juhtelemendid eemaldada?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Lisatud lemmikuks"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Lisatud lemmikuks, positsioon <xliff:g id="NUMBER">%d</xliff:g>"</string> @@ -831,9 +830,9 @@ <string name="controls_dialog_message" msgid="342066938390663844">"Soovitas <xliff:g id="APP">%s</xliff:g>"</string> <string name="controls_tile_locked" msgid="731547768182831938">"Seade on lukustatud"</string> <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Kas soovite seadmete juhtelemente lukustuskuval kuvada ja kasutada?"</string> - <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Võite lukustuskuvale oma väliste seadmete juhtelemendid lisada.\n\nTeie seadmerakendus võib võimaldada teil teatud seadmeid ilma telefoni või tahvelarvutit avamata hallata.\n\nSaate igal ajal seadetes muudatusi teha."</string> - <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kas soovite seadmeid lukustuskuva kaudu hallata?"</string> - <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Võite teatud seadmeid ilma telefoni või tahvelarvutit avamata hallata. Teie seadmerakendus määrab, milliseid seadmeid saab sel viisil hallata."</string> + <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Võite lukustuskuvale oma väliste seadmete juhtelemendid lisada.\n\nTeie seadmerakendus võib võimaldada teil teatud seadmeid ilma telefoni või tahvelarvutit avamata juhtida.\n\nSaate igal ajal seadetes muudatusi teha."</string> + <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Kas soovite seadmeid lukustuskuva kaudu juhtida?"</string> + <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"Võite teatud seadmeid ilma telefoni või tahvelarvutit avamata juhtida. Teie seadmerakendus määrab, milliseid seadmeid saab sel viisil juhtida."</string> <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Tänan, ei"</string> <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Jah"</string> <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN-kood sisaldab tähti või sümboleid"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index c9bc9dce1c46..aec32a5e1166 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Kontrolatzeko # aukera gehitu da.}other{Kontrolatzeko # aukera gehitu dira.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Kenduta"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> gehitu nahi duzu?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Hemen zein kontrolatzeko aukera eta eduki agertzen diren aukera dezake <xliff:g id="APPNAME">%s</xliff:g> aplikazioak."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> kontrolatzeko aukerak kendu nahi dituzu?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Gogokoetan dago"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>. gogokoa da"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 989b7e691005..e8ff3bfbefd3 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# کنترل اضافه شد.}one{# کنترل اضافه شد.}other{# کنترل اضافه شد.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"حذف شد"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> افزوده شود؟"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> میتواند انتخاب کند چه کنترلها و محتوایی اینجا نشان داده شود."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"کنترلهای <xliff:g id="APPNAME">%s</xliff:g> برداشته شود؟"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"به موارد دلخواه اضافه شد"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"اضافهشده به موارد دلخواه، جایگاه <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 78182a0b244f..68c5b51cb123 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# commandes ajoutées.}other{# commandes ajoutées.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ajouter <xliff:g id="APPNAME">%s</xliff:g> ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> peut choisir les commandes et contenus à afficher ici."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Supprimer les commandes pour <xliff:g id="APPNAME">%s</xliff:g> ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 33693cef9dbc..4bf9078ebd20 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# નિયંત્રણ ઉમેર્યું.}one{# નિયંત્રણ ઉમેર્યું.}other{# નિયંત્રણ ઉમેર્યા.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"કાઢી નાખ્યું"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ઉમેરીએ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> પસંદ કરી શકે છે કે કયા નિયંત્રણો અને કન્ટેન્ટ અહીં બતાવવામાં આવે."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> માટે નિયંત્રણો કાઢી નાખીએ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"મનપસંદમાં ઉમેર્યું"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"મનપસંદમાં ઉમેર્યું, સ્થાન <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 48428fd8469a..cdd8ecb69c7a 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# कंट्रोल जोड़ा गया.}one{# कंट्रोल जोड़ा गया.}other{# कंट्रोल जोड़े गए.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"हटाया गया"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> को जोड़ना है?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> यह चुन सकता है कि इस पैनल पर कौनसे कंट्रोल और कॉन्टेंट दिखे."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> के लिए कंट्रोल हटाने हैं?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"पसंदीदा बनाया गया"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"पसंदीदा बनाया गया, क्रम संख्या <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index d6b07df79048..c53be7eebded 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodana je # kontrola.}one{Dodana je # kontrola.}few{Dodane su # kontrole.}other{Dodano je # kontrola.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite li dodati aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"U aplikaciji <xliff:g id="APPNAME">%s</xliff:g> možete odabrati koje se kontrole i sadržaj ovdje prikazuju."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Ukloniti kontrole za aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano u favorite"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano u favorite, položaj <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index b7bf31c6f096..d45491f7b6e0 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# vezérlő hozzáadva.}other{# vezérlő hozzáadva.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Eltávolítva"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Hozzáadja a(z) <xliff:g id="APPNAME">%s</xliff:g> alkalmazást?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"A(z) <xliff:g id="APPNAME">%s</xliff:g> eldöntheti, milyen vezérlőket és tartalmakat jelenít meg itt."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Eltávolítja a(z) <xliff:g id="APPNAME">%s</xliff:g> vezérlőit?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Hozzáadva a kedvencekhez"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Hozzáadva a kedvencekhez <xliff:g id="NUMBER">%d</xliff:g>. helyen"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index f0f63acd90e7..6be304c059b6 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrol ditambahkan.}other{# kontrol ditambahkan.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Dihapus"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Tambahkan <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> dapat memilih kontrol dan konten yang ditampilkan di sini."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Hapus kontrol untuk <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Difavoritkan"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Difavoritkan, posisi <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index faf1341ab117..ad803ca1f97f 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# stýringu bætt við.}one{# stýringu bætt við.}other{# stýringum bætt við.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Fjarlægt"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Viltu bæta <xliff:g id="APPNAME">%s</xliff:g> við?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> getur valið hvaða stýringar og efni birtist hér."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Fjarlægja stýringar fyrir <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Eftirlæti"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Eftirlæti, staða <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 8a94f926efff..7a2ace6c5439 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -759,7 +759,7 @@ <string name="slice_permission_deny" msgid="6870256451658176895">"Rifiuta"</string> <string name="auto_saver_title" msgid="6873691178754086596">"Tocca per programmare il Risparmio energetico"</string> <string name="auto_saver_text" msgid="3214960308353838764">"Attiva questa funzionalità se è probabile che la batteria si scarichi"</string> - <string name="no_auto_saver_action" msgid="7467924389609773835">"No grazie"</string> + <string name="no_auto_saver_action" msgid="7467924389609773835">"No, grazie"</string> <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump heap SysUI"</string> <string name="ongoing_privacy_dialog_a11y_title" msgid="2205794093673327974">"In uso"</string> <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 8bcca2137067..b4cb279deef5 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{נוסף אמצעי בקרה אחד (#).}one{נוספו # אמצעי בקרה.}two{נוספו # אמצעי בקרה.}other{נוספו # אמצעי בקרה.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"הוסר"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"להוסיף את <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"האפליקציה <xliff:g id="APPNAME">%s</xliff:g> יכולה לבחור אילו אמצעי בקרה ותוכן להראות כאן."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"להסיר את אמצעי הבקרה של <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"סומן כמועדף"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"סומן כמועדף, במיקום <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 086f9fa0e83c..7188d682fa35 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{დაემატა მართვის # საშუალება.}other{დაემატა მართვის # საშუალება.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ამოიშალა"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"გსურთ <xliff:g id="APPNAME">%s</xliff:g>-ის დამატება?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>-ს შეუძლია აირჩიოს, მართვის რომელი საშუალებები და კონტენტი უნდა გამოჩნდეს აქ."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ამოიშალოს <xliff:g id="APPNAME">%s</xliff:g>-ის მართვის საშუალებები?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"რჩეულებშია"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"რჩეულებშია, პოზიციაზე <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 6652f16a9e11..915c5bcbebe6 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# басқару элементі қосылды.}other{# басқару элементі қосылды.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Өшірілді"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> қолданбасын қосу керек пе?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> қолданбасы осы жерде көрсетілетін басқару құралдары мен контентті таңдай алады."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> қолданбасының басқару элементтері жойылсын ба?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Таңдаулыларға қосылды"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Таңдаулыларға қосылды, <xliff:g id="NUMBER">%d</xliff:g>-позиция"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 077ec89c0bd8..e853bea9887f 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{បានបញ្ចូលការគ្រប់គ្រង #។}other{បានបញ្ចូលការគ្រប់គ្រង #។}}"</string> <string name="controls_removed" msgid="3731789252222856959">"បានដកចេញ"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"បញ្ចូល <xliff:g id="APPNAME">%s</xliff:g> ឬ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> អាចជ្រើសរើសឱ្យការគ្រប់គ្រង និងខ្លឹមសារណាខ្លះបង្ហាញនៅទីនេះ។"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ដកការគ្រប់គ្រងសម្រាប់ <xliff:g id="APPNAME">%s</xliff:g> ចេញឬ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"បានដាក់ជាសំណព្វ"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"បានដាក់ជាសំណព្វ ទីតាំងទី <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index a080ca72ed6d..361e35c7567d 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ನಿಯಂತ್ರಣವನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}one{# ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}other{# ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ಅನ್ನು ಸೇರಿಸಬೇಕೆ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ಯಾವ ಕಂಟ್ರೋಲ್ಗಳು ಮತ್ತು ವಿಷಯವನ್ನು ತೋರಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಬಹುದು."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> ಗಾಗಿ ನಿಯಂತ್ರಣಗಳನ್ನು ತೆಗೆದುಹಾಕಬೇಕೆ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ಮೆಚ್ಚಲಾಗಿರುವುದು"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ಮೆಚ್ಚಲಾಗಿರುವುದು, ಸ್ಥಾನ <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index b99d81eba78e..be4ef11b3de6 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{설정이 #개 추가되었습니다.}other{설정이 #개 추가되었습니다.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"삭제됨"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>을(를) 추가할까요?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>에서 여기에 표시되는 컨트롤 및 콘텐츠를 선택할 수 있습니다."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> 컨트롤을 삭제할까요?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"즐겨찾기에 추가됨"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"즐겨찾기에 추가됨, 위치 <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 2d0560273f0f..c67b75189e27 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# көзөмөл кошулду.}other{# көзөмөл кошулду.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Өчүрүлдү"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> кошулсунбу?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> бул жерде көрсөтүлө турган башкаруу элементтерин жана контентти тандай алат."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> башкаруу элементтери өчүрүлсүнбү?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Сүйүктүүлөргө кошулду"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Сүйүктүүлөргө <xliff:g id="NUMBER">%d</xliff:g>-позицияга кошулду"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 6a54f28460f1..01e35cf7ec3d 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ເພີ່ມ # ການຄວບຄຸມແລ້ວ.}other{ເພີ່ມ # ການຄວບຄຸມແລ້ວ.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ລຶບອອກແລ້ວ"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"ເພີ່ມ <xliff:g id="APPNAME">%s</xliff:g> ບໍ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ສາມາດເລືອກໄດ້ວ່າການຄວບຄຸມ ແລະ ເນື້ອຫາໃດຈະສະແດງຢູ່ບ່ອນນີ້."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"ລຶບການຄວບຄຸມສຳລັບ <xliff:g id="APPNAME">%s</xliff:g> ອອກບໍ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ເພີ່ມລາຍການທີ່ມັກແລ້ວ"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ເພີ່ມລາຍການທີ່ມັກແລ້ວ, ຕຳແໜ່ງ <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index a08c2d9c7b95..893c97802a7c 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Pridėtas # valdiklis.}one{Pridėtas # valdiklis.}few{Pridėti # valdikliai.}many{Pridėta # valdiklio.}other{Pridėta # valdiklių.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Pašalinta"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Pridėti „<xliff:g id="APPNAME">%s</xliff:g>“?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"„<xliff:g id="APPNAME">%s</xliff:g>“ gali pasirinkti, kuriuos valdiklius ir turinį čia rodyti."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Pašalinti „<xliff:g id="APPNAME">%s</xliff:g>“ valdiklius?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Įtraukta į mėgstamiausius"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Įtraukta į mėgstamiausius, padėtis: <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index a83fe80136a0..befcfbe1b105 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Pievienota # vadīkla.}zero{Pievienotas # vadīklas.}one{Pievienota # vadīkla.}other{Pievienotas # vadīklas.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Noņemta"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vai pievienot lietotni <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> var izvēlēties, kuras vadīklas un saturu šeit rādīt."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vai noņemt vadīklas lietotnei <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Pievienota izlasei"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Pievienota izlasei, <xliff:g id="NUMBER">%d</xliff:g>. pozīcija"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 1623ea8216a5..ca1ac647467b 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Додадена е # контрола.}one{Додадени се # контрола.}other{Додадени се # контроли.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Отстранета"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Да се додаде <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> може да избере кои контроли и содржини се прикажуваат овде."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Да се отстранат контролите за <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Омилена"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Омилена, позиција <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 9cb93fa4fbdf..102d81ea0653 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# നിയന്ത്രണം ചേർത്തു.}other{# നിയന്ത്രണങ്ങൾ ചേർത്തു.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"നീക്കം ചെയ്തു"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ചേർക്കണോ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"ഏതൊക്കെ നിയന്ത്രണങ്ങളും ഉള്ളടക്കവും ഇവിടെ ദൃശ്യമാകണമെന്ന് <xliff:g id="APPNAME">%s</xliff:g> എന്നതിന് തിരഞ്ഞെടുക്കാനാകും."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> എന്നതിനുള്ള നിയന്ത്രണങ്ങൾ നീക്കം ചെയ്യണോ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"പ്രിയപ്പെട്ടതാക്കി"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"പ്രിയപ്പെട്ടതാക്കി, സ്ഥാനം <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index bd8a430f051f..020fe3fd27a6 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# хяналт нэмсэн.}other{# хяналт нэмсэн.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Хассан"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>-г нэмэх үү?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> аль хяналт болон контент энд харагдахыг сонгож болно."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g>-н тохиргоог хасах уу?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Дуртай гэж тэмдэглэсэн"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>-р байршилд дуртай гэж тэмдэглэсэн"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index cdd7771b0fe2..13111e2685c1 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -144,10 +144,10 @@ <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"चेहरा ऑथेंटिकेशन केलेला आहे"</string> <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"निश्चित केले"</string> <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"पूर्ण करण्यासाठी खात्री करा वर टॅप करा"</string> - <string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"चेहऱ्याने अनलॉक केले. सुरू ठेवण्यासाठी अनलॉक करा आयकन दाबा."</string> - <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहऱ्याने अनलॉक केले आहे. पुढे सुरू ठेवण्यासाठी दाबा."</string> - <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी दाबा."</string> - <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी अनलॉक करा आयकन दाबा."</string> + <string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"चेहऱ्याने अनलॉक केले. सुरू ठेवण्यासाठी अनलॉक करा आयकन प्रेस करा."</string> + <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"चेहऱ्याने अनलॉक केले आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string> + <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी प्रेस करा."</string> + <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"चेहरा ओळखला आहे. पुढे सुरू ठेवण्यासाठी अनलॉक करा आयकन प्रेस करा."</string> <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"ऑथेंटिकेशन केलेले"</string> <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"पिन वापरा"</string> <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"पॅटर्न वापरा"</string> @@ -323,12 +323,12 @@ <string name="notification_tap_again" msgid="4477318164947497249">"उघडण्यासाठी पुन्हा टॅप करा"</string> <string name="tap_again" msgid="1315420114387908655">"पुन्हा टॅप करा"</string> <string name="keyguard_unlock" msgid="8031975796351361601">"उघडण्यासाठी वर स्वाइप करा"</string> - <string name="keyguard_unlock_press" msgid="9140109453735019209">"उघडण्यासाठी अनलॉक करा आयकन दाबा"</string> + <string name="keyguard_unlock_press" msgid="9140109453735019209">"उघडण्यासाठी अनलॉक करा आयकन प्रेस करा"</string> <string name="keyguard_face_successful_unlock_swipe" msgid="6180997591385846073">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी वर स्वाइप करा."</string> - <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"चेहऱ्याने अनलॉक केले. उघडण्यासाठी अनलॉक करा आयकन दाबा."</string> - <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी दाबा."</string> - <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरा ओळखला आहे. उघडण्यासाठी दाबा."</string> - <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरा ओळखला आहे. उघडण्यासाठी अनलॉक करा आयकन दाबा."</string> + <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"चेहऱ्याने अनलॉक केले. उघडण्यासाठी अनलॉक करा आयकन प्रेस करा."</string> + <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"चेहऱ्याने अनलॉक केले आहे. उघडण्यासाठी प्रेस करा."</string> + <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"चेहरा ओळखला आहे. उघडण्यासाठी प्रेस करा."</string> + <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"चेहरा ओळखला आहे. उघडण्यासाठी अनलॉक करा आयकन प्रेस करा."</string> <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"चेहऱ्याने अनलॉक केले आहे"</string> <string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"चेहरा ओळखला आहे"</string> <string-array name="udfps_accessibility_touch_hints"> @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# नियंत्रण जोडले आहे.}other{# नियंत्रणे जोडली आहेत.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"काढून टाकले"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> जोडायचे आहे का?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> हे येथे कोणती नियंत्रणे आणि आशय दाखवावा ते निवडू शकते."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> साठी नियंत्रणे काढून टाकायची आहेत का?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"आवडले"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"आवडले, स्थान <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 432a10b61faf..526c0503e89f 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kawalan ditambah.}other{# kawalan ditambah.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Dialih keluar"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Tambahkan <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g>boleh memilih kawalan dan kandungan yang dipaparkan di sini."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Alih keluar kawalan untuk <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Digemari"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Digemari, kedudukan <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 3c81d567eed6..835376c747ba 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ထိန်းချုပ်ခလုတ် # ခု ထည့်ထားသည်။}other{ထိန်းချုပ်ခလုတ် # ခု ထည့်ထားသည်။}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ဖယ်ရှားထားသည်"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ထည့်မလား။"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> သည် ဤနေရာတွင်ပြသည့် သတ်မှတ်ချက်နှင့် အကြောင်းအရာများကို ရွေးနိုင်သည်။"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> အတွက် သတ်မှတ်ချက်များ ဖယ်ရှားမလား။"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"အကြိုက်ဆုံးတွင် ထည့်ထားသည်"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"အကြိုက်ဆုံးတွင် ထည့်ထားသည်၊ အဆင့် <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index e8900223db81..fc5a2ec0afa0 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# कन्ट्रोल हालियो।}other{# वटा कन्ट्रोल हालियो।}}"</string> <string name="controls_removed" msgid="3731789252222856959">"हटाइएको"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> हाल्ने हो?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ले यहाँ कुन कुन कन्ट्रोल र सामग्री देखाउने भन्ने कुरा छनौट गर्न सक्छ।"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> का सेटिङ हटाउने हो?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"मनपराइएको"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"मन पराइएका कुराहरूको <xliff:g id="NUMBER">%d</xliff:g> औँ स्थानमा"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index fc5f97d807af..2682ec8df56a 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# bedieningselement toegevoegd.}other{# bedieningselementen toegevoegd.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Verwijderd"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> toevoegen?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan kiezen welke bedieningselementen en content hier worden getoond."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Bedieningselementen voor <xliff:g id="APPNAME">%s</xliff:g> verwijderen?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Gemarkeerd als favoriet"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Gemarkeerd als favoriet, positie <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 2d8b07f2dd59..cc69f846682f 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{#ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।}other{#ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।}}"</string> <string name="controls_removed" msgid="3731789252222856959">"କାଢ଼ି ଦିଆଯାଇଛି"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>କୁ ଯୋଗ କରିବେ?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"ଏଠାରେ କେଉଁ ନିୟନ୍ତ୍ରଣ ଏବଂ ବିଷୟବସ୍ତୁ ଦେଖାଯିବ ତାହା <xliff:g id="APPNAME">%s</xliff:g> ବାଛିପାରିବ।"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> ପାଇଁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ କାଢ଼ି ଦେବେ?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ପସନ୍ଦ କରାଯାଇଛି"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ପସନ୍ଦ କରାଯାଇଛି, ସ୍ଥିତି <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 9be8569fd847..ec4cecb0fa35 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodano # element sterujący.}few{Dodano # elementy sterujące.}many{Dodano # elementów sterujących.}other{Dodano # elementu sterującego.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Usunięto"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Dodać aplikację <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Aplikacja <xliff:g id="APPNAME">%s</xliff:g> może wybrać elementy sterujące i treści, które się tu pojawią."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Usunąć elementy sterujące aplikacji <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano do ulubionych"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano do ulubionych, pozycja <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index c69d78e88214..f950f36014de 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removido"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar o app <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> pode escolher quais controles e conteúdos aparecem aqui."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remover controles do app <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 1c2bc280ec3b..78f179d26cc1 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controlo adicionado.}many{# controlos adicionados.}other{# controlos adicionados.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removido"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"A app <xliff:g id="APPNAME">%s</xliff:g> pode escolher que controlos e conteúdos são apresentados aqui."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remover controlos para a app <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionados aos favoritos, posição <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index c69d78e88214..f950f36014de 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Removido"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar o app <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> pode escolher quais controles e conteúdos aparecem aqui."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Remover controles do app <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index e0a15a2fe88c..b8146da2c334 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S-a adăugat # comandă.}few{S-au adăugat # comenzi.}other{S-au adăugat # de comenzi.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Eliminată"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adaugi <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> poate să aleagă comenzile și conținutul care se afișează aici."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Elimini comenzile pentru <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Marcată ca preferată"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Marcată ca preferată, poziția <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 89090308f8ae..1f4ffea6ced4 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Добавлен # элемент управления.}one{Добавлен # элемент управления.}few{Добавлено # элемента управления.}many{Добавлено # элементов управления.}other{Добавлено # элемента управления.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Удалено"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Добавить приложение \"<xliff:g id="APPNAME">%s</xliff:g>\"?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Приложение \"<xliff:g id="APPNAME">%s</xliff:g>\" может выбирать, какой контент и настройки будут здесь показываться."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Удалить приложение \"<xliff:g id="APPNAME">%s</xliff:g>\" с панели управления устройствами?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Добавлено в избранное"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Добавлено в избранное на позицию <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 786b75edb8b6..f2262599e968 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Bol pridaný # ovládací prvok.}few{Boli pridané # ovládacie prvky.}many{# controls added.}other{Bolo pridaných # ovládacích prvkov.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Odstránené"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Chcete pridať aplikáciu <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> môže vybrať, ktoré ovládacie prvky a obsah sa tu majú zobrazovať."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Chcete odstrániť ovládanie aplikácie <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Pridané medzi obľúbené"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Pridané medzi obľúbené, pozícia <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index b8b4152396c0..3d040924b21b 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrolnik je dodan.}one{# kontrolnik je dodan.}two{# kontrolnika sta dodana.}few{# kontrolniki so dodani.}other{# kontrolnikov je dodanih.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Odstranjeno"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite dodati aplikacijo <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Aplikacija <xliff:g id="APPNAME">%s</xliff:g> lahko izbere, kateri kontrolniki in vsebine so prikazani tukaj."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Želite odstraniti kontrolnike za aplikacijo <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano med priljubljene"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano med priljubljene, položaj <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 031da8da0cdd..a348385550cd 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{U shtua # kontroll.}other{U shtuan # kontrolle.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"E hequr"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Të shtohet <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> mund të zgjedhë se cilat kontrolle dhe përmbajtje shfaqen këtu."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Të hiqen kontrollet për <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"E shtuar te të preferuarat"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"E shtuar te të preferuarat, pozicioni <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 074bb3c510ad..fef43eb6b637 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# контрола је додата.}one{# контрола је додата.}few{# контроле су додате.}other{# контрола је додато.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Уклоњено"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Желите ли да додате <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> може да одабере које контроле и садржај се приказују овде."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Желите да уклоните контроле за <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Означено је као омиљено"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Означено је као омиљено, <xliff:g id="NUMBER">%d</xliff:g>. позиција"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index afb190f1b50e..3d1ed13cc946 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontroll har lagts till.}other{# kontroller har lagts till.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Har tagits bort"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vill du lägga till <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> kan välja vilka kontroller och vilket innehåll som visas här."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Vill du ta bort inställningarna för <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Har lagts till som favorit"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Har lagts till som favorit, plats <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index c2edd6e25fba..b3d71a5349da 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Umeweka kidhibiti #.}other{Umeweka vidhibiti #.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Kimeondolewa"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Ungependa kuweka <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> inaweza kuchagua ni vidhibiti na maudhui yapi yatakayoonekana hapa."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Ungependa kuondoa vidhibiti vya <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Kimewekwa kwenye vipendwa"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Kimewekwa kwenye vipendwa, nafasi ya <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 23fc2ff8cccd..45b73c0f7693 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# కంట్రోల్ జోడించబడింది.}other{# కంట్రోల్స్ జోడించబడ్డాయి.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"తీసివేయబడింది"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g>ను జోడించాలా?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> ఇక్కడ ఏ కంట్రోల్స్, కంటెంట్ కనిపించాలో ఎంచుకోగలదు."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> కోసం కంట్రోల్స్ను తీసివేయాలా?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ఇష్టమైనదిగా గుర్తు పెట్టబడింది"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>వ స్థానంలో ఇష్టమైనదిగా గుర్తు పెట్టబడింది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 40f4667b3c69..c523d97ee7a3 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{เพิ่มตัวควบคุม # ตัวแล้ว}other{เพิ่มตัวควบคุม # ตัวแล้ว}}"</string> <string name="controls_removed" msgid="3731789252222856959">"นำออกแล้ว"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"เพิ่ม <xliff:g id="APPNAME">%s</xliff:g> ไหม"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> สามารถเลือกตัวควบคุมและเนื้อหาที่จะปรากฏขึ้นที่นี่"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"นำการควบคุมสำหรับ <xliff:g id="APPNAME">%s</xliff:g> ออกไหม"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"ตั้งเป็นรายการโปรดแล้ว"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"ตั้งเป็นรายการโปรดแล้ว โดยอยู่ลำดับที่ <xliff:g id="NUMBER">%d</xliff:g>"</string> @@ -835,7 +834,7 @@ <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"ควบคุมอุปกรณ์จากหน้าจอล็อกไหม"</string> <string name="controls_settings_trivial_controls_dialog_message" msgid="397178734990952575">"คุณควบคุมอุปกรณ์บางอย่างได้โดยไม่ต้องปลดล็อกโทรศัพท์หรือแท็บเล็ต แอปจัดการอุปกรณ์จะระบุอุปกรณ์ที่สามารถควบคุมด้วยวิธีนี้ได้"</string> <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"ไม่เป็นไร"</string> - <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"มี"</string> + <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"ใช่"</string> <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"PIN ประกอบด้วยตัวอักษรหรือสัญลักษณ์"</string> <string name="controls_pin_verify" msgid="3452778292918877662">"ยืนยัน <xliff:g id="DEVICE">%s</xliff:g>"</string> <string name="controls_pin_wrong" msgid="6162694056042164211">"PIN ไม่ถูกต้อง"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index dfe9eea044ef..93f817757230 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Nagdagdag ng # kontrol.}one{Nagdagdag ng # kontrol.}other{Nagdagdag ng # na kontrol.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Inalis"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Idagdag ang <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"Mapipili ng <xliff:g id="APPNAME">%s</xliff:g> kung aling mga kontrol at content ang lalabas dito."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Alisin ang mga kontrol para sa <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Ginawang paborito"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ginawang paborito, posisyon <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 45bdfca3cda5..793d733dc164 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# کنٹرول کو شامل کیا گیا۔}other{# کنٹرولز کو شامل کیا گیا۔}}"</string> <string name="controls_removed" msgid="3731789252222856959">"ہٹا دیا گیا"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> کو شامل کریں؟"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> انتخاب کر سکتی ہے کہ یہاں کون سے کنٹرولز اور مواد دکھایا جائے۔"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> کے کنٹرولز کو ہٹا دیں؟"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"پسند کردہ"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"پسند کردہ، پوزیشن <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index a108b354ba89..6eba5b274951 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ta boshqaruv elementi kiritildi.}other{# ta boshqaruv elementi kiritildi.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Olib tashlandi"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> qoʻshilsinmi?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> bu yerda qaysi kontent va sozlamalar chiqishini tanlay oladi."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"<xliff:g id="APPNAME">%s</xliff:g> qurilma boshqaruv panelidan olib tashlansinmi?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Saralanganlarga kiritilgan"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Saralanganlarga kiritilgan, <xliff:g id="NUMBER">%d</xliff:g>-joy"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index f8efbfa6205f..5cd6afe8f198 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Đã thêm # chế độ điều khiển.}other{Đã thêm # chế độ điều khiển.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Đã xóa"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Thêm <xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"<xliff:g id="APPNAME">%s</xliff:g> có thể chọn các nút điều khiển và nội dung hiện ở đây."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Xoá chế độ cài đặt cho <xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Được yêu thích"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Được yêu thích, vị trí số <xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 50883f092eb8..14b46674557e 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已添加 # 个控件。}other{已添加 # 个控件。}}"</string> <string name="controls_removed" msgid="3731789252222856959">"已移除"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"添加“<xliff:g id="APPNAME">%s</xliff:g>”?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"“<xliff:g id="APPNAME">%s</xliff:g>”可以选择在此处显示哪些控件和内容。"</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"移除<xliff:g id="APPNAME">%s</xliff:g>的控件?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"已收藏"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"已收藏,位置:<xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 837031984da8..281e57e4b972 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -807,8 +807,7 @@ <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ulawulo olu-# olwengeziwe.}one{ukulawulwa okungu-# okwengeziwe.}other{ukulawulwa okungu-# okwengeziwe.}}"</string> <string name="controls_removed" msgid="3731789252222856959">"Isusiwe"</string> <string name="controls_panel_authorization_title" msgid="267429338785864842">"Engeza i-<xliff:g id="APPNAME">%s</xliff:g>?"</string> - <!-- no translation found for controls_panel_authorization (7045551688535104194) --> - <skip /> + <string name="controls_panel_authorization" msgid="7045551688535104194">"I-<xliff:g id="APPNAME">%s</xliff:g> ingakhetha ukuthi yiziphi izilawuli nokuqukethwe okuboniswa lapha."</string> <string name="controls_panel_remove_app_authorization" msgid="5920442084735364674">"Susa izilawuli ze-<xliff:g id="APPNAME">%s</xliff:g>?"</string> <string name="accessibility_control_favorite" msgid="8694362691985545985">"Kwenziwe intandokazi"</string> <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Kwenziwe intandokazi, isimo esiyi-<xliff:g id="NUMBER">%d</xliff:g>"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 89857f120396..91459825f5e0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1632,11 +1632,11 @@ .2 </item> - <!-- The margins applied to the dream overlay container --> - <dimen name="dream_overlay_container_margin_start">0dp</dimen> - <dimen name="dream_overlay_container_margin_end">0dp</dimen> - <dimen name="dream_overlay_container_margin_top">0dp</dimen> - <dimen name="dream_overlay_container_margin_bottom">0dp</dimen> + <!-- The padding applied to the dream overlay container --> + <dimen name="dream_overlay_container_padding_start">0dp</dimen> + <dimen name="dream_overlay_container_padding_end">0dp</dimen> + <dimen name="dream_overlay_container_padding_top">0dp</dimen> + <dimen name="dream_overlay_container_padding_bottom">0dp</dimen> <!-- The margin applied between complications --> <dimen name="dream_overlay_complication_margin">0dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index 541f69c62a1f..b3cb79e8b3e1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -41,8 +41,8 @@ import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.BiometricUnlockController -import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_DISMISS_BOUNCER import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController @@ -60,9 +60,7 @@ import javax.inject.Provider * The ripple uses the accent color of the current theme. */ @CentralSurfacesScope -class AuthRippleController -@Inject -constructor( +class AuthRippleController @Inject constructor( private val centralSurfaces: CentralSurfaces, private val sysuiContext: Context, private val authController: AuthController, @@ -72,18 +70,18 @@ constructor( private val wakefulnessLifecycle: WakefulnessLifecycle, private val commandRegistry: CommandRegistry, private val notificationShadeWindowController: NotificationShadeWindowController, + private val bypassController: KeyguardBypassController, private val biometricUnlockController: BiometricUnlockController, private val udfpsControllerProvider: Provider<UdfpsController>, private val statusBarStateController: StatusBarStateController, private val featureFlags: FeatureFlags, private val logger: KeyguardLogger, - rippleView: AuthRippleView? -) : - ViewController<AuthRippleView>(rippleView), - KeyguardStateController.Callback, + rippleView: AuthRippleView? +) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback, WakefulnessLifecycle.Observer { - @VisibleForTesting internal var startLightRevealScrimOnKeyguardFadingAway = false + @VisibleForTesting + internal var startLightRevealScrimOnKeyguardFadingAway = false var lightRevealScrimAnimator: ValueAnimator? = null var fingerprintSensorLocation: Point? = null private var faceSensorLocation: Point? = null @@ -92,21 +90,6 @@ constructor( private var udfpsController: UdfpsController? = null private var udfpsRadius: Float = -1f - private val biometricModeListener = object : BiometricUnlockController.BiometricModeListener { - override fun onModeChanged(mode: Int) { - // isBiometricUnlock does not cover the scenario when biometrics unlocks - // the device while the bouncer is showing. - if (biometricUnlockController.isBiometricUnlock || mode == MODE_DISMISS_BOUNCER) { - showUnlockRipple(biometricUnlockController.biometricType) - } - } - } - - override fun onInit() { - mView.setAlphaInDuration(sysuiContext.resources.getInteger( - R.integer.auth_ripple_alpha_in_duration).toLong()) - } - @VisibleForTesting public override fun onViewAttached() { authController.addCallback(authControllerCallback) @@ -118,7 +101,6 @@ constructor( keyguardStateController.addCallback(this) wakefulnessLifecycle.addObserver(this) commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() } - biometricUnlockController.addBiometricModeListener(biometricModeListener) } @VisibleForTesting @@ -130,7 +112,6 @@ constructor( keyguardStateController.removeCallback(this) wakefulnessLifecycle.removeObserver(this) commandRegistry.unregisterCommand("auth-ripple") - biometricUnlockController.removeBiometricModeListener(biometricModeListener) notificationShadeWindowController.setForcePluginOpen(false, this) } @@ -161,7 +142,10 @@ constructor( showUnlockedRipple() } } else if (biometricSourceType == BiometricSourceType.FACE) { - faceSensorLocation?.let { + if (!bypassController.canBypass() && !authController.isUdfpsFingerDown) { + return + } + faceSensorLocation?.let { mView.setSensorLocation(it) circleReveal = CircleReveal( it.x, @@ -282,6 +266,7 @@ constructor( if (biometricSourceType == BiometricSourceType.FINGERPRINT) { mView.fadeDwellRipple() } + showUnlockRipple(biometricSourceType) } override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt index 84094626193d..b0071340cf1a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt @@ -54,12 +54,11 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at private var lockScreenColorVal = Color.WHITE private val fadeDuration = 83L private val retractDuration = 400L - private var alphaInDuration: Long = 0 private val dwellShader = DwellRippleShader() private val dwellPaint = Paint() private val rippleShader = RippleShader() private val ripplePaint = Paint() - private var unlockedRippleAnimator: AnimatorSet? = null + private var unlockedRippleAnimator: Animator? = null private var fadeDwellAnimator: Animator? = null private var retractDwellAnimator: Animator? = null private var dwellPulseOutAnimator: Animator? = null @@ -85,12 +84,12 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at } init { - rippleShader.color = 0xffffffff.toInt() // default color rippleShader.rawProgress = 0f rippleShader.pixelDensity = resources.displayMetrics.density rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH updateRippleFadeParams() ripplePaint.shader = rippleShader + setLockScreenColor(0xffffffff.toInt()) // default color dwellShader.color = 0xffffffff.toInt() // default color dwellShader.progress = 0f @@ -111,10 +110,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at dwellRadius = sensorRadius * 1.5f } - fun setAlphaInDuration(duration: Long) { - alphaInDuration = duration - } - /** * Animate dwell ripple inwards back to radius 0 */ @@ -253,7 +248,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at override fun onAnimationEnd(animation: Animator?) { drawDwell = false - resetRippleAlpha() } }) start() @@ -277,22 +271,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at } } - val alphaInAnimator = ValueAnimator.ofInt(0, 62).apply { - duration = alphaInDuration - addUpdateListener { animator -> - rippleShader.color = ColorUtils.setAlphaComponent( - rippleShader.color, - animator.animatedValue as Int - ) - invalidate() - } - } - - unlockedRippleAnimator = AnimatorSet().apply { - playTogether( - rippleAnimator, - alphaInAnimator - ) + unlockedRippleAnimator = rippleAnimator.apply { addListener(object : AnimatorListenerAdapter() { override fun onAnimationStart(animation: Animator?) { drawRipple = true @@ -310,17 +289,12 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at unlockedRippleAnimator?.start() } - fun resetRippleAlpha() { - rippleShader.color = ColorUtils.setAlphaComponent( - rippleShader.color, - 255 - ) - } - fun setLockScreenColor(color: Int) { lockScreenColorVal = color - rippleShader.color = lockScreenColorVal - resetRippleAlpha() + rippleShader.color = ColorUtils.setAlphaComponent( + lockScreenColorVal, + 62 + ) } fun updateDwellRippleColor(isDozing: Boolean) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt index 224eb1ca409a..c964b9654955 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt @@ -47,7 +47,8 @@ import javax.inject.Inject * destroyed on SCREEN_OFF events, due to issues with occluded activities over lockscreen as well as * user expectations for the activity to not continue running. */ -class ControlsActivity @Inject constructor( +// Open for testing +open class ControlsActivity @Inject constructor( private val uiController: ControlsUiController, private val broadcastDispatcher: BroadcastDispatcher, private val dreamManager: IDreamManager, @@ -98,8 +99,11 @@ class ControlsActivity @Inject constructor( override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - if (lastConfiguration.diff(newConfig) and ActivityInfo.CONFIG_ORIENTATION != 0 ) { - uiController.onOrientationChange() + val interestingFlags = ActivityInfo.CONFIG_ORIENTATION or + ActivityInfo.CONFIG_SCREEN_SIZE or + ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE + if (lastConfiguration.diff(newConfig) and interestingFlags != 0 ) { + uiController.onSizeChange() } lastConfiguration = newConfig } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 3ecf4236656d..0cc4683baef1 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -65,7 +65,7 @@ interface ControlsUiController { */ fun getPreferredSelectedItem(structures: List<StructureInfo>): SelectedItem - fun onOrientationChange() + fun onSizeChange() } sealed class SelectedItem { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index d2833796d2a5..554391649548 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -809,7 +809,7 @@ class ControlsUiControllerImpl @Inject constructor ( } } - override fun onOrientationChange() { + override fun onSizeChange() { selectionItem?.let { when (selectedItem) { is SelectedItem.StructureItem -> createListView(it) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index fc3263fd3d11..f0aefb5bc0df 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -398,7 +398,8 @@ public class DozeMachine { } if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING || mState == State.DOZE_AOD || mState == State.DOZE - || mState == State.DOZE_AOD_DOCKED) && requestedState == State.DOZE_PULSE_DONE) { + || mState == State.DOZE_AOD_DOCKED || mState == State.DOZE_SUSPEND_TRIGGERS) + && requestedState == State.DOZE_PULSE_DONE) { Log.i(TAG, "Dropping pulse done because current state is already done: " + mState); return mState; } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index e15ca46b6c59..2bfd9fd5b963 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -233,7 +233,7 @@ object Flags { /** Whether to inflate the bouncer view on a background thread. */ // TODO(b/272091103): Tracking Bug @JvmField - val ASYNC_INFLATE_BOUNCER = unreleasedFlag(229, "async_inflate_bouncer", teamfood = true) + val ASYNC_INFLATE_BOUNCER = unreleasedFlag(229, "async_inflate_bouncer", teamfood = false) /** Whether to inflate the bouncer view on a background thread. */ // TODO(b/273341787): Tracking Bug @@ -258,20 +258,12 @@ object Flags { // TODO(b/270223352): Tracking Bug @JvmField val HIDE_SMARTSPACE_ON_DREAM_OVERLAY = - unreleasedFlag( - 404, - "hide_smartspace_on_dream_overlay", - teamfood = true - ) + releasedFlag(404, "hide_smartspace_on_dream_overlay") // TODO(b/271460958): Tracking Bug @JvmField val SHOW_WEATHER_COMPLICATION_ON_DREAM_OVERLAY = - unreleasedFlag( - 405, - "show_weather_complication_on_dream_overlay", - teamfood = true - ) + releasedFlag(405, "show_weather_complication_on_dream_overlay") // 500 - quick settings @@ -425,7 +417,7 @@ object Flags { @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag(1002, "rounded_box_ripple") // TODO(b/270882464): Tracking Bug - val ENABLE_DOCK_SETUP_V2 = unreleasedFlag(1005, "enable_dock_setup_v2", teamfood = true) + val ENABLE_DOCK_SETUP_V2 = releasedFlag(1005, "enable_dock_setup_v2") // TODO(b/265045965): Tracking Bug val SHOW_LOWLIGHT_ON_DIRECT_BOOT = releasedFlag(1003, "show_lowlight_on_direct_boot") @@ -527,7 +519,7 @@ object Flags { @JvmField val ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP = sysPropBooleanFlag( - 1116, "persist.wm.debug.enable_move_floating_window_in_tabletop", default = false) + 1116, "persist.wm.debug.enable_move_floating_window_in_tabletop", default = true) // 1200 - predictive back @Keep diff --git a/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt b/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt index b49d60dbdde1..dc0de2cef349 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/RestartDozeListener.kt @@ -39,15 +39,15 @@ constructor( ) { companion object { - @VisibleForTesting val RESTART_NAP_KEY = "restart_nap_after_start" + @VisibleForTesting val RESTART_SLEEP_KEY = "restart_nap_after_start" } private var inited = false val listener = object : StatusBarStateController.StateListener { - override fun onDreamingChanged(isDreaming: Boolean) { - storeSleepState(isDreaming) + override fun onDozingChanged(isDozing: Boolean) { + storeSleepState(isDozing) } } @@ -67,9 +67,13 @@ constructor( fun maybeRestartSleep() { bgExecutor.executeDelayed( { - if (settings.getBool(RESTART_NAP_KEY, false)) { + if (settings.getBool(RESTART_SLEEP_KEY, false)) { Log.d("RestartDozeListener", "Restarting sleep state") - powerManager.wakeUp(systemClock.uptimeMillis()) + powerManager.wakeUp( + systemClock.uptimeMillis(), + PowerManager.WAKE_REASON_APPLICATION, + "RestartDozeListener" + ) powerManager.goToSleep(systemClock.uptimeMillis()) } }, @@ -78,6 +82,6 @@ constructor( } private fun storeSleepState(sleeping: Boolean) { - bgExecutor.execute { settings.putBool(RESTART_NAP_KEY, sleeping) } + bgExecutor.execute { settings.putBool(RESTART_SLEEP_KEY, sleeping) } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt index 95d38b1fdd82..0a3b3d3796cc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt @@ -309,6 +309,10 @@ constructor( /** Tell the bouncer to start the pre hide animation. */ fun startDisappearAnimation(runnable: Runnable) { + if (willRunDismissFromKeyguard()) { + runnable.run() + return + } val finishRunnable = Runnable { runnable.run() repository.setPrimaryStartDisappearAnimation(null) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt index b23247c30256..df93d235245c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt @@ -81,9 +81,7 @@ constructor( ) .map { if (willRunDismissFromKeyguard) { - ScrimAlpha( - notificationsAlpha = 1f, - ) + ScrimAlpha() } else if (leaveShadeOpen) { ScrimAlpha( behindAlpha = 1f, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt index 9c7b48d2514d..0176c4273a68 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt @@ -39,7 +39,6 @@ import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -69,7 +68,6 @@ import com.android.systemui.util.time.SystemClock import com.android.systemui.util.traceSection import java.io.PrintWriter import java.util.TreeMap -import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.CoroutineScope @@ -95,8 +93,7 @@ constructor( private val mediaHostStatesManager: MediaHostStatesManager, private val activityStarter: ActivityStarter, private val systemClock: SystemClock, - @Main private val mainExecutor: DelayableExecutor, - @Background private val backgroundExecutor: Executor, + @Main executor: DelayableExecutor, private val mediaManager: MediaDataManager, configurationController: ConfigurationController, falsingCollector: FalsingCollector, @@ -253,7 +250,7 @@ constructor( MediaCarouselScrollHandler( mediaCarousel, pageIndicator, - mainExecutor, + executor, this::onSwipeToDismiss, this::updatePageIndicatorLocation, this::updateSeekbarListening, @@ -615,50 +612,10 @@ constructor( MediaPlayerData.visiblePlayerKeys() .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) if (existingPlayer == null) { - setupNewPlayer(key, data, isSsReactivated, curVisibleMediaKey) - } else { - existingPlayer.bindPlayer(data, key) - MediaPlayerData.addMediaPlayer( - key, - data, - existingPlayer, - systemClock, - isSsReactivated, - debugLogger - ) - val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String() - // In case of recommendations hits. - // Check the playing status of media player and the package name. - // To make sure we scroll to the right app's media player. - if ( - isReorderingAllowed || - shouldScrollToKey && - data.isPlaying == true && - packageName == data.packageName - ) { - reorderAllPlayers(curVisibleMediaKey, key) - } else { - needsReordering = true - } - updatePageIndicator() - mediaCarouselScrollHandler.onPlayersChanged() - mediaFrame.requiresRemeasuring = true - } - return existingPlayer == null - } - - private fun setupNewPlayer( - key: String, - data: MediaData, - isSsReactivated: Boolean, - curVisibleMediaKey: MediaPlayerData.MediaSortKey?, - ) { - backgroundExecutor.execute { - val mediaViewHolder = createMediaViewHolderInBg() - // Add the new player in the main thread. - mainExecutor.execute { val newPlayer = mediaControlPanelFactory.get() - newPlayer.attachPlayer(mediaViewHolder) + newPlayer.attachPlayer( + MediaViewHolder.create(LayoutInflater.from(context), mediaContent) + ) newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = LinearLayout.LayoutParams( @@ -688,16 +645,36 @@ constructor( } else { needsReordering = true } - updatePageIndicator() - mediaCarouselScrollHandler.onPlayersChanged() - mediaFrame.requiresRemeasuring = true + } else { + existingPlayer.bindPlayer(data, key) + MediaPlayerData.addMediaPlayer( + key, + data, + existingPlayer, + systemClock, + isSsReactivated, + debugLogger + ) + val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String() + // In case of recommendations hits. + // Check the playing status of media player and the package name. + // To make sure we scroll to the right app's media player. + if ( + isReorderingAllowed || + shouldScrollToKey && + data.isPlaying == true && + packageName == data.packageName + ) { + reorderAllPlayers(curVisibleMediaKey, key) + } else { + needsReordering = true + } } + updatePageIndicator() + mediaCarouselScrollHandler.onPlayersChanged() + mediaFrame.requiresRemeasuring = true + return existingPlayer == null } - } - - private fun createMediaViewHolderInBg(): MediaViewHolder { - return MediaViewHolder.create(LayoutInflater.from(context), mediaContent) - } private fun addSmartspaceMediaRecommendations( key: String, @@ -731,14 +708,15 @@ constructor( debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey) } } + val newRecs = mediaControlPanelFactory.get() - val recommendationViewHolder = + newRecs.attachRecommendation( RecommendationViewHolder.create( LayoutInflater.from(context), mediaContent, mediaFlags.isRecommendationCardUpdateEnabled() ) - newRecs.attachRecommendation(recommendationViewHolder) + ) newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = LinearLayout.LayoutParams( @@ -762,6 +740,17 @@ constructor( reorderAllPlayers(curVisibleMediaKey) updatePageIndicator() mediaFrame.requiresRemeasuring = true + // Check postcondition: mediaContent should have the same number of children as there + // are + // elements in mediaPlayers. + if (MediaPlayerData.players().size != mediaContent.childCount) { + Log.e( + TAG, + "Size of players list and number of views in carousel are out of sync. " + + "Players size is ${MediaPlayerData.players().size}. " + + "View count is ${mediaContent.childCount}." + ) + } } fun removePlayer( diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index c91f855a853d..36eab3949318 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -646,12 +646,15 @@ public class MediaControlPanel { } else { mLogger.logOpenOutputSwitcher(mUid, mPackageName, mInstanceId); if (device.getIntent() != null) { - if (device.getIntent().isActivity()) { - mActivityStarter.startActivity( - device.getIntent().getIntent(), true); + PendingIntent deviceIntent = device.getIntent(); + boolean showOverLockscreen = mKeyguardStateController.isShowing() + && mActivityIntentHelper.wouldPendingShowOverLockscreen( + deviceIntent, mLockscreenUserManager.getCurrentUserId()); + if (deviceIntent.isActivity() && !showOverLockscreen) { + mActivityStarter.postStartActivityDismissingKeyguard(deviceIntent); } else { try { - device.getIntent().send(); + deviceIntent.send(); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Device pending intent was canceled"); } diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt index 9bccb7df4ed0..89f66b7daaf8 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt @@ -19,12 +19,11 @@ package com.android.systemui.mediaprojection.appselector.view import android.content.Context import android.content.res.Configuration import android.graphics.Rect +import android.view.WindowInsets.Type import android.view.WindowManager -import com.android.internal.R as AndroidR import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener import com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen -import com.android.systemui.shared.system.QuickStepContract import com.android.systemui.statusbar.policy.CallbackController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener @@ -62,17 +61,12 @@ constructor( val width = windowMetrics.bounds.width() var height = maximumWindowHeight - // TODO(b/271410803): Read isTransientTaskbar from Launcher val isLargeScreen = isLargeScreen(context) - val isTransientTaskbar = - QuickStepContract.isGesturalMode( - context.resources.getInteger( - com.android.internal.R.integer.config_navBarInteractionMode - ) - ) - if (isLargeScreen && !isTransientTaskbar) { + if (isLargeScreen) { val taskbarSize = - context.resources.getDimensionPixelSize(AndroidR.dimen.taskbar_frame_height) + windowManager.currentWindowMetrics.windowInsets + .getInsets(Type.tappableElement()) + .bottom height -= taskbarSize } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 46412a37572c..75d01723667d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -478,13 +478,13 @@ public class InternetTile extends QSTileImpl<SignalState> { synchronized (mSignalCallback.mWifiInfo) { mSignalCallback.mWifiInfo.copyTo(mifiInfo); } - handleUpdateCellularState(state, mifiInfo); + handleUpdateWifiState(state, mifiInfo); } else if (mLastTileState == LAST_STATE_ETHERNET) { EthernetCallbackInfo ethernetInfo = new EthernetCallbackInfo(); synchronized (mSignalCallback.mEthernetInfo) { mSignalCallback.mEthernetInfo.copyTo(ethernetInfo); } - handleUpdateCellularState(state, ethernetInfo); + handleUpdateEthernetState(state, ethernetInfo); } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 0748bcbf020c..c28a40a91378 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -140,7 +140,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private final Handler mHandler; private final Lazy<NavigationBarController> mNavBarControllerLazy; private final NotificationShadeWindowController mStatusBarWinController; - private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser; + private final Runnable mConnectionRunnable = () -> + internalConnectToCurrentUser("runnable: startConnectionToCurrentUser"); private final ComponentName mRecentsComponentName; private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>(); private final Intent mQuickStepIntent; @@ -406,7 +407,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis // Failed to link to death (process may have died between binding and connecting), // just unbind the service for now and retry again Log.e(TAG_OPS, "Lost connection to launcher service", e); - disconnectFromLauncherService(); + disconnectFromLauncherService("Lost connection to launcher service"); retryConnectionWithBackoff(); return; } @@ -501,7 +502,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis @Override public void onUserChanged(int newUser, @NonNull Context userContext) { mConnectionBackoffAttempts = 0; - internalConnectToCurrentUser(); + internalConnectToCurrentUser("User changed"); } }; @@ -716,12 +717,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis if (mHandler.getLooper() != Looper.myLooper()) { mHandler.post(mConnectionRunnable); } else { - internalConnectToCurrentUser(); + internalConnectToCurrentUser("startConnectionToCurrentUser"); } } - private void internalConnectToCurrentUser() { - disconnectFromLauncherService(); + private void internalConnectToCurrentUser(String reason) { + disconnectFromLauncherService(reason); // If user has not setup yet or already connected, do not try to connect if (!isEnabled()) { @@ -783,7 +784,9 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis return mOverviewProxy; } - private void disconnectFromLauncherService() { + private void disconnectFromLauncherService(String disconnectReason) { + Log.d(TAG_OPS, "disconnectFromLauncherService bound?: " + mBound + + " currentProxy: " + mOverviewProxy + " disconnectReason: " + disconnectReason); if (mBound) { // Always unbind the service (ie. if called through onNullBinding or onBindingDied) mContext.unbindService(mOverviewServiceConnection); @@ -1047,6 +1050,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mContext.unregisterReceiver(mLauncherStateChangedReceiver); mIsEnabled = false; mHandler.removeCallbacks(mConnectionRunnable); - disconnectFromLauncherService(); + disconnectFromLauncherService("Shutdown for test"); } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index c4784d6211bb..3541aaf53a7e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -961,6 +961,7 @@ public final class NotificationPanelViewController implements Dumpable { onTrackingStopped(false); instantCollapse(); } else { + mView.animate().cancel(); mView.animate() .alpha(0f) .setStartDelay(0) @@ -2732,7 +2733,6 @@ public final class NotificationPanelViewController implements Dumpable { public void setIsLaunchAnimationRunning(boolean running) { boolean wasRunning = mIsLaunchAnimationRunning; mIsLaunchAnimationRunning = running; - mCentralSurfaces.updateIsKeyguard(); if (wasRunning != mIsLaunchAnimationRunning) { mShadeExpansionStateManager.notifyLaunchingActivityChanged(running); } @@ -3087,7 +3087,9 @@ public final class NotificationPanelViewController implements Dumpable { */ public void startFoldToAodAnimation(Runnable startAction, Runnable endAction, Runnable cancelAction) { - mView.animate() + final ViewPropertyAnimator viewAnimator = mView.animate(); + viewAnimator.cancel(); + viewAnimator .translationX(0) .alpha(1f) .setDuration(ANIMATION_DURATION_FOLD_TO_AOD) @@ -3106,9 +3108,14 @@ public final class NotificationPanelViewController implements Dumpable { @Override public void onAnimationEnd(Animator animation) { endAction.run(); + + viewAnimator.setListener(null); + viewAnimator.setUpdateListener(null); } - }).setUpdateListener(anim -> mKeyguardStatusViewController.animateFoldToAod( - anim.getAnimatedFraction())).start(); + }) + .setUpdateListener(anim -> + mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction())) + .start(); } /** Cancels fold to AOD transition and resets view state. */ @@ -3307,6 +3314,7 @@ public final class NotificationPanelViewController implements Dumpable { } public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) { + mView.animate().cancel(); return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration( durationMs).setInterpolator(Interpolators.ALPHA_OUT).withLayer().withEndAction( endAction); @@ -3796,10 +3804,6 @@ public final class NotificationPanelViewController implements Dumpable { return mClosing || mIsLaunchAnimationRunning; } - public boolean isLaunchAnimationRunning() { - return mIsLaunchAnimationRunning; - } - public boolean isTracking() { return mTracking; } diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index e7759df6e81b..156e4fd1889f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -301,11 +301,9 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW } private void applyKeyguardFlags(NotificationShadeWindowState state) { - // Keyguard is visible if it's showing or if it's fading away (in which case we're animating - // it out, but the wallpaper should remain visible as a backdrop for the animation); - final boolean keyguardOrAodVisible = (state.keyguardShowing || state.keyguardFadingAway) + final boolean keyguardOrAod = state.keyguardShowing || (state.dozing && mDozeParameters.getAlwaysOn()); - if ((keyguardOrAodVisible && !state.mediaBackdropShowing && !state.lightRevealScrimOpaque) + if ((keyguardOrAod && !state.mediaBackdropShowing && !state.lightRevealScrimOpaque) || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind()) { // Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a // solid backdrop. Also, show it if we are currently animating between the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java index 5adb58bca886..63179dac7b8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java @@ -77,12 +77,6 @@ public class CrossFadeHelper { */ public static void fadeOut(View view, float fadeOutAmount, boolean remap) { view.animate().cancel(); - - // Don't fade out if already not visible. - if (view.getAlpha() == 0.0f) { - return; - } - if (fadeOutAmount == 1.0f && view.getVisibility() != View.GONE) { view.setVisibility(View.INVISIBLE); } else if (view.getVisibility() == View.INVISIBLE) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 191302547458..5131772e34a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1007,8 +1007,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // The light reveal scrim should always be fully revealed by the time the keyguard // is done going away. Double check that this is true. if (!mKeyguardStateController.isKeyguardGoingAway()) { - updateIsKeyguard(); - if (mLightRevealScrim.getRevealAmount() != 1f) { Log.e(TAG, "Keyguard is done going away, but someone left the light reveal " + "scrim at reveal amount: " + mLightRevealScrim.getRevealAmount()); @@ -2895,10 +2893,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { showKeyguardImpl(); } } else { - final boolean isLaunchingOrGoingAway = - mNotificationPanelViewController.isLaunchAnimationRunning() - || mKeyguardStateController.isKeyguardGoingAway(); - // During folding a foldable device this might be called as a result of // 'onScreenTurnedOff' call for the inner display. // In this case: @@ -2910,14 +2904,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { if (!mScreenOffAnimationController.isKeyguardHideDelayed() // If we're animating occluded, there's an activity launching over the keyguard // UI. Wait to hide it until after the animation concludes. - && !mKeyguardViewMediator.isOccludeAnimationPlaying() - // If we're occluded, but playing an animation (launch or going away animations) - // the keyguard is visible behind the animation. - && !(mKeyguardStateController.isOccluded() && isLaunchingOrGoingAway)) { - // If we're going away and occluded, it means we are launching over the - // unsecured keyguard, which will subsequently go away. Wait to hide it until - // after the animation concludes to avoid the lockscreen UI changing into the - // shade UI behind the launch animation. + && !mKeyguardViewMediator.isOccludeAnimationPlaying()) { return hideKeyguardImpl(forceStateChange); } } 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 2dc15d09afe2..71e2e405d071 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -1452,11 +1452,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public boolean onTouch(MotionEvent event) { boolean handledTouch = false; if (mAlternateBouncerInteractor.isVisibleState()) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { + final boolean downThenUp = event.getActionMasked() == MotionEvent.ACTION_UP + && mAlternateBouncerReceivedDownTouch; + final boolean outsideTouch = event.getActionMasked() == MotionEvent.ACTION_OUTSIDE; + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { mAlternateBouncerReceivedDownTouch = true; - } else if (event.getAction() == MotionEvent.ACTION_UP - && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime() - && mAlternateBouncerReceivedDownTouch) { + } else if ((downThenUp || outsideTouch) + && mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()) { showPrimaryBouncer(true); } handledTouch = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt index f866d65e2d2d..d0c6215a55d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt @@ -105,10 +105,14 @@ class MobileConnectionRepositoryImpl( * The reason we need to do this is because TelephonyManager limits the number of registered * listeners per-process, so we don't want to create a new listener for every callback. * - * A note on the design for back pressure here: We use the [coalesce] operator here to change - * the backpressure strategy to store exactly the last callback event of _each type_ here, as - * opposed to the default strategy which is to drop the oldest event (regardless of type). This - * means that we should never miss any single event as long as the flow has been started. + * A note on the design for back pressure here: We don't control _which_ telephony callback + * comes in first, since we register every relevant bit of information as a batch. E.g., if a + * downstream starts collecting on a field which is backed by + * [TelephonyCallback.ServiceStateListener], it's not possible for us to guarantee that _that_ + * callback comes in -- the first callback could very well be + * [TelephonyCallback.DataActivityListener], which would promptly be dropped if we didn't keep + * it tracked. We use the [scan] operator here to track the most recent callback of _each type_ + * here. See [TelephonyCallbackState] to see how the callbacks are stored. */ private val callbackEvents: StateFlow<TelephonyCallbackState> = run { val initial = TelephonyCallbackState() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 2ee52325ca4a..654ba04eba7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -57,6 +57,8 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.concurrent.GuardedBy; + /** * Default implementation of a {@link BatteryController}. This controller monitors for battery * level change events that are broadcasted by the system. @@ -94,7 +96,10 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC private boolean mTestMode = false; @VisibleForTesting boolean mHasReceivedBattery = false; + @GuardedBy("mEstimateLock") private Estimate mEstimate; + private final Object mEstimateLock = new Object(); + private boolean mFetchingEstimate = false; // Use AtomicReference because we may request it from a different thread @@ -321,7 +326,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @Nullable private String generateTimeRemainingString() { - synchronized (mFetchCallbacks) { + synchronized (mEstimateLock) { if (mEstimate == null) { return null; } @@ -340,7 +345,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC mFetchingEstimate = true; mBgHandler.post(() -> { // Only fetch the estimate if they are enabled - synchronized (mFetchCallbacks) { + synchronized (mEstimateLock) { mEstimate = null; if (mEstimates.isHybridNotificationEnabled()) { updateEstimate(); @@ -363,6 +368,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } @WorkerThread + @GuardedBy("mEstimateLock") private void updateEstimate() { Assert.isNotMainThread(); // if the estimate has been cached we can just use that, otherwise get a new one and diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index d4e06bc2a5c8..690f63c456c7 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -108,6 +108,11 @@ android:excludeFromRecents="true" /> + <activity android:name="com.android.systemui.controls.ui.TestableControlsActivity" + android:exported="false" + android:excludeFromRecents="true" + /> + <activity android:name="com.android.systemui.screenshot.ScrollViewActivity" android:exported="false" /> 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 6e423593b379..a245c01d74de 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -17,14 +17,14 @@ package com.android.systemui.biometrics import android.graphics.Point -import android.hardware.biometrics.BiometricSourceType.FACE -import android.hardware.biometrics.BiometricSourceType.FINGERPRINT +import android.hardware.biometrics.BiometricSourceType import android.hardware.fingerprint.FingerprintSensorPropertiesInternal 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.keyguard.logging.KeyguardLogger import com.android.systemui.SysuiTestCase import com.android.systemui.dump.logcatLogBuffer @@ -36,11 +36,11 @@ import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.CentralSurfaces +import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.leak.RotationUtils import com.android.systemui.util.mockito.any -import javax.inject.Provider import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue @@ -50,15 +50,15 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.eq -import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.`when` import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.MockitoSession import org.mockito.quality.Strictness +import javax.inject.Provider @SmallTest @RunWith(AndroidTestingRunner::class) @@ -75,6 +75,7 @@ class AuthRippleControllerTest : SysuiTestCase() { @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController + @Mock private lateinit var bypassController: KeyguardBypassController @Mock private lateinit var biometricUnlockController: BiometricUnlockController @Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController> @Mock private lateinit var udfpsController: UdfpsController @@ -83,15 +84,10 @@ class AuthRippleControllerTest : SysuiTestCase() { @Mock private lateinit var lightRevealScrim: LightRevealScrim @Mock private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal - @Captor - private lateinit var biometricModeListener: - ArgumentCaptor<BiometricUnlockController.BiometricModeListener> - @Before fun setUp() { MockitoAnnotations.initMocks(this) - staticMockSession = - mockitoSession() + staticMockSession = mockitoSession() .mockStatic(RotationUtils::class.java) .strictness(Strictness.LENIENT) .startMocking() @@ -100,24 +96,24 @@ class AuthRippleControllerTest : SysuiTestCase() { `when`(authController.udfpsProps).thenReturn(listOf(fpSensorProp)) `when`(udfpsControllerProvider.get()).thenReturn(udfpsController) - controller = - AuthRippleController( - mCentralSurfaces, - context, - authController, - configurationController, - keyguardUpdateMonitor, - keyguardStateController, - wakefulnessLifecycle, - commandRegistry, - notificationShadeWindowController, - biometricUnlockController, - udfpsControllerProvider, - statusBarStateController, - featureFlags, - KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)), - rippleView - ) + controller = AuthRippleController( + mCentralSurfaces, + context, + authController, + configurationController, + keyguardUpdateMonitor, + keyguardStateController, + wakefulnessLifecycle, + commandRegistry, + notificationShadeWindowController, + bypassController, + biometricUnlockController, + udfpsControllerProvider, + statusBarStateController, + featureFlags, + KeyguardLogger(logcatLogBuffer(AuthRippleController.TAG)), + rippleView + ) controller.init() `when`(mCentralSurfaces.lightRevealScrim).thenReturn(lightRevealScrim) } @@ -134,14 +130,16 @@ class AuthRippleControllerTest : SysuiTestCase() { `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardStateController.isShowing).thenReturn(true) - `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FINGERPRINT))) - .thenReturn(true) - `when`(biometricUnlockController.isBiometricUnlock).thenReturn(true) - `when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT) + `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + eq(BiometricSourceType.FINGERPRINT))).thenReturn(true) - // WHEN unlocked with fingerprint - verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture()) - biometricModeListener.value.onModeChanged(/* mode= */ 0) + // WHEN fingerprint authenticated + val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + verify(keyguardUpdateMonitor).registerCallback(captor.capture()) + captor.value.onBiometricAuthenticated( + 0 /* userId */, + BiometricSourceType.FINGERPRINT /* type */, + false /* isStrongBiometric */) // THEN update sensor location and show ripple verify(rippleView).setFingerprintSensorLocation(fpsLocation, 0f) @@ -154,15 +152,17 @@ class AuthRippleControllerTest : SysuiTestCase() { val fpsLocation = Point(5, 5) `when`(authController.udfpsLocation).thenReturn(fpsLocation) controller.onViewAttached() - `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FINGERPRINT))) - .thenReturn(true) - `when`(biometricUnlockController.isBiometricUnlock).thenReturn(true) - `when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT) + `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + eq(BiometricSourceType.FINGERPRINT))).thenReturn(true) // WHEN keyguard is NOT showing & fingerprint authenticated `when`(keyguardStateController.isShowing).thenReturn(false) - verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture()) - biometricModeListener.value.onModeChanged(/* mode= */ 0) + val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + verify(keyguardUpdateMonitor).registerCallback(captor.capture()) + captor.value.onBiometricAuthenticated( + 0 /* userId */, + BiometricSourceType.FINGERPRINT /* type */, + false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any()) @@ -175,14 +175,61 @@ class AuthRippleControllerTest : SysuiTestCase() { `when`(authController.udfpsLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardStateController.isShowing).thenReturn(true) - `when`(biometricUnlockController.isBiometricUnlock).thenReturn(true) - `when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT) // WHEN unlocking with fingerprint is NOT allowed & fingerprint authenticated - `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FINGERPRINT))) - .thenReturn(false) - verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture()) - biometricModeListener.value.onModeChanged(/* mode= */ 0) + `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + eq(BiometricSourceType.FINGERPRINT))).thenReturn(false) + val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + verify(keyguardUpdateMonitor).registerCallback(captor.capture()) + captor.value.onBiometricAuthenticated( + 0 /* userId */, + BiometricSourceType.FINGERPRINT /* type */, + false /* isStrongBiometric */) + + // THEN no ripple + verify(rippleView, never()).startUnlockedRipple(any()) + } + + @Test + fun testFaceTriggerBypassEnabled_Ripple() { + // GIVEN face auth sensor exists, keyguard is showing & unlocking with face is allowed + val faceLocation = Point(5, 5) + `when`(authController.faceSensorLocation).thenReturn(faceLocation) + controller.onViewAttached() + + `when`(keyguardStateController.isShowing).thenReturn(true) + `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + BiometricSourceType.FACE)).thenReturn(true) + + // WHEN bypass is enabled & face authenticated + `when`(bypassController.canBypass()).thenReturn(true) + val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + verify(keyguardUpdateMonitor).registerCallback(captor.capture()) + captor.value.onBiometricAuthenticated( + 0 /* userId */, + BiometricSourceType.FACE /* type */, + false /* isStrongBiometric */) + + // THEN show ripple + verify(rippleView).setSensorLocation(faceLocation) + verify(rippleView).startUnlockedRipple(any()) + } + + @Test + fun testFaceTriggerNonBypass_NoRipple() { + // GIVEN face auth sensor exists + val faceLocation = Point(5, 5) + `when`(authController.faceSensorLocation).thenReturn(faceLocation) + controller.onViewAttached() + + // WHEN bypass isn't enabled & face authenticated + `when`(bypassController.canBypass()).thenReturn(false) + val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + verify(keyguardUpdateMonitor).registerCallback(captor.capture()) + captor.value.onBiometricAuthenticated( + 0 /* userId */, + BiometricSourceType.FACE /* type */, + false /* isStrongBiometric */) // THEN no ripple verify(rippleView, never()).startUnlockedRipple(any()) @@ -192,12 +239,14 @@ class AuthRippleControllerTest : SysuiTestCase() { fun testNullFaceSensorLocationDoesNothing() { `when`(authController.faceSensorLocation).thenReturn(null) controller.onViewAttached() - `when`(biometricUnlockController.biometricType).thenReturn(FACE) - `when`(biometricUnlockController.isBiometricUnlock).thenReturn(true) - verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture()) - biometricModeListener.value.onModeChanged(/* mode= */ 0) + val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + verify(keyguardUpdateMonitor).registerCallback(captor.capture()) + captor.value.onBiometricAuthenticated( + 0 /* userId */, + BiometricSourceType.FACE /* type */, + false /* isStrongBiometric */) verify(rippleView, never()).startUnlockedRipple(any()) } @@ -205,21 +254,25 @@ class AuthRippleControllerTest : SysuiTestCase() { fun testNullFingerprintSensorLocationDoesNothing() { `when`(authController.fingerprintSensorLocation).thenReturn(null) controller.onViewAttached() - `when`(biometricUnlockController.biometricType).thenReturn(FINGERPRINT) - `when`(biometricUnlockController.isBiometricUnlock).thenReturn(true) - verify(biometricUnlockController).addBiometricModeListener(biometricModeListener.capture()) - biometricModeListener.value.onModeChanged(/* mode= */ 0) + val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java) + verify(keyguardUpdateMonitor).registerCallback(captor.capture()) + captor.value.onBiometricAuthenticated( + 0 /* userId */, + BiometricSourceType.FINGERPRINT /* type */, + false /* isStrongBiometric */) verify(rippleView, never()).startUnlockedRipple(any()) } @Test fun registersAndDeregisters() { controller.onViewAttached() - val captor = ArgumentCaptor.forClass(KeyguardStateController.Callback::class.java) + val captor = ArgumentCaptor + .forClass(KeyguardStateController.Callback::class.java) verify(keyguardStateController).addCallback(captor.capture()) - val captor2 = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java) + val captor2 = ArgumentCaptor + .forClass(WakefulnessLifecycle.Observer::class.java) verify(wakefulnessLifecycle).addObserver(captor2.capture()) controller.onViewDetached() verify(keyguardStateController).removeCallback(any()) @@ -233,20 +286,17 @@ class AuthRippleControllerTest : SysuiTestCase() { `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation) controller.onViewAttached() `when`(keyguardStateController.isShowing).thenReturn(true) - `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(FINGERPRINT)).thenReturn(true) + `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + BiometricSourceType.FINGERPRINT)).thenReturn(true) `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true) - controller.showUnlockRipple(FINGERPRINT) - assertTrue( - "reveal didn't start on keyguardFadingAway", - controller.startLightRevealScrimOnKeyguardFadingAway - ) + controller.showUnlockRipple(BiometricSourceType.FINGERPRINT) + assertTrue("reveal didn't start on keyguardFadingAway", + controller.startLightRevealScrimOnKeyguardFadingAway) `when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true) controller.onKeyguardFadingAwayChanged() - assertFalse( - "reveal triggers multiple times", - controller.startLightRevealScrimOnKeyguardFadingAway - ) + assertFalse("reveal triggers multiple times", + controller.startLightRevealScrimOnKeyguardFadingAway) } @Test @@ -258,26 +308,23 @@ class AuthRippleControllerTest : SysuiTestCase() { `when`(keyguardStateController.isShowing).thenReturn(true) `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true) `when`(authController.isUdfpsFingerDown).thenReturn(true) - `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(eq(FACE))).thenReturn(true) + `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed( + eq(BiometricSourceType.FACE))).thenReturn(true) - controller.showUnlockRipple(FACE) - assertTrue( - "reveal didn't start on keyguardFadingAway", - controller.startLightRevealScrimOnKeyguardFadingAway - ) + controller.showUnlockRipple(BiometricSourceType.FACE) + assertTrue("reveal didn't start on keyguardFadingAway", + controller.startLightRevealScrimOnKeyguardFadingAway) `when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true) controller.onKeyguardFadingAwayChanged() - assertFalse( - "reveal triggers multiple times", - controller.startLightRevealScrimOnKeyguardFadingAway - ) + assertFalse("reveal triggers multiple times", + controller.startLightRevealScrimOnKeyguardFadingAway) } @Test fun testUpdateRippleColor() { controller.onViewAttached() - val captor = - ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java) + val captor = ArgumentCaptor + .forClass(ConfigurationController.ConfigurationListener::class.java) verify(configurationController).addCallback(captor.capture()) reset(rippleView) diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt new file mode 100644 index 000000000000..0f62b24bdb06 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 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.controls.ui + +import android.content.Intent +import android.content.res.Configuration +import android.service.dreams.IDreamManager +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import androidx.test.rule.ActivityTestRule +import androidx.test.runner.intercepting.SingleActivityFactory +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.settings.ControlsSettingsDialogManager +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.statusbar.policy.KeyguardStateController +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class ControlsActivityTest : SysuiTestCase() { + @Mock private lateinit var uiController: ControlsUiController + @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock private lateinit var dreamManager: IDreamManager + @Mock private lateinit var featureFlags: FeatureFlags + @Mock private lateinit var controlsSettingsDialogManager: ControlsSettingsDialogManager + @Mock private lateinit var keyguardStateController: KeyguardStateController + + @Rule + @JvmField + var activityRule = + ActivityTestRule( + object : + SingleActivityFactory<TestableControlsActivity>( + TestableControlsActivity::class.java + ) { + override fun create(intent: Intent?): TestableControlsActivity { + return TestableControlsActivity( + uiController, + broadcastDispatcher, + dreamManager, + featureFlags, + controlsSettingsDialogManager, + keyguardStateController, + ) + } + }, + false, + false + ) + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + activityRule.launchActivity(Intent()) + } + + @Test + fun testOrientationChangeForwardsToUiController() { + val currentConfig = activityRule.activity.resources.configuration + val newConfig = Configuration(currentConfig) + newConfig.orientation = switchOrientation(currentConfig.orientation) + activityRule.runOnUiThread { activityRule.activity.onConfigurationChanged(newConfig) } + + verify(uiController).onSizeChange() + } + + @Test + fun testScreenChangeForwardsToUiController() { + val currentConfig = activityRule.activity.resources.configuration + val newConfig = Configuration(currentConfig) + swapHeightWidth(newConfig) + activityRule.runOnUiThread { activityRule.activity.onConfigurationChanged(newConfig) } + + verify(uiController).onSizeChange() + } + + @Test + fun testChangeSmallestScreenSizeForwardsToUiController() { + val currentConfig = activityRule.activity.resources.configuration + val newConfig = Configuration(currentConfig) + newConfig.smallestScreenWidthDp *= 2 + newConfig.screenWidthDp *= 2 + activityRule.runOnUiThread { activityRule.activity.onConfigurationChanged(newConfig) } + + verify(uiController).onSizeChange() + } + + private fun switchOrientation(orientation: Int): Int { + return if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + Configuration.ORIENTATION_PORTRAIT + } else { + Configuration.ORIENTATION_LANDSCAPE + } + } + + private fun swapHeightWidth(configuration: Configuration) { + val oldHeight = configuration.screenHeightDp + val oldWidth = configuration.screenWidthDp + configuration.screenHeightDp = oldWidth + configuration.screenWidthDp = oldHeight + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt index 6ca4dcccfca0..91f279c1bf73 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt @@ -450,7 +450,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() { taskViewConsumerCaptor.value.accept(taskView) - underTest.onOrientationChange() + underTest.onSizeChange() verify(taskView).onLocationChanged() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TestableControlsActivity.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TestableControlsActivity.kt new file mode 100644 index 000000000000..f0b473210630 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/TestableControlsActivity.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 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.controls.ui + +import android.service.dreams.IDreamManager +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.settings.ControlsSettingsDialogManager +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.statusbar.policy.KeyguardStateController + +class TestableControlsActivity( + uiController: ControlsUiController, + broadcastDispatcher: BroadcastDispatcher, + dreamManager: IDreamManager, + featureFlags: FeatureFlags, + controlsSettingsDialogManager: ControlsSettingsDialogManager, + keyguardStateController: KeyguardStateController +) : + ControlsActivity( + uiController, + broadcastDispatcher, + dreamManager, + featureFlags, + controlsSettingsDialogManager, + keyguardStateController + ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index a636b7f43648..b87647ef9839 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -408,6 +408,17 @@ public class DozeMachineTest extends SysuiTestCase { } @Test + public void testPulsing_dozeSuspendTriggers_pulseDone_doesntCrash() { + mMachine.requestState(INITIALIZED); + + mMachine.requestState(DOZE); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestState(DOZE_PULSING); + mMachine.requestState(DOZE_SUSPEND_TRIGGERS); + mMachine.requestState(DOZE_PULSE_DONE); + } + + @Test public void testSuppressingPulse_doesntCrash() { mMachine.requestState(INITIALIZED); diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt index 2db4596c80a7..e287f19b2455 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/RestartDozeListenerTest.kt @@ -21,12 +21,15 @@ import android.test.suitebuilder.annotation.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.eq import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString import org.mockito.Mock import org.mockito.Mockito.anyLong import org.mockito.Mockito.never @@ -58,36 +61,37 @@ class RestartDozeListenerTest : SysuiTestCase() { } @Test - fun testStoreDreamState_onDreamingStarted() { - listener.onDreamingChanged(true) + fun testStoreDreamState_onDozingStarted() { + listener.onDozingChanged(true) executor.runAllReady() - assertThat(settings.getBool(RestartDozeListener.RESTART_NAP_KEY)).isTrue() + assertThat(settings.getBool(RestartDozeListener.RESTART_SLEEP_KEY)).isTrue() } @Test - fun testStoreDreamState_onDreamingStopped() { - listener.onDreamingChanged(false) + fun testStoreDozeState_onDozingStopped() { + listener.onDozingChanged(false) executor.runAllReady() - assertThat(settings.getBool(RestartDozeListener.RESTART_NAP_KEY)).isFalse() + assertThat(settings.getBool(RestartDozeListener.RESTART_SLEEP_KEY)).isFalse() } @Test - fun testRestoreDreamState_dreamingShouldStart() { - settings.putBool(RestartDozeListener.RESTART_NAP_KEY, true) + fun testRestoreDozeState_dozingShouldStart() { + settings.putBool(RestartDozeListener.RESTART_SLEEP_KEY, true) restartDozeListener.maybeRestartSleep() executor.advanceClockToLast() executor.runAllReady() - verify(powerManager).wakeUp(clock.uptimeMillis()) + verify(powerManager) + .wakeUp(eq(clock.uptimeMillis()), eq(PowerManager.WAKE_REASON_APPLICATION), anyString()) verify(powerManager).goToSleep(clock.uptimeMillis()) } @Test - fun testRestoreDreamState_dreamingShouldNot() { - settings.putBool(RestartDozeListener.RESTART_NAP_KEY, false) + fun testRestoreDozeState_dozingShouldNotStart() { + settings.putBool(RestartDozeListener.RESTART_SLEEP_KEY, false) restartDozeListener.maybeRestartSleep() executor.advanceClockToLast() executor.runAllReady() - verify(powerManager, never()).wakeUp(anyLong()) + verify(powerManager, never()).wakeUp(anyLong(), anyInt(), anyString()) verify(powerManager, never()).goToSleep(anyLong()) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt index 5ec6283f3de0..bdc33f45c717 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt @@ -39,6 +39,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever import com.android.systemui.utils.os.FakeHandler import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -50,7 +51,6 @@ import org.mockito.Mock import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @@ -90,9 +90,9 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { keyguardUpdateMonitor, keyguardBypassController, ) - `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) - `when`(repository.primaryBouncerShow.value).thenReturn(false) - `when`(bouncerView.delegate).thenReturn(bouncerViewDelegate) + whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + whenever(repository.primaryBouncerShow.value).thenReturn(false) + whenever(bouncerView.delegate).thenReturn(bouncerViewDelegate) resources = context.orCreateTestableResources } @@ -118,7 +118,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @Test fun testShow_keyguardIsDone() { - `when`(bouncerView.delegate?.showNextSecurityScreenOrFinish()).thenReturn(true) + whenever(bouncerView.delegate?.showNextSecurityScreenOrFinish()).thenReturn(true) verify(keyguardStateController, never()).notifyPrimaryBouncerShowing(true) verify(mPrimaryBouncerCallbackInteractor, never()).dispatchStartingToShow() } @@ -135,7 +135,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @Test fun testExpansion() { - `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) + whenever(repository.panelExpansionAmount.value).thenReturn(0.5f) underTest.setPanelExpansion(0.6f) verify(repository).setPanelExpansion(0.6f) verify(mPrimaryBouncerCallbackInteractor).dispatchExpansionChanged(0.6f) @@ -143,8 +143,8 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @Test fun testExpansion_fullyShown() { - `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) - `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + whenever(repository.panelExpansionAmount.value).thenReturn(0.5f) + whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) underTest.setPanelExpansion(EXPANSION_VISIBLE) verify(falsingCollector).onBouncerShown() verify(mPrimaryBouncerCallbackInteractor).dispatchFullyShown() @@ -152,8 +152,8 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @Test fun testExpansion_fullyHidden() { - `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) - `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + whenever(repository.panelExpansionAmount.value).thenReturn(0.5f) + whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) underTest.setPanelExpansion(EXPANSION_HIDDEN) verify(repository).setPrimaryShow(false) verify(falsingCollector).onBouncerHidden() @@ -163,7 +163,7 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @Test fun testExpansion_startingToHide() { - `when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE) + whenever(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE) underTest.setPanelExpansion(0.1f) verify(repository).setPrimaryStartingToHide(true) verify(mPrimaryBouncerCallbackInteractor).dispatchStartingToHide() @@ -228,7 +228,21 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { } @Test - fun testStartDisappearAnimation() { + fun testStartDisappearAnimation_willRunDismissFromKeyguard() { + whenever(bouncerViewDelegate.willRunDismissFromKeyguard()).thenReturn(true) + + val runnable = mock(Runnable::class.java) + underTest.startDisappearAnimation(runnable) + // End runnable should run immediately + verify(runnable).run() + // ... while the disappear animation should never be run + verify(repository, never()).setPrimaryStartDisappearAnimation(any(Runnable::class.java)) + } + + @Test + fun testStartDisappearAnimation_willNotRunDismissFromKeyguard_() { + whenever(bouncerViewDelegate.willRunDismissFromKeyguard()).thenReturn(false) + val runnable = mock(Runnable::class.java) underTest.startDisappearAnimation(runnable) verify(repository).setPrimaryStartDisappearAnimation(any(Runnable::class.java)) @@ -236,45 +250,45 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { @Test fun testIsFullShowing() { - `when`(repository.primaryBouncerShow.value).thenReturn(true) - `when`(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE) - `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + whenever(repository.primaryBouncerShow.value).thenReturn(true) + whenever(repository.panelExpansionAmount.value).thenReturn(EXPANSION_VISIBLE) + whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) assertThat(underTest.isFullyShowing()).isTrue() - `when`(repository.primaryBouncerShow.value).thenReturn(false) + whenever(repository.primaryBouncerShow.value).thenReturn(false) assertThat(underTest.isFullyShowing()).isFalse() } @Test fun testIsScrimmed() { - `when`(repository.primaryBouncerScrimmed.value).thenReturn(true) + whenever(repository.primaryBouncerScrimmed.value).thenReturn(true) assertThat(underTest.isScrimmed()).isTrue() - `when`(repository.primaryBouncerScrimmed.value).thenReturn(false) + whenever(repository.primaryBouncerScrimmed.value).thenReturn(false) assertThat(underTest.isScrimmed()).isFalse() } @Test fun testIsInTransit() { - `when`(repository.primaryBouncerShowingSoon.value).thenReturn(true) + whenever(repository.primaryBouncerShowingSoon.value).thenReturn(true) assertThat(underTest.isInTransit()).isTrue() - `when`(repository.primaryBouncerShowingSoon.value).thenReturn(false) + whenever(repository.primaryBouncerShowingSoon.value).thenReturn(false) assertThat(underTest.isInTransit()).isFalse() - `when`(repository.panelExpansionAmount.value).thenReturn(0.5f) + whenever(repository.panelExpansionAmount.value).thenReturn(0.5f) assertThat(underTest.isInTransit()).isTrue() } @Test fun testIsAnimatingAway() { - `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(Runnable {}) + whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(Runnable {}) assertThat(underTest.isAnimatingAway()).isTrue() - `when`(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) + whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null) assertThat(underTest.isAnimatingAway()).isFalse() } @Test fun testWillDismissWithAction() { - `when`(bouncerViewDelegate.willDismissWithActions()).thenReturn(true) + whenever(bouncerViewDelegate.willDismissWithActions()).thenReturn(true) assertThat(underTest.willDismissWithAction()).isTrue() - `when`(bouncerViewDelegate.willDismissWithActions()).thenReturn(false) + whenever(bouncerViewDelegate.willDismissWithActions()).thenReturn(false) assertThat(underTest.willDismissWithAction()).isFalse() } @@ -363,12 +377,13 @@ class PrimaryBouncerInteractorTest : SysuiTestCase() { isUnlockingWithFpAllowed: Boolean, isAnimatingAway: Boolean ) { - `when`(repository.primaryBouncerShow.value).thenReturn(isVisible) + whenever(repository.primaryBouncerShow.value).thenReturn(isVisible) resources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, sfpsEnabled) - `when`(keyguardUpdateMonitor.isFingerprintDetectionRunning).thenReturn(fpsDetectionRunning) - `when`(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) + whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning) + .thenReturn(fpsDetectionRunning) + whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed) .thenReturn(isUnlockingWithFpAllowed) - `when`(repository.primaryBouncerStartingDisappearAnimation.value) + whenever(repository.primaryBouncerStartingDisappearAnimation.value) .thenReturn(if (isAnimatingAway) Runnable {} else null) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt index 746f66881a88..98794fd4de0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -115,7 +115,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { repository.sendTransitionStep(step(1f)) assertThat(values.size).isEqualTo(4) - values.forEach { assertThat(it).isEqualTo(ScrimAlpha(notificationsAlpha = 1f)) } + values.forEach { assertThat(it).isEqualTo(ScrimAlpha()) } job.cancel() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt index e0ca90ec2c58..a72634bcb807 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt @@ -17,7 +17,7 @@ package com.android.systemui.media.controls.ui import android.app.PendingIntent -import android.content.res.ColorStateList +import android.content.res.Configuration import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.util.MathUtils.abs @@ -26,9 +26,9 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback -import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -49,7 +49,7 @@ import com.android.systemui.qs.PageIndicator import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider import com.android.systemui.statusbar.policy.ConfigurationController -import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock @@ -89,6 +89,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Mock lateinit var mediaHostStatesManager: MediaHostStatesManager @Mock lateinit var mediaHostState: MediaHostState @Mock lateinit var activityStarter: ActivityStarter + @Mock @Main private lateinit var executor: DelayableExecutor @Mock lateinit var mediaDataManager: MediaDataManager @Mock lateinit var configurationController: ConfigurationController @Mock lateinit var falsingCollector: FalsingCollector @@ -112,15 +113,11 @@ class MediaCarouselControllerTest : SysuiTestCase() { private val clock = FakeSystemClock() private lateinit var mediaCarouselController: MediaCarouselController - private lateinit var mainExecutor: FakeExecutor - private lateinit var backgroundExecutor: FakeExecutor @Before fun setup() { MockitoAnnotations.initMocks(this) transitionRepository = FakeKeyguardTransitionRepository() - mainExecutor = FakeExecutor(clock) - backgroundExecutor = FakeExecutor(clock) mediaCarouselController = MediaCarouselController( context, @@ -129,8 +126,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { mediaHostStatesManager, activityStarter, clock, - mainExecutor, - backgroundExecutor, + executor, mediaDataManager, configurationController, falsingCollector, @@ -405,7 +401,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { resumption = true ) ) - runAllReady() assertEquals( MediaPlayerData.getMediaPlayerIndex("paused local"), @@ -515,8 +510,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { false ) mediaCarouselController.shouldScrollToKey = true - runAllReady() - // switching between media players. listener.value.onMediaDataLoaded( "playing local", @@ -538,7 +531,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { resumption = false ) ) - runAllReady() assertEquals( MediaPlayerData.getMediaPlayerIndex("paused local"), @@ -563,7 +555,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { resumption = false ) ) - runAllReady() var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local") assertEquals( @@ -586,8 +577,6 @@ class MediaCarouselControllerTest : SysuiTestCase() { packageName = "PACKAGE_NAME" ) ) - runAllReady() - playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local") assertEquals(playerIndex, 0) } @@ -684,38 +673,17 @@ class MediaCarouselControllerTest : SysuiTestCase() { } @Test - fun testOnUiModeChanged_playersAreAddedBack() { - mediaCarouselController.pageIndicator = pageIndicator - + fun testOnConfigChanged_playersAreAddedBack() { listener.value.onMediaDataLoaded( - "paused local", + "playing local", null, DATA.copy( active = true, - isPlaying = false, + isPlaying = true, playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false ) ) - runAllReady() - - val playersSize = MediaPlayerData.players().size - configListener.value.onUiModeChanged() - runAllReady() - - verify(pageIndicator).tintList = - ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) - assertEquals(playersSize, MediaPlayerData.players().size) - assertEquals( - MediaPlayerData.getMediaPlayerIndex("paused local"), - mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex - ) - } - - @Test - fun testOnDensityOrFontScaleChanged_playersAreAddedBack() { - mediaCarouselController.pageIndicator = pageIndicator - listener.value.onMediaDataLoaded( "paused local", null, @@ -726,46 +694,14 @@ class MediaCarouselControllerTest : SysuiTestCase() { resumption = false ) ) - runAllReady() val playersSize = MediaPlayerData.players().size - configListener.value.onDensityOrFontScaleChanged() - runAllReady() - - verify(pageIndicator).tintList = - ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) - assertEquals(playersSize, MediaPlayerData.players().size) - assertEquals( - MediaPlayerData.getMediaPlayerIndex("paused local"), - mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex - ) - } - @Test - fun testOnThemeChanged_playersAreAddedBack() { - mediaCarouselController.pageIndicator = pageIndicator + configListener.value.onConfigChanged(Configuration()) - listener.value.onMediaDataLoaded( - "paused local", - null, - DATA.copy( - active = true, - isPlaying = false, - playbackLocation = MediaData.PLAYBACK_LOCAL, - resumption = false - ) - ) - runAllReady() - - val playersSize = MediaPlayerData.players().size - configListener.value.onThemeChanged() - runAllReady() - - verify(pageIndicator).tintList = - ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator)) assertEquals(playersSize, MediaPlayerData.players().size) assertEquals( - MediaPlayerData.getMediaPlayerIndex("paused local"), + MediaPlayerData.getMediaPlayerIndex("playing local"), mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex ) } @@ -896,9 +832,4 @@ class MediaCarouselControllerTest : SysuiTestCase() { // Verify that seekbar listening attribute in media control panel is set to false. verify(panel, times(MediaPlayerData.players().size)).listening = false } - - private fun runAllReady() { - backgroundExecutor.runAllReady() - mainExecutor.runAllReady() - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt index df13fddc5a28..eba059137511 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt @@ -2350,6 +2350,48 @@ public class MediaControlPanelTest : SysuiTestCase() { } } + @Test + fun outputSwitcher_hasCustomIntent_openOverLockscreen() { + // When the device for a media player has an intent that opens over lockscreen + val pendingIntent = mock(PendingIntent::class.java) + whenever(pendingIntent.isActivity).thenReturn(true) + whenever(keyguardStateController.isShowing).thenReturn(true) + whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())).thenReturn(true) + + val customDevice = device.copy(intent = pendingIntent) + val dataWithDevice = mediaData.copy(device = customDevice) + player.attachPlayer(viewHolder) + player.bindPlayer(dataWithDevice, KEY) + + // When the user taps on the output switcher, + seamless.callOnClick() + + // Then we send the pending intent as is, without modifying the original intent + verify(pendingIntent).send() + verify(pendingIntent, never()).getIntent() + } + + @Test + fun outputSwitcher_hasCustomIntent_requiresUnlock() { + // When the device for a media player has an intent that cannot open over lockscreen + val pendingIntent = mock(PendingIntent::class.java) + whenever(pendingIntent.isActivity).thenReturn(true) + whenever(keyguardStateController.isShowing).thenReturn(true) + whenever(activityIntentHelper.wouldPendingShowOverLockscreen(any(), any())) + .thenReturn(false) + + val customDevice = device.copy(intent = pendingIntent) + val dataWithDevice = mediaData.copy(device = customDevice) + player.attachPlayer(viewHolder) + player.bindPlayer(dataWithDevice, KEY) + + // When the user taps on the output switcher, + seamless.callOnClick() + + // Then we request keyguard dismissal + verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent)) + } + private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener = withArgCaptor { verify(seekBarViewModel).setScrubbingChangeListener(capture()) diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt index 464acb68fb07..01ffdcd580c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt @@ -19,12 +19,14 @@ package com.android.systemui.mediaprojection.appselector.view import android.content.Context import android.content.res.Configuration import android.content.res.Resources +import android.graphics.Insets import android.graphics.Rect import android.util.DisplayMetrics.DENSITY_DEFAULT +import android.view.WindowInsets import android.view.WindowManager import android.view.WindowMetrics +import androidx.core.view.WindowInsetsCompat.Type import androidx.test.filters.SmallTest -import com.android.internal.R import com.android.systemui.SysuiTestCase import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener import com.android.systemui.statusbar.policy.FakeConfigurationController @@ -94,7 +96,13 @@ class TaskPreviewSizeProviderTest : SysuiTestCase() { } private fun givenTaskbarSize(size: Int) { - whenever(resources.getDimensionPixelSize(eq(R.dimen.taskbar_frame_height))).thenReturn(size) + val windowInsets = + WindowInsets.Builder() + .setInsets(Type.tappableElement(), Insets.of(Rect(0, 0, 0, size))) + .build() + val windowMetrics = WindowMetrics(windowManager.maximumWindowMetrics.bounds, windowInsets) + whenever(windowManager.maximumWindowMetrics).thenReturn(windowMetrics) + whenever(windowManager.currentWindowMetrics).thenReturn(windowMetrics) } private fun givenDisplay(width: Int, height: Int, isTablet: Boolean = false) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 99cf8d0ebe93..7087c0135998 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -24,7 +24,9 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doAnswer; @@ -184,6 +186,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected NotificationStackScrollLayout mNotificationStackScrollLayout; @Mock protected KeyguardBottomAreaView mKeyguardBottomArea; @Mock protected KeyguardBottomAreaViewController mKeyguardBottomAreaViewController; + @Mock protected ViewPropertyAnimator mViewPropertyAnimator; @Mock protected KeyguardBottomAreaView mQsFrame; @Mock protected HeadsUpManagerPhone mHeadsUpManager; @Mock protected NotificationShelfController mNotificationShelfController; @@ -357,7 +360,14 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { .thenReturn(mHeadsUpCallback); when(mKeyguardBottomAreaViewController.getView()).thenReturn(mKeyguardBottomArea); when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); - when(mKeyguardBottomArea.animate()).thenReturn(mock(ViewPropertyAnimator.class)); + when(mKeyguardBottomArea.animate()).thenReturn(mViewPropertyAnimator); + when(mView.animate()).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.translationX(anyFloat())).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.setInterpolator(any())).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.setListener(any())).thenReturn(mViewPropertyAnimator); + when(mViewPropertyAnimator.setUpdateListener(any())).thenReturn(mViewPropertyAnimator); when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame); when(mView.findViewById(R.id.keyguard_status_view)) .thenReturn(mock(KeyguardStatusView.class)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index 4517596e8b02..b868018b7dda 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -42,6 +42,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.animation.Animator; +import android.animation.ValueAnimator; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.MotionEvent; @@ -674,6 +676,24 @@ public class NotificationPanelViewControllerTest extends NotificationPanelViewCo } @Test + public void testFoldToAodAnimationCleansupInAnimationEnd() { + ArgumentCaptor<Animator.AnimatorListener> animCaptor = + ArgumentCaptor.forClass(Animator.AnimatorListener.class); + ArgumentCaptor<ValueAnimator.AnimatorUpdateListener> updateCaptor = + ArgumentCaptor.forClass(ValueAnimator.AnimatorUpdateListener.class); + + // Start fold animation & Capture Listeners + mNotificationPanelViewController.startFoldToAodAnimation(() -> {}, () -> {}, () -> {}); + verify(mViewPropertyAnimator).setListener(animCaptor.capture()); + verify(mViewPropertyAnimator).setUpdateListener(updateCaptor.capture()); + + // End animation and validate listeners were unset + animCaptor.getValue().onAnimationEnd(null); + verify(mViewPropertyAnimator).setListener(null); + verify(mViewPropertyAnimator).setUpdateListener(null); + } + + @Test public void testExpandWithQsMethodIsUsingLockscreenTransitionController() { enableSplitShade(/* enabled= */ true); mStatusBarStateController.setState(KEYGUARD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index dd7929771bb2..526dc8d150fe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -223,16 +223,6 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { } @Test - public void attach_fadingAway_wallpaperVisible() { - clearInvocations(mWindowManager); - mNotificationShadeWindowController.attach(); - mNotificationShadeWindowController.setKeyguardFadingAway(true); - - verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture()); - assertThat((mLayoutParameters.getValue().flags & FLAG_SHOW_WALLPAPER) != 0).isTrue(); - } - - @Test public void setBackgroundBlurRadius_expandedWithBlurs() { mNotificationShadeWindowController.setBackgroundBlurRadius(10); verify(mNotificationShadeWindowView).setVisibility(eq(View.VISIBLE)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index bf05d4e43224..33a813f5b0ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -1287,18 +1287,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { } @Test - public void keyguard_notHidden_ifGoingAwayAndOccluded() { - setKeyguardShowingAndOccluded(true /* showing */, false /* occluded */); - - when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true); - when(mKeyguardStateController.isOccluded()).thenReturn(true); - - mCentralSurfaces.updateIsKeyguard(false); - - verify(mStatusBarStateController, never()).setState(eq(SHADE), anyBoolean()); - } - - @Test public void frpLockedDevice_shadeDisabled() { when(mDeviceProvisionedController.isFrpActive()).thenReturn(true); when(mDozeServiceHost.isPulsing()).thenReturn(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 61286a43217c..346b90c1bd88 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 @@ -786,4 +786,20 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { // THEN the alternateBouncer doesn't hide verify(mAlternateBouncerInteractor, never()).hide(); } + + @Test + public void testAlternateBouncerOnTouch_actionOutside_hidesAlternateBouncer() { + reset(mAlternateBouncerInteractor); + + // GIVEN the alternate bouncer has shown for a minimum amount of time + when(mAlternateBouncerInteractor.hasAlternateBouncerShownWithMinTime()).thenReturn(true); + when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true); + + // WHEN only ACTION_OUTSIDE touch event comes + mStatusBarKeyguardViewManager.onTouch( + MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_OUTSIDE, 0f, 0f, 0)); + + // THEN the alternateBouncer hides + verify(mAlternateBouncerInteractor).hide(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index 542b688b162d..934e1c64c6da 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -25,7 +25,6 @@ import android.telephony.ServiceState.STATE_OUT_OF_SERVICE import android.telephony.TelephonyCallback import android.telephony.TelephonyCallback.DataActivityListener import android.telephony.TelephonyCallback.ServiceStateListener -import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE import android.telephony.TelephonyManager @@ -68,6 +67,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameMo import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength +import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel @@ -392,13 +392,17 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this) val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() - val type = NETWORK_TYPE_UNKNOWN - val expected = UnknownNetworkType - val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) } + val ti = + telephonyDisplayInfo( + networkType = NETWORK_TYPE_UNKNOWN, + overrideNetworkType = NETWORK_TYPE_UNKNOWN, + ) + callback.onDisplayInfoChanged(ti) + val expected = UnknownNetworkType assertThat(latest).isEqualTo(expected) - assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(type)) + assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN)) job.cancel() } @@ -412,14 +416,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() val overrideType = OVERRIDE_NETWORK_TYPE_NONE val type = NETWORK_TYPE_LTE - val expected = DefaultNetworkType(mobileMappings.toIconKey(type)) - val ti = - mock<TelephonyDisplayInfo>().also { - whenever(it.overrideNetworkType).thenReturn(overrideType) - whenever(it.networkType).thenReturn(type) - } + val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = overrideType) callback.onDisplayInfoChanged(ti) + val expected = DefaultNetworkType(mobileMappings.toIconKey(type)) assertThat(latest).isEqualTo(expected) job.cancel() @@ -433,14 +433,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() val type = OVERRIDE_NETWORK_TYPE_LTE_CA - val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type)) - val ti = - mock<TelephonyDisplayInfo>().also { - whenever(it.networkType).thenReturn(type) - whenever(it.overrideNetworkType).thenReturn(type) - } + val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = type) callback.onDisplayInfoChanged(ti) + val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type)) assertThat(latest).isEqualTo(expected) job.cancel() @@ -455,14 +451,10 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>() val unknown = NETWORK_TYPE_UNKNOWN val type = OVERRIDE_NETWORK_TYPE_LTE_CA - val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type)) - val ti = - mock<TelephonyDisplayInfo>().also { - whenever(it.networkType).thenReturn(unknown) - whenever(it.overrideNetworkType).thenReturn(type) - } + val ti = telephonyDisplayInfo(unknown, type) callback.onDisplayInfoChanged(ti) + val expected = OverrideNetworkType(mobileMappings.toIconKeyOverride(type)) assertThat(latest).isEqualTo(expected) job.cancel() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt index bbf04ed28fd7..9da9ff72d380 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt @@ -64,10 +64,14 @@ import org.mockito.MockitoAnnotations * * Kind of like an interaction test case build just for [TelephonyCallback] * - * The list of telephony callbacks we use is: [TelephonyCallback.CarrierNetworkListener] - * [TelephonyCallback.DataActivityListener] [TelephonyCallback.DataConnectionStateListener] - * [TelephonyCallback.DataEnabledListener] [TelephonyCallback.DisplayInfoListener] - * [TelephonyCallback.ServiceStateListener] [TelephonyCallback.SignalStrengthsListener] + * The list of telephony callbacks we use is: + * - [TelephonyCallback.CarrierNetworkListener] + * - [TelephonyCallback.DataActivityListener] + * - [TelephonyCallback.DataConnectionStateListener] + * - [TelephonyCallback.DataEnabledListener] + * - [TelephonyCallback.DisplayInfoListener] + * - [TelephonyCallback.ServiceStateListener] + * - [TelephonyCallback.SignalStrengthsListener] * * Because each of these callbacks comes in on the same callbackFlow, collecting on a field backed * by only a single callback can immediately create backpressure on the other fields related to a @@ -201,7 +205,6 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() { 200 /* unused */ ) - // Send a bunch of events that we don't care about, to overrun the replay buffer flipActivity(100, activityCallback) val connectionJob = underTest.dataConnectionState.onEach { latest = it }.launchIn(this) @@ -225,7 +228,6 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() { enabledCallback.onDataEnabledChanged(true, 1 /* unused */) - // Send a bunch of events that we don't care about, to overrun the replay buffer flipActivity(100, activityCallback) val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this) @@ -252,7 +254,6 @@ class MobileConnectionTelephonySmokeTests : SysuiTestCase() { val ti = mock<TelephonyDisplayInfo>().also { whenever(it.networkType).thenReturn(type) } displayInfoCallback.onDisplayInfoChanged(ti) - // Send a bunch of events that we don't care about, to overrun the replay buffer flipActivity(100, activityCallback) val job = underTest.resolvedNetworkType.onEach { latest = it }.launchIn(this) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt index d07b96f6609e..cf815c27a0bf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileTelephonyHelpers.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod import android.telephony.CellSignalStrengthCdma import android.telephony.SignalStrength import android.telephony.TelephonyCallback +import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyManager import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argumentCaptor @@ -48,6 +49,12 @@ object MobileTelephonyHelpers { return signalStrength } + fun telephonyDisplayInfo(networkType: Int, overrideNetworkType: Int) = + mock<TelephonyDisplayInfo>().also { + whenever(it.networkType).thenReturn(networkType) + whenever(it.overrideNetworkType).thenReturn(overrideNetworkType) + } + inline fun <reified T> getTelephonyCallbackForType(mockTelephonyManager: TelephonyManager): T { val cbs = getTelephonyCallbacks(mockTelephonyManager).filterIsInstance<T>() assertThat(cbs.size).isEqualTo(1) diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt index 8476d0d45603..bf54d4297ad8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt @@ -16,6 +16,9 @@ package com.android.systemui.unfold.updates +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources import android.os.Handler import android.testing.AndroidTestingRunner import androidx.core.util.Consumer @@ -33,6 +36,7 @@ import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenLis import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityProvider import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import java.util.concurrent.Executor import org.junit.Before @@ -49,20 +53,19 @@ import org.mockito.MockitoAnnotations @SmallTest class DeviceFoldStateProviderTest : SysuiTestCase() { - @Mock - private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider + @Mock private lateinit var activityTypeProvider: ActivityManagerActivityTypeProvider - @Mock - private lateinit var handler: Handler + @Mock private lateinit var handler: Handler - @Mock - private lateinit var rotationChangeProvider: RotationChangeProvider + @Mock private lateinit var rotationChangeProvider: RotationChangeProvider - @Mock - private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider + @Mock private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider - @Captor - private lateinit var rotationListener: ArgumentCaptor<RotationListener> + @Mock private lateinit var resources: Resources + + @Mock private lateinit var context: Context + + @Captor private lateinit var rotationListener: ArgumentCaptor<RotationListener> private val foldProvider = TestFoldProvider() private val screenOnStatusProvider = TestScreenOnStatusProvider() @@ -81,10 +84,13 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) - val config = object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() { - override val halfFoldedTimeoutMillis: Int - get() = HALF_OPENED_TIMEOUT_MILLIS.toInt() - } + val config = + object : UnfoldTransitionConfig by ResourceUnfoldTransitionConfig() { + override val halfFoldedTimeoutMillis: Int + get() = HALF_OPENED_TIMEOUT_MILLIS.toInt() + } + whenever(context.resources).thenReturn(resources) + whenever(context.mainExecutor).thenReturn(mContext.mainExecutor) foldStateProvider = DeviceFoldStateProvider( @@ -95,6 +101,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { activityTypeProvider, unfoldKeyguardVisibilityProvider, rotationChangeProvider, + context, context.mainExecutor, handler ) @@ -112,7 +119,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { override fun onUnfoldedScreenAvailable() { unfoldedScreenAvailabilityUpdates.add(Unit) } - }) + } + ) foldStateProvider.start() verify(rotationChangeProvider).addCallback(capture(rotationListener)) @@ -134,6 +142,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { // By default, we're on launcher. setupForegroundActivityType(isHomeActivity = true) + setIsLargeScreen(true) } @Test @@ -181,7 +190,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { sendHingeAngleEvent(10) assertThat(foldUpdates) - .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING) + .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING) assertThat(unfoldedScreenAvailabilityUpdates).hasSize(1) } @@ -386,8 +395,10 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES) sendHingeAngleEvent( - START_CLOSING_ON_APPS_THRESHOLD_DEGREES - - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1) + START_CLOSING_ON_APPS_THRESHOLD_DEGREES - + HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - + 1 + ) assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) } @@ -429,8 +440,10 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { setInitialHingeAngle(START_CLOSING_ON_APPS_THRESHOLD_DEGREES) sendHingeAngleEvent( - START_CLOSING_ON_APPS_THRESHOLD_DEGREES - - HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - 1) + START_CLOSING_ON_APPS_THRESHOLD_DEGREES - + HINGE_ANGLE_CHANGE_THRESHOLD_DEGREES.toInt() - + 1 + ) assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) } @@ -470,7 +483,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { sendHingeAngleEvent(130) sendHingeAngleEvent(120) assertThat(foldUpdates) - .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING) + .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING) } @Test @@ -531,8 +544,8 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { rotationListener.value.onRotationChanged(1) - assertThat(foldUpdates).containsExactly( - FOLD_UPDATE_START_OPENING, FOLD_UPDATE_FINISH_HALF_OPEN) + assertThat(foldUpdates) + .containsExactly(FOLD_UPDATE_START_OPENING, FOLD_UPDATE_FINISH_HALF_OPEN) } @Test @@ -545,6 +558,45 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { assertThat(foldUpdates).containsExactly(FOLD_UPDATE_FINISH_CLOSED) } + @Test + fun onFolding_onSmallScreen_tansitionDoesNotStart() { + setIsLargeScreen(false) + + setInitialHingeAngle(120) + sendHingeAngleEvent(110) + sendHingeAngleEvent(100) + + assertThat(foldUpdates).isEmpty() + } + + @Test + fun onFolding_onLargeScreen_tansitionStarts() { + setIsLargeScreen(true) + + setInitialHingeAngle(120) + sendHingeAngleEvent(110) + sendHingeAngleEvent(100) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) + } + + @Test + fun onUnfold_onSmallScreen_emitsStartOpening() { + // the new display state might arrive later, so it shouldn't be used to decide to send the + // start opening event, but only for the closing. + setFoldState(folded = true) + setIsLargeScreen(false) + foldUpdates.clear() + + setFoldState(folded = false) + screenOnStatusProvider.notifyScreenTurningOn() + sendHingeAngleEvent(10) + sendHingeAngleEvent(20) + screenOnStatusProvider.notifyScreenTurnedOn() + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_OPENING) + } + private fun setupForegroundActivityType(isHomeActivity: Boolean?) { whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity) } @@ -566,6 +618,13 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { foldProvider.notifyFolded(folded) } + private fun setIsLargeScreen(isLargeScreen: Boolean) { + val smallestScreenWidth = if (isLargeScreen) { 601 } else { 10 } + val configuration = Configuration() + configuration.smallestScreenWidthDp = smallestScreenWidth + whenever(resources.configuration).thenReturn(configuration) + } + private fun fireScreenOnEvent() { screenOnStatusProvider.notifyScreenTurnedOn() } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt index 2044f05664d0..380c1fcbf732 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt @@ -53,4 +53,4 @@ class ScreenSizeFoldProvider(private val context: Context) : FoldProvider { } } -private const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600 +internal const val INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600 diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index d653fc7beff2..a633a5e41882 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -15,12 +15,14 @@ */ package com.android.systemui.unfold.updates +import android.content.Context import android.os.Handler import android.os.Trace import android.util.Log import androidx.annotation.FloatRange import androidx.annotation.VisibleForTesting import androidx.core.util.Consumer +import com.android.systemui.unfold.compat.INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP import com.android.systemui.unfold.config.UnfoldTransitionConfig import com.android.systemui.unfold.dagger.UnfoldMain import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate @@ -45,6 +47,7 @@ constructor( private val activityTypeProvider: CurrentActivityTypeProvider, private val unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider, private val rotationChangeProvider: RotationChangeProvider, + private val context: Context, @UnfoldMain private val mainExecutor: Executor, @UnfoldMain private val handler: Handler ) : FoldStateProvider { @@ -119,7 +122,7 @@ constructor( "lastHingeAngle: $lastHingeAngle, " + "lastHingeAngleBeforeTransition: $lastHingeAngleBeforeTransition" ) - Trace.setCounter( "hinge_angle", angle.toLong()) + Trace.setCounter("hinge_angle", angle.toLong()) } val currentDirection = @@ -136,6 +139,7 @@ constructor( val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES val eventNotAlreadyDispatched = lastFoldUpdate != transitionUpdate val screenAvailableEventSent = isUnfoldHandled + val isOnLargeScreen = isOnLargeScreen() if ( angleChangeSurpassedThreshold && // Do not react immediately to small changes in angle @@ -144,7 +148,9 @@ constructor( // angle range as closing threshold could overlap this range screenAvailableEventSent && // do not send transition event if we are still in the // process of turning on the inner display - isClosingThresholdMet(angle) // hinge angle is below certain threshold. + isClosingThresholdMet(angle) && // hinge angle is below certain threshold. + isOnLargeScreen // Avoids sending closing event when on small screen. + // Start event is sent regardless due to hall sensor. ) { notifyFoldUpdate(transitionUpdate, lastHingeAngle) } @@ -233,7 +239,7 @@ constructor( } private fun cancelAnimation(): Unit = - notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle) + notifyFoldUpdate(FOLD_UPDATE_FINISH_HALF_OPEN, lastHingeAngle) private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener { @@ -261,6 +267,11 @@ constructor( } } + private fun isOnLargeScreen(): Boolean { + return context.resources.configuration.smallestScreenWidthDp > + INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP + } + /** While the screen is off or the device is folded, hinge angle updates are not needed. */ private fun updateHingeAngleProviderState() { if (isScreenOn && !isFolded) { diff --git a/packages/VpnDialogs/res/values-af/strings.xml b/packages/VpnDialogs/res/values-af/strings.xml index 88ccbd9e98dc..db3c3558dc69 100644 --- a/packages/VpnDialogs/res/values-af/strings.xml +++ b/packages/VpnDialogs/res/values-af/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Ontkoppel"</string> <string name="open_app" msgid="3717639178595958667">"Maak program oop"</string> <string name="dismiss" msgid="6192859333764711227">"Maak toe"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g> … ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-am/strings.xml b/packages/VpnDialogs/res/values-am/strings.xml index 9fc5ff43d946..d86e043a4c6a 100644 --- a/packages/VpnDialogs/res/values-am/strings.xml +++ b/packages/VpnDialogs/res/values-am/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ግንኙነት አቋርጥ"</string> <string name="open_app" msgid="3717639178595958667">"መተግበሪያን ክፈት"</string> <string name="dismiss" msgid="6192859333764711227">"አሰናብት"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ar/strings.xml b/packages/VpnDialogs/res/values-ar/strings.xml index 33be6a3e458a..9307a744c37f 100644 --- a/packages/VpnDialogs/res/values-ar/strings.xml +++ b/packages/VpnDialogs/res/values-ar/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"قطع الاتصال"</string> <string name="open_app" msgid="3717639178595958667">"فتح التطبيق"</string> <string name="dismiss" msgid="6192859333764711227">"تجاهل"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml index 3f2e2347135d..736bb8318d99 100644 --- a/packages/VpnDialogs/res/values-as/strings.xml +++ b/packages/VpnDialogs/res/values-as/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"সংযোগ বিচ্ছিন্ন কৰক"</string> <string name="open_app" msgid="3717639178595958667">"এপ্ খোলক"</string> <string name="dismiss" msgid="6192859333764711227">"অগ্ৰাহ্য কৰক"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-az/strings.xml b/packages/VpnDialogs/res/values-az/strings.xml index d8788350bb8c..9b69e3e5d395 100644 --- a/packages/VpnDialogs/res/values-az/strings.xml +++ b/packages/VpnDialogs/res/values-az/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Əlaqəni kəs"</string> <string name="open_app" msgid="3717639178595958667">"Tətbiqi açın"</string> <string name="dismiss" msgid="6192859333764711227">"İmtina edin"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml index a1075d22df84..3270744783e6 100644 --- a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml +++ b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string> <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string> <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-be/strings.xml b/packages/VpnDialogs/res/values-be/strings.xml index fc3f8787b5d7..54908f6d8ce7 100644 --- a/packages/VpnDialogs/res/values-be/strings.xml +++ b/packages/VpnDialogs/res/values-be/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Адключыцца"</string> <string name="open_app" msgid="3717639178595958667">"Адкрыць праграму"</string> <string name="dismiss" msgid="6192859333764711227">"Адхіліць"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-bg/strings.xml b/packages/VpnDialogs/res/values-bg/strings.xml index 6345f1dd7911..734888f6205d 100644 --- a/packages/VpnDialogs/res/values-bg/strings.xml +++ b/packages/VpnDialogs/res/values-bg/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Изключване"</string> <string name="open_app" msgid="3717639178595958667">"Към приложението"</string> <string name="dismiss" msgid="6192859333764711227">"Отхвърляне"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-bn/strings.xml b/packages/VpnDialogs/res/values-bn/strings.xml index 352b786bc009..f176b2442973 100644 --- a/packages/VpnDialogs/res/values-bn/strings.xml +++ b/packages/VpnDialogs/res/values-bn/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"সংযোগ বিচ্ছিন্ন করুন"</string> <string name="open_app" msgid="3717639178595958667">"অ্যাপটি খুলুন"</string> <string name="dismiss" msgid="6192859333764711227">"খারিজ করুন"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-bs/strings.xml b/packages/VpnDialogs/res/values-bs/strings.xml index fa5f4ea2b762..b2f40e22e589 100644 --- a/packages/VpnDialogs/res/values-bs/strings.xml +++ b/packages/VpnDialogs/res/values-bs/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string> <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string> <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ca/strings.xml b/packages/VpnDialogs/res/values-ca/strings.xml index cdb754723c28..aa64abd7247d 100644 --- a/packages/VpnDialogs/res/values-ca/strings.xml +++ b/packages/VpnDialogs/res/values-ca/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Desconnecta"</string> <string name="open_app" msgid="3717639178595958667">"Obre l\'aplicació"</string> <string name="dismiss" msgid="6192859333764711227">"Ignora"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-cs/strings.xml b/packages/VpnDialogs/res/values-cs/strings.xml index c06f6ff0cf02..06589308034e 100644 --- a/packages/VpnDialogs/res/values-cs/strings.xml +++ b/packages/VpnDialogs/res/values-cs/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Odpojit"</string> <string name="open_app" msgid="3717639178595958667">"Do aplikace"</string> <string name="dismiss" msgid="6192859333764711227">"Zavřít"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-da/strings.xml b/packages/VpnDialogs/res/values-da/strings.xml index a4ddc1963de8..63a32f9c113e 100644 --- a/packages/VpnDialogs/res/values-da/strings.xml +++ b/packages/VpnDialogs/res/values-da/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Fjern tilknytning"</string> <string name="open_app" msgid="3717639178595958667">"Åbn app"</string> <string name="dismiss" msgid="6192859333764711227">"Luk"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-de/strings.xml b/packages/VpnDialogs/res/values-de/strings.xml index 1de780562966..7397ddb2510c 100644 --- a/packages/VpnDialogs/res/values-de/strings.xml +++ b/packages/VpnDialogs/res/values-de/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Verbindung trennen"</string> <string name="open_app" msgid="3717639178595958667">"App öffnen"</string> <string name="dismiss" msgid="6192859333764711227">"Schließen"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-el/strings.xml b/packages/VpnDialogs/res/values-el/strings.xml index e3eb4603ea61..3d140993541a 100644 --- a/packages/VpnDialogs/res/values-el/strings.xml +++ b/packages/VpnDialogs/res/values-el/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Αποσύνδεση"</string> <string name="open_app" msgid="3717639178595958667">"Άνοιγμα εφαρμογής"</string> <string name="dismiss" msgid="6192859333764711227">"Παράβλεψη"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-en-rAU/strings.xml b/packages/VpnDialogs/res/values-en-rAU/strings.xml index cb8b79d61ace..7855b24a7f38 100644 --- a/packages/VpnDialogs/res/values-en-rAU/strings.xml +++ b/packages/VpnDialogs/res/values-en-rAU/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Disconnect"</string> <string name="open_app" msgid="3717639178595958667">"Open app"</string> <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-en-rCA/strings.xml b/packages/VpnDialogs/res/values-en-rCA/strings.xml index f715c05b4b2c..eca5db04bf95 100644 --- a/packages/VpnDialogs/res/values-en-rCA/strings.xml +++ b/packages/VpnDialogs/res/values-en-rCA/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Disconnect"</string> <string name="open_app" msgid="3717639178595958667">"Open app"</string> <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-en-rGB/strings.xml b/packages/VpnDialogs/res/values-en-rGB/strings.xml index cb8b79d61ace..7855b24a7f38 100644 --- a/packages/VpnDialogs/res/values-en-rGB/strings.xml +++ b/packages/VpnDialogs/res/values-en-rGB/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Disconnect"</string> <string name="open_app" msgid="3717639178595958667">"Open app"</string> <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-en-rIN/strings.xml b/packages/VpnDialogs/res/values-en-rIN/strings.xml index cb8b79d61ace..7855b24a7f38 100644 --- a/packages/VpnDialogs/res/values-en-rIN/strings.xml +++ b/packages/VpnDialogs/res/values-en-rIN/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Disconnect"</string> <string name="open_app" msgid="3717639178595958667">"Open app"</string> <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-en-rXC/strings.xml b/packages/VpnDialogs/res/values-en-rXC/strings.xml index f5e2deb071a1..06d1421a7407 100644 --- a/packages/VpnDialogs/res/values-en-rXC/strings.xml +++ b/packages/VpnDialogs/res/values-en-rXC/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Disconnect"</string> <string name="open_app" msgid="3717639178595958667">"Open app"</string> <string name="dismiss" msgid="6192859333764711227">"Dismiss"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml index 232b53ab3d48..3a82cb526f15 100644 --- a/packages/VpnDialogs/res/values-es-rUS/strings.xml +++ b/packages/VpnDialogs/res/values-es-rUS/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Desconectar"</string> <string name="open_app" msgid="3717639178595958667">"Abrir app"</string> <string name="dismiss" msgid="6192859333764711227">"Descartar"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-es/strings.xml b/packages/VpnDialogs/res/values-es/strings.xml index 4e21fd099892..336ac0570b33 100644 --- a/packages/VpnDialogs/res/values-es/strings.xml +++ b/packages/VpnDialogs/res/values-es/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Desconectar"</string> <string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string> <string name="dismiss" msgid="6192859333764711227">"Cerrar"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-et/strings.xml b/packages/VpnDialogs/res/values-et/strings.xml index 140c18311607..864b9a428df5 100644 --- a/packages/VpnDialogs/res/values-et/strings.xml +++ b/packages/VpnDialogs/res/values-et/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Katkesta ühendus"</string> <string name="open_app" msgid="3717639178595958667">"Ava rakendus"</string> <string name="dismiss" msgid="6192859333764711227">"Loobu"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-eu/strings.xml b/packages/VpnDialogs/res/values-eu/strings.xml index a27a66a86c9d..01d80ebf8deb 100644 --- a/packages/VpnDialogs/res/values-eu/strings.xml +++ b/packages/VpnDialogs/res/values-eu/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Deskonektatu"</string> <string name="open_app" msgid="3717639178595958667">"Ireki aplikazioa"</string> <string name="dismiss" msgid="6192859333764711227">"Baztertu"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-fa/strings.xml b/packages/VpnDialogs/res/values-fa/strings.xml index 6fb5a001316e..47b8735a577f 100644 --- a/packages/VpnDialogs/res/values-fa/strings.xml +++ b/packages/VpnDialogs/res/values-fa/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"قطع اتصال"</string> <string name="open_app" msgid="3717639178595958667">"باز کردن برنامه"</string> <string name="dismiss" msgid="6192859333764711227">"رد کردن"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-fi/strings.xml b/packages/VpnDialogs/res/values-fi/strings.xml index 8abca06c2739..a08d66c8b4d7 100644 --- a/packages/VpnDialogs/res/values-fi/strings.xml +++ b/packages/VpnDialogs/res/values-fi/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Katkaise yhteys"</string> <string name="open_app" msgid="3717639178595958667">"Avaa sovellus"</string> <string name="dismiss" msgid="6192859333764711227">"Hylkää"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-fr-rCA/strings.xml b/packages/VpnDialogs/res/values-fr-rCA/strings.xml index 876111c26cdf..ad450b4c5f39 100644 --- a/packages/VpnDialogs/res/values-fr-rCA/strings.xml +++ b/packages/VpnDialogs/res/values-fr-rCA/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string> <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'application"</string> <string name="dismiss" msgid="6192859333764711227">"Ignorer"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-fr/strings.xml b/packages/VpnDialogs/res/values-fr/strings.xml index 91a995a591ee..c70fd5437a62 100644 --- a/packages/VpnDialogs/res/values-fr/strings.xml +++ b/packages/VpnDialogs/res/values-fr/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string> <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'appli"</string> <string name="dismiss" msgid="6192859333764711227">"Ignorer"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-gl/strings.xml b/packages/VpnDialogs/res/values-gl/strings.xml index 08ab9aea93cb..5595e15a9a85 100644 --- a/packages/VpnDialogs/res/values-gl/strings.xml +++ b/packages/VpnDialogs/res/values-gl/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Desconectar"</string> <string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string> <string name="dismiss" msgid="6192859333764711227">"Pechar"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-gu/strings.xml b/packages/VpnDialogs/res/values-gu/strings.xml index 5ffdcb1d8079..516d51c409f0 100644 --- a/packages/VpnDialogs/res/values-gu/strings.xml +++ b/packages/VpnDialogs/res/values-gu/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ડિસ્કનેક્ટ કરો"</string> <string name="open_app" msgid="3717639178595958667">"ઍપ ખોલો"</string> <string name="dismiss" msgid="6192859333764711227">"છોડી દો"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml index c9c65d5ac593..ad0cc0b128aa 100644 --- a/packages/VpnDialogs/res/values-hi/strings.xml +++ b/packages/VpnDialogs/res/values-hi/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"डिसकनेक्ट करें"</string> <string name="open_app" msgid="3717639178595958667">"ऐप खोलें"</string> <string name="dismiss" msgid="6192859333764711227">"खारिज करें"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-hr/strings.xml b/packages/VpnDialogs/res/values-hr/strings.xml index 576d99761571..ec1868870ab6 100644 --- a/packages/VpnDialogs/res/values-hr/strings.xml +++ b/packages/VpnDialogs/res/values-hr/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string> <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string> <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-hu/strings.xml b/packages/VpnDialogs/res/values-hu/strings.xml index 69b999fee1e1..0ce41ce82e4a 100644 --- a/packages/VpnDialogs/res/values-hu/strings.xml +++ b/packages/VpnDialogs/res/values-hu/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Kapcsolat bontása"</string> <string name="open_app" msgid="3717639178595958667">"Alkalmazás indítása"</string> <string name="dismiss" msgid="6192859333764711227">"Bezárás"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-hy/strings.xml b/packages/VpnDialogs/res/values-hy/strings.xml index d2a6d421592c..b699902353ce 100644 --- a/packages/VpnDialogs/res/values-hy/strings.xml +++ b/packages/VpnDialogs/res/values-hy/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Անջատել"</string> <string name="open_app" msgid="3717639178595958667">"Բացել հավելվածը"</string> <string name="dismiss" msgid="6192859333764711227">"Փակել"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-in/strings.xml b/packages/VpnDialogs/res/values-in/strings.xml index 88a588c5eddc..342f403ef09f 100644 --- a/packages/VpnDialogs/res/values-in/strings.xml +++ b/packages/VpnDialogs/res/values-in/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Putuskan koneksi"</string> <string name="open_app" msgid="3717639178595958667">"Buka aplikasi"</string> <string name="dismiss" msgid="6192859333764711227">"Tutup"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-is/strings.xml b/packages/VpnDialogs/res/values-is/strings.xml index a75371d77951..a52292ce2bdf 100644 --- a/packages/VpnDialogs/res/values-is/strings.xml +++ b/packages/VpnDialogs/res/values-is/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Aftengja"</string> <string name="open_app" msgid="3717639178595958667">"Opna forrit"</string> <string name="dismiss" msgid="6192859333764711227">"Hunsa"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-it/strings.xml b/packages/VpnDialogs/res/values-it/strings.xml index 118fb6a69005..7773c9e4813a 100644 --- a/packages/VpnDialogs/res/values-it/strings.xml +++ b/packages/VpnDialogs/res/values-it/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Disconnetti"</string> <string name="open_app" msgid="3717639178595958667">"Apri app"</string> <string name="dismiss" msgid="6192859333764711227">"Ignora"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-iw/strings.xml b/packages/VpnDialogs/res/values-iw/strings.xml index 56d810591400..3d4e0f0a8f14 100644 --- a/packages/VpnDialogs/res/values-iw/strings.xml +++ b/packages/VpnDialogs/res/values-iw/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"נתק"</string> <string name="open_app" msgid="3717639178595958667">"פתיחת האפליקציה"</string> <string name="dismiss" msgid="6192859333764711227">"סגירה"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ja/strings.xml b/packages/VpnDialogs/res/values-ja/strings.xml index e03e9d38087b..658569f275b9 100644 --- a/packages/VpnDialogs/res/values-ja/strings.xml +++ b/packages/VpnDialogs/res/values-ja/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"切断"</string> <string name="open_app" msgid="3717639178595958667">"アプリを開く"</string> <string name="dismiss" msgid="6192859333764711227">"閉じる"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g>(<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ka/strings.xml b/packages/VpnDialogs/res/values-ka/strings.xml index 9c4388e0e30e..5c4c8158044b 100644 --- a/packages/VpnDialogs/res/values-ka/strings.xml +++ b/packages/VpnDialogs/res/values-ka/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"კავშირის გაწყვეტა"</string> <string name="open_app" msgid="3717639178595958667">"გახსენით აპი"</string> <string name="dismiss" msgid="6192859333764711227">"დახურვა"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-kk/strings.xml b/packages/VpnDialogs/res/values-kk/strings.xml index 9a499d346ef7..a519e4c068ae 100644 --- a/packages/VpnDialogs/res/values-kk/strings.xml +++ b/packages/VpnDialogs/res/values-kk/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Ажырату"</string> <string name="open_app" msgid="3717639178595958667">"Қолданбаны ашу"</string> <string name="dismiss" msgid="6192859333764711227">"Жабу"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-km/strings.xml b/packages/VpnDialogs/res/values-km/strings.xml index de18abafb9eb..d93c6943861e 100644 --- a/packages/VpnDialogs/res/values-km/strings.xml +++ b/packages/VpnDialogs/res/values-km/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ផ្ដាច់"</string> <string name="open_app" msgid="3717639178595958667">"បើកកម្មវិធី"</string> <string name="dismiss" msgid="6192859333764711227">"ច្រានចោល"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-kn/strings.xml b/packages/VpnDialogs/res/values-kn/strings.xml index 6308f1844bfd..4f8d90b20405 100644 --- a/packages/VpnDialogs/res/values-kn/strings.xml +++ b/packages/VpnDialogs/res/values-kn/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string> <string name="open_app" msgid="3717639178595958667">"ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಿರಿ"</string> <string name="dismiss" msgid="6192859333764711227">"ವಜಾಗೊಳಿಸಿ"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ko/strings.xml b/packages/VpnDialogs/res/values-ko/strings.xml index 6e179bb9bcb0..ebadad7a5b0e 100644 --- a/packages/VpnDialogs/res/values-ko/strings.xml +++ b/packages/VpnDialogs/res/values-ko/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"연결 끊기"</string> <string name="open_app" msgid="3717639178595958667">"앱 열기"</string> <string name="dismiss" msgid="6192859333764711227">"닫기"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g>(<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ky/strings.xml b/packages/VpnDialogs/res/values-ky/strings.xml index ea33e3427b0d..41204aa322e2 100644 --- a/packages/VpnDialogs/res/values-ky/strings.xml +++ b/packages/VpnDialogs/res/values-ky/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Ажыратуу"</string> <string name="open_app" msgid="3717639178595958667">"Колдонмону ачуу"</string> <string name="dismiss" msgid="6192859333764711227">"Четке кагуу"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-lo/strings.xml b/packages/VpnDialogs/res/values-lo/strings.xml index cec69f0fe9c0..4c36b71a2a7c 100644 --- a/packages/VpnDialogs/res/values-lo/strings.xml +++ b/packages/VpnDialogs/res/values-lo/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ຕັດການເຊື່ອມຕໍ່"</string> <string name="open_app" msgid="3717639178595958667">"ເປີດແອັບ"</string> <string name="dismiss" msgid="6192859333764711227">"ປິດໄວ້"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-lt/strings.xml b/packages/VpnDialogs/res/values-lt/strings.xml index 97abd0d66eb3..d8783d232ac9 100644 --- a/packages/VpnDialogs/res/values-lt/strings.xml +++ b/packages/VpnDialogs/res/values-lt/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Atsijungti"</string> <string name="open_app" msgid="3717639178595958667">"Atidaryti programą"</string> <string name="dismiss" msgid="6192859333764711227">"Atsisakyti"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-lv/strings.xml b/packages/VpnDialogs/res/values-lv/strings.xml index 6341fbdf0158..7e8ecc1fe11c 100644 --- a/packages/VpnDialogs/res/values-lv/strings.xml +++ b/packages/VpnDialogs/res/values-lv/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Pārtraukt savienojumu"</string> <string name="open_app" msgid="3717639178595958667">"Atvērt lietotni"</string> <string name="dismiss" msgid="6192859333764711227">"Nerādīt"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-mk/strings.xml b/packages/VpnDialogs/res/values-mk/strings.xml index 689d028fd724..ec692ab02249 100644 --- a/packages/VpnDialogs/res/values-mk/strings.xml +++ b/packages/VpnDialogs/res/values-mk/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Прекини врска"</string> <string name="open_app" msgid="3717639178595958667">"Отвори ја апликацијата"</string> <string name="dismiss" msgid="6192859333764711227">"Отфрли"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ml/strings.xml b/packages/VpnDialogs/res/values-ml/strings.xml index 8284a78c26f8..a98bcdcb1059 100644 --- a/packages/VpnDialogs/res/values-ml/strings.xml +++ b/packages/VpnDialogs/res/values-ml/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"വിച്ഛേദിക്കുക"</string> <string name="open_app" msgid="3717639178595958667">"ആപ്പ് തുറക്കുക"</string> <string name="dismiss" msgid="6192859333764711227">"നിരസിക്കുക"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-mn/strings.xml b/packages/VpnDialogs/res/values-mn/strings.xml index 1dd4c15c43bb..8eb3289454af 100644 --- a/packages/VpnDialogs/res/values-mn/strings.xml +++ b/packages/VpnDialogs/res/values-mn/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Салгах"</string> <string name="open_app" msgid="3717639178595958667">"Апп нээх"</string> <string name="dismiss" msgid="6192859333764711227">"Хаах"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-mr/strings.xml b/packages/VpnDialogs/res/values-mr/strings.xml index 22fb502129a5..cccf3695a537 100644 --- a/packages/VpnDialogs/res/values-mr/strings.xml +++ b/packages/VpnDialogs/res/values-mr/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"डिस्कनेक्ट करा"</string> <string name="open_app" msgid="3717639178595958667">"अॅप उघडा"</string> <string name="dismiss" msgid="6192859333764711227">"डिसमिस करा"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ms/strings.xml b/packages/VpnDialogs/res/values-ms/strings.xml index c9961d2654e2..ad42abb3e3d7 100644 --- a/packages/VpnDialogs/res/values-ms/strings.xml +++ b/packages/VpnDialogs/res/values-ms/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Putuskan sambungan"</string> <string name="open_app" msgid="3717639178595958667">"Buka apl"</string> <string name="dismiss" msgid="6192859333764711227">"Ketepikan"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-my/strings.xml b/packages/VpnDialogs/res/values-my/strings.xml index 36348c8b5c8c..bc212a265f48 100644 --- a/packages/VpnDialogs/res/values-my/strings.xml +++ b/packages/VpnDialogs/res/values-my/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string> <string name="open_app" msgid="3717639178595958667">"အက်ပ်ကို ဖွင့်ရန်"</string> <string name="dismiss" msgid="6192859333764711227">"ပယ်ရန်"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-nb/strings.xml b/packages/VpnDialogs/res/values-nb/strings.xml index 14c84d702712..bca01d0dbeba 100644 --- a/packages/VpnDialogs/res/values-nb/strings.xml +++ b/packages/VpnDialogs/res/values-nb/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Koble fra"</string> <string name="open_app" msgid="3717639178595958667">"Åpne appen"</string> <string name="dismiss" msgid="6192859333764711227">"Lukk"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml index 2a5648d147c1..675a76dc6c02 100644 --- a/packages/VpnDialogs/res/values-ne/strings.xml +++ b/packages/VpnDialogs/res/values-ne/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"डिस्कनेक्ट गर्नुहोस्"</string> <string name="open_app" msgid="3717639178595958667">"एप खोल्नुहोस्"</string> <string name="dismiss" msgid="6192859333764711227">"खारेज गर्नुहोस्"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-nl/strings.xml b/packages/VpnDialogs/res/values-nl/strings.xml index 76f56afb63df..80e7f1b12b07 100644 --- a/packages/VpnDialogs/res/values-nl/strings.xml +++ b/packages/VpnDialogs/res/values-nl/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Verbinding verbreken"</string> <string name="open_app" msgid="3717639178595958667">"App openen"</string> <string name="dismiss" msgid="6192859333764711227">"Sluiten"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml index 4c5c2591986f..2f5a3dd06626 100644 --- a/packages/VpnDialogs/res/values-or/strings.xml +++ b/packages/VpnDialogs/res/values-or/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string> <string name="open_app" msgid="3717639178595958667">"ଆପ୍ ଖୋଲନ୍ତୁ"</string> <string name="dismiss" msgid="6192859333764711227">"ଖାରଜ କରନ୍ତୁ"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-pa/strings.xml b/packages/VpnDialogs/res/values-pa/strings.xml index d2eba0f52005..427cf8682b23 100644 --- a/packages/VpnDialogs/res/values-pa/strings.xml +++ b/packages/VpnDialogs/res/values-pa/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string> <string name="open_app" msgid="3717639178595958667">"ਐਪ ਖੋਲ੍ਹੋ"</string> <string name="dismiss" msgid="6192859333764711227">"ਖਾਰਜ ਕਰੋ"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-pl/strings.xml b/packages/VpnDialogs/res/values-pl/strings.xml index 82161d389368..1bd89bb43dd3 100644 --- a/packages/VpnDialogs/res/values-pl/strings.xml +++ b/packages/VpnDialogs/res/values-pl/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Rozłącz"</string> <string name="open_app" msgid="3717639178595958667">"Otwórz aplikację"</string> <string name="dismiss" msgid="6192859333764711227">"Zamknij"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-pt-rBR/strings.xml b/packages/VpnDialogs/res/values-pt-rBR/strings.xml index 0d6dd0b136e9..53d65af4efd9 100644 --- a/packages/VpnDialogs/res/values-pt-rBR/strings.xml +++ b/packages/VpnDialogs/res/values-pt-rBR/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Desconectar"</string> <string name="open_app" msgid="3717639178595958667">"Abrir app"</string> <string name="dismiss" msgid="6192859333764711227">"Dispensar"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-pt-rPT/strings.xml b/packages/VpnDialogs/res/values-pt-rPT/strings.xml index a310104555a2..95f7c1abe0f3 100644 --- a/packages/VpnDialogs/res/values-pt-rPT/strings.xml +++ b/packages/VpnDialogs/res/values-pt-rPT/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Desligar"</string> <string name="open_app" msgid="3717639178595958667">"Abrir app"</string> <string name="dismiss" msgid="6192859333764711227">"Ignorar"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-pt/strings.xml b/packages/VpnDialogs/res/values-pt/strings.xml index 0d6dd0b136e9..53d65af4efd9 100644 --- a/packages/VpnDialogs/res/values-pt/strings.xml +++ b/packages/VpnDialogs/res/values-pt/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Desconectar"</string> <string name="open_app" msgid="3717639178595958667">"Abrir app"</string> <string name="dismiss" msgid="6192859333764711227">"Dispensar"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml index f86a5d64fcce..f45609beba66 100644 --- a/packages/VpnDialogs/res/values-ro/strings.xml +++ b/packages/VpnDialogs/res/values-ro/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Deconectează"</string> <string name="open_app" msgid="3717639178595958667">"Deschide aplicația"</string> <string name="dismiss" msgid="6192859333764711227">"Închide"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ru/strings.xml b/packages/VpnDialogs/res/values-ru/strings.xml index ce099562f854..2e346d348072 100644 --- a/packages/VpnDialogs/res/values-ru/strings.xml +++ b/packages/VpnDialogs/res/values-ru/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Разъединить"</string> <string name="open_app" msgid="3717639178595958667">"Открыть приложение"</string> <string name="dismiss" msgid="6192859333764711227">"Закрыть"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-si/strings.xml b/packages/VpnDialogs/res/values-si/strings.xml index a836baef545c..fa5a70f0c3bd 100644 --- a/packages/VpnDialogs/res/values-si/strings.xml +++ b/packages/VpnDialogs/res/values-si/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"විසන්ධි කරන්න"</string> <string name="open_app" msgid="3717639178595958667">"යෙදුම විවෘත කරන්න"</string> <string name="dismiss" msgid="6192859333764711227">"ඉවතලන්න"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-sk/strings.xml b/packages/VpnDialogs/res/values-sk/strings.xml index 766c1393b524..755abb2860c6 100644 --- a/packages/VpnDialogs/res/values-sk/strings.xml +++ b/packages/VpnDialogs/res/values-sk/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Odpojiť"</string> <string name="open_app" msgid="3717639178595958667">"Otvoriť aplikáciu"</string> <string name="dismiss" msgid="6192859333764711227">"Zavrieť"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-sl/strings.xml b/packages/VpnDialogs/res/values-sl/strings.xml index 361a5fa2f1fa..b473ce0a3160 100644 --- a/packages/VpnDialogs/res/values-sl/strings.xml +++ b/packages/VpnDialogs/res/values-sl/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Prekini povezavo"</string> <string name="open_app" msgid="3717639178595958667">"Odpri aplikacijo"</string> <string name="dismiss" msgid="6192859333764711227">"Opusti"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g> … (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-sq/strings.xml b/packages/VpnDialogs/res/values-sq/strings.xml index eb73baad00b4..ad9f66e65158 100644 --- a/packages/VpnDialogs/res/values-sq/strings.xml +++ b/packages/VpnDialogs/res/values-sq/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Shkëputu"</string> <string name="open_app" msgid="3717639178595958667">"Hap aplikacionin"</string> <string name="dismiss" msgid="6192859333764711227">"Hiq"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-sr/strings.xml b/packages/VpnDialogs/res/values-sr/strings.xml index 01bd4df700a7..eaa0aeffcb3e 100644 --- a/packages/VpnDialogs/res/values-sr/strings.xml +++ b/packages/VpnDialogs/res/values-sr/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Прекини везу"</string> <string name="open_app" msgid="3717639178595958667">"Отвори апликацију"</string> <string name="dismiss" msgid="6192859333764711227">"Одбаци"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-sv/strings.xml b/packages/VpnDialogs/res/values-sv/strings.xml index 60ed75250856..175ebbada1eb 100644 --- a/packages/VpnDialogs/res/values-sv/strings.xml +++ b/packages/VpnDialogs/res/values-sv/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Koppla från"</string> <string name="open_app" msgid="3717639178595958667">"Öppna appen"</string> <string name="dismiss" msgid="6192859333764711227">"Ignorera"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-sw/strings.xml b/packages/VpnDialogs/res/values-sw/strings.xml index c4f46628f8bc..66c2899009fd 100644 --- a/packages/VpnDialogs/res/values-sw/strings.xml +++ b/packages/VpnDialogs/res/values-sw/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Tenganisha"</string> <string name="open_app" msgid="3717639178595958667">"Fungua programu"</string> <string name="dismiss" msgid="6192859333764711227">"Ondoa"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ta/strings.xml b/packages/VpnDialogs/res/values-ta/strings.xml index 1385bdc401c3..31602a6a9152 100644 --- a/packages/VpnDialogs/res/values-ta/strings.xml +++ b/packages/VpnDialogs/res/values-ta/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"தொடர்பைத் துண்டி"</string> <string name="open_app" msgid="3717639178595958667">"பயன்பாட்டைத் திற"</string> <string name="dismiss" msgid="6192859333764711227">"நிராகரி"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-te/strings.xml b/packages/VpnDialogs/res/values-te/strings.xml index 78843360bdab..685dd26de30d 100644 --- a/packages/VpnDialogs/res/values-te/strings.xml +++ b/packages/VpnDialogs/res/values-te/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"డిస్కనెక్ట్ చేయి"</string> <string name="open_app" msgid="3717639178595958667">"యాప్ని తెరవండి"</string> <string name="dismiss" msgid="6192859333764711227">"తీసివేయండి"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-th/strings.xml b/packages/VpnDialogs/res/values-th/strings.xml index 2e174cd7b296..3e15d4b34025 100644 --- a/packages/VpnDialogs/res/values-th/strings.xml +++ b/packages/VpnDialogs/res/values-th/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"ยกเลิกการเชื่อมต่อ"</string> <string name="open_app" msgid="3717639178595958667">"เปิดแอป"</string> <string name="dismiss" msgid="6192859333764711227">"ปิด"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-tl/strings.xml b/packages/VpnDialogs/res/values-tl/strings.xml index ea69fba45f1e..0b4a10625697 100644 --- a/packages/VpnDialogs/res/values-tl/strings.xml +++ b/packages/VpnDialogs/res/values-tl/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Idiskonekta"</string> <string name="open_app" msgid="3717639178595958667">"Buksan ang app"</string> <string name="dismiss" msgid="6192859333764711227">"I-dismiss"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-tr/strings.xml b/packages/VpnDialogs/res/values-tr/strings.xml index 7ffa4bc1e4e9..e3606effa3fc 100644 --- a/packages/VpnDialogs/res/values-tr/strings.xml +++ b/packages/VpnDialogs/res/values-tr/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Bağlantıyı kes"</string> <string name="open_app" msgid="3717639178595958667">"Uygulamayı aç"</string> <string name="dismiss" msgid="6192859333764711227">"Kapat"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-uk/strings.xml b/packages/VpnDialogs/res/values-uk/strings.xml index 6411d7cf9d76..1dd0e8aa6364 100644 --- a/packages/VpnDialogs/res/values-uk/strings.xml +++ b/packages/VpnDialogs/res/values-uk/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Від’єднати"</string> <string name="open_app" msgid="3717639178595958667">"Відкрити додаток"</string> <string name="dismiss" msgid="6192859333764711227">"Закрити"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-ur/strings.xml b/packages/VpnDialogs/res/values-ur/strings.xml index 3a23e940d9e9..803f0427c78b 100644 --- a/packages/VpnDialogs/res/values-ur/strings.xml +++ b/packages/VpnDialogs/res/values-ur/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"منقطع کریں"</string> <string name="open_app" msgid="3717639178595958667">"ایپ کھولیں"</string> <string name="dismiss" msgid="6192859333764711227">"برخاست کریں"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-uz/strings.xml b/packages/VpnDialogs/res/values-uz/strings.xml index a3256e7bb927..a54fa0834ae9 100644 --- a/packages/VpnDialogs/res/values-uz/strings.xml +++ b/packages/VpnDialogs/res/values-uz/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Aloqani uzish"</string> <string name="open_app" msgid="3717639178595958667">"Ilovani ochish"</string> <string name="dismiss" msgid="6192859333764711227">"Yopish"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-vi/strings.xml b/packages/VpnDialogs/res/values-vi/strings.xml index 184d08d7d665..6ce9f393f1cc 100644 --- a/packages/VpnDialogs/res/values-vi/strings.xml +++ b/packages/VpnDialogs/res/values-vi/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Ngắt kết nối"</string> <string name="open_app" msgid="3717639178595958667">"Mở ứng dụng"</string> <string name="dismiss" msgid="6192859333764711227">"Loại bỏ"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-zh-rCN/strings.xml b/packages/VpnDialogs/res/values-zh-rCN/strings.xml index a7262bedce96..38a2e8de6161 100644 --- a/packages/VpnDialogs/res/values-zh-rCN/strings.xml +++ b/packages/VpnDialogs/res/values-zh-rCN/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"断开连接"</string> <string name="open_app" msgid="3717639178595958667">"打开应用"</string> <string name="dismiss" msgid="6192859333764711227">"关闭"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-zh-rHK/strings.xml b/packages/VpnDialogs/res/values-zh-rHK/strings.xml index e4e643234143..f3abf3cd89a2 100644 --- a/packages/VpnDialogs/res/values-zh-rHK/strings.xml +++ b/packages/VpnDialogs/res/values-zh-rHK/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"中斷連線"</string> <string name="open_app" msgid="3717639178595958667">"開啟應用程式"</string> <string name="dismiss" msgid="6192859333764711227">"關閉"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-zh-rTW/strings.xml b/packages/VpnDialogs/res/values-zh-rTW/strings.xml index f54ca4a7a576..3f1336be9184 100644 --- a/packages/VpnDialogs/res/values-zh-rTW/strings.xml +++ b/packages/VpnDialogs/res/values-zh-rTW/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"中斷連線"</string> <string name="open_app" msgid="3717639178595958667">"開啟應用程式"</string> <string name="dismiss" msgid="6192859333764711227">"關閉"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/packages/VpnDialogs/res/values-zu/strings.xml b/packages/VpnDialogs/res/values-zu/strings.xml index c224b13b06da..563ed0f5beb4 100644 --- a/packages/VpnDialogs/res/values-zu/strings.xml +++ b/packages/VpnDialogs/res/values-zu/strings.xml @@ -34,4 +34,6 @@ <string name="disconnect" msgid="971412338304200056">"Ayixhumekile kwi-inthanethi"</string> <string name="open_app" msgid="3717639178595958667">"Vula uhlelo lokusebenza"</string> <string name="dismiss" msgid="6192859333764711227">"Cashisa"</string> + <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string> + <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string> </resources> diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index ff1a495edcbb..802574828d15 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -168,6 +168,7 @@ public final class ContentCaptureManagerService extends @GuardedBy("mLock") int mDevCfgTextChangeFlushingFrequencyMs; @GuardedBy("mLock") int mDevCfgLogHistorySize; @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs; + @GuardedBy("mLock") boolean mDevCfgDisableFlushForViewTreeAppearing; private final Executor mDataShareExecutor = Executors.newCachedThreadPool(); private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -358,6 +359,8 @@ public final class ContentCaptureManagerService extends case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE: case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY: case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT: + case ContentCaptureManager + .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING: setFineTuneParamsFromDeviceConfig(); return; default: @@ -387,13 +390,20 @@ public final class ContentCaptureManagerService extends DeviceConfig.NAMESPACE_CONTENT_CAPTURE, ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT, (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS); + mDevCfgDisableFlushForViewTreeAppearing = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_CONTENT_CAPTURE, + ContentCaptureManager + .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING, + false); if (verbose) { Slog.v(TAG, "setFineTuneParamsFromDeviceConfig(): " + "bufferSize=" + mDevCfgMaxBufferSize + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs + ", logHistory=" + mDevCfgLogHistorySize - + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs); + + ", idleUnbindTimeoutMs=" + mDevCfgIdleUnbindTimeoutMs + + ", disableFlushForViewTreeAppearing=" + + mDevCfgDisableFlushForViewTreeAppearing); } } } @@ -628,6 +638,7 @@ public final class ContentCaptureManagerService extends } @Override // from AbstractMasterSystemService + @GuardedBy("mLock") protected void dumpLocked(String prefix, PrintWriter pw) { super.dumpLocked(prefix, pw); @@ -645,6 +656,8 @@ public final class ContentCaptureManagerService extends pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize); pw.print(prefix2); pw.print("idleUnbindTimeoutMs: "); pw.println(mDevCfgIdleUnbindTimeoutMs); + pw.print(prefix2); pw.print("disableFlushForViewTreeAppearing: "); + pw.println(mDevCfgDisableFlushForViewTreeAppearing); pw.print(prefix); pw.println("Global Options:"); mGlobalContentCaptureOptions.dump(prefix2, pw); } @@ -1003,12 +1016,15 @@ public final class ContentCaptureManagerService extends return null; } - final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel, - mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs, - mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, - whitelistedComponents); - if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); - return options; + synchronized (mLock) { + final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel, + mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs, + mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, + mDevCfgDisableFlushForViewTreeAppearing, + whitelistedComponents); + if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); + return options; + } } @Override diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 425158195940..1dc0942ceac5 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4893,10 +4893,6 @@ public class AccountManagerService if (intent.getClipData() == null) { intent.setClipData(ClipData.newPlainText(null, null)); } - intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION - | Intent.FLAG_GRANT_WRITE_URI_PERMISSION - | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION - | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)); final long bid = Binder.clearCallingIdentity(); try { PackageManager pm = mContext.getPackageManager(); @@ -4942,7 +4938,19 @@ public class AccountManagerService if (intent == null) { return (simulateIntent == null); } - return intent.filterEquals(simulateIntent); + if (!intent.filterEquals(simulateIntent)) { + return false; + } + + if (intent.getSelector() != simulateIntent.getSelector()) { + return false; + } + + int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION + | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION + | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; + return (simulateIntent.getFlags() & prohibitedFlags) == 0; } private boolean isExportedSystemActivity(ActivityInfo activityInfo) { diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index 702526a4beab..dc1ef7eee0b6 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -891,6 +891,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { break; case EnergyConsumerType.MOBILE_RADIO: buckets[MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO] = true; + buckets[MeasuredEnergyStats.POWER_BUCKET_PHONE] = true; break; case EnergyConsumerType.DISPLAY: buckets[MeasuredEnergyStats.POWER_BUCKET_SCREEN_ON] = true; diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index ff18167ee86f..158492056fb5 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1017,9 +1017,14 @@ public class AudioService extends IAudioService.Stub mSfxHelper = new SoundEffectsHelper(mContext, playerBase -> ignorePlayerLogs(playerBase)); - final boolean headTrackingDefault = mContext.getResources().getBoolean( + final boolean binauralEnabledDefault = SystemProperties.getBoolean( + "ro.audio.spatializer_binaural_enabled_default", true); + final boolean transauralEnabledDefault = SystemProperties.getBoolean( + "ro.audio.spatializer_transaural_enabled_default", true); + final boolean headTrackingEnabledDefault = mContext.getResources().getBoolean( com.android.internal.R.bool.config_spatial_audio_head_tracking_enabled_default); - mSpatializerHelper = new SpatializerHelper(this, mAudioSystem, headTrackingDefault); + mSpatializerHelper = new SpatializerHelper(this, mAudioSystem, + binauralEnabledDefault, transauralEnabledDefault, headTrackingEnabledDefault); mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator(); diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index 2b566668a7c7..a9e7d4b0bac8 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -171,13 +171,17 @@ public class SpatializerHelper { // initialization @SuppressWarnings("StaticAssignmentInConstructor") SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa, - boolean headTrackingEnabledByDefault) { + boolean binauralEnabledDefault, + boolean transauralEnabledDefault, + boolean headTrackingEnabledDefault) { mAudioService = mother; mASA = asa; // "StaticAssignmentInConstructor" warning is suppressed as the SpatializerHelper being // constructed here is the factory for SADeviceState, thus SADeviceState and its // private static field sHeadTrackingEnabledDefault should never be accessed directly. - SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledByDefault; + SADeviceState.sBinauralEnabledDefault = binauralEnabledDefault; + SADeviceState.sTransauralEnabledDefault = transauralEnabledDefault; + SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledDefault; } synchronized void initForTest(boolean hasBinaural, boolean hasTransaural) { @@ -1539,10 +1543,12 @@ public class SpatializerHelper { } /*package*/ static final class SADeviceState { + private static boolean sBinauralEnabledDefault = true; + private static boolean sTransauralEnabledDefault = true; private static boolean sHeadTrackingEnabledDefault = false; final @AudioDeviceInfo.AudioDeviceType int mDeviceType; final @NonNull String mDeviceAddress; - boolean mEnabled = true; // by default, SA is enabled on any device + boolean mEnabled; boolean mHasHeadTracker = false; boolean mHeadTrackerEnabled; static final String SETTING_FIELD_SEPARATOR = ","; @@ -1558,6 +1564,12 @@ public class SpatializerHelper { SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @Nullable String address) { mDeviceType = deviceType; mDeviceAddress = isWireless(deviceType) ? Objects.requireNonNull(address) : ""; + final int spatMode = SPAT_MODE_FOR_DEVICE_TYPE.get(deviceType, Integer.MIN_VALUE); + mEnabled = spatMode == SpatializationMode.SPATIALIZER_BINAURAL + ? sBinauralEnabledDefault + : spatMode == SpatializationMode.SPATIALIZER_TRANSAURAL + ? sTransauralEnabledDefault + : false; mHeadTrackerEnabled = sHeadTrackingEnabledDefault; } diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 1bbdc20c81e5..8c83be3ea8dd 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -1230,13 +1230,12 @@ public class DisplayModeDirector { } public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) { - if (defaultPeakRefreshRate == null) { - defaultPeakRefreshRate = (float) mContext.getResources().getInteger( - R.integer.config_defaultPeakRefreshRate); - } - - if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) { - synchronized (mLock) { + synchronized (mLock) { + if (defaultPeakRefreshRate == null) { + setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig, + /* attemptLoadingFromDeviceConfig= */ false); + updateRefreshRateSettingLocked(); + } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) { mDefaultPeakRefreshRate = defaultPeakRefreshRate; updateRefreshRateSettingLocked(); } @@ -1869,11 +1868,20 @@ public class DisplayModeDirector { mLowDisplayBrightnessThresholds = displayThresholds; mLowAmbientBrightnessThresholds = ambientThresholds; } else { - // Invalid or empty. Use device default. - mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray( - R.array.config_brightnessThresholdsOfPeakRefreshRate); - mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray( - R.array.config_ambientThresholdsOfPeakRefreshRate); + DisplayDeviceConfig displayDeviceConfig; + synchronized (mLock) { + displayDeviceConfig = mDefaultDisplayDeviceConfig; + } + mLowDisplayBrightnessThresholds = loadBrightnessThresholds( + () -> mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds(), + () -> displayDeviceConfig.getLowDisplayBrightnessThresholds(), + R.array.config_brightnessThresholdsOfPeakRefreshRate, + displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); + mLowAmbientBrightnessThresholds = loadBrightnessThresholds( + () -> mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds(), + () -> displayDeviceConfig.getLowAmbientBrightnessThresholds(), + R.array.config_ambientThresholdsOfPeakRefreshRate, + displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); } restartObserver(); } @@ -1883,24 +1891,41 @@ public class DisplayModeDirector { * DeviceConfig properties. */ public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) { - if (refreshRate != mRefreshRateInLowZone) { + if (refreshRate == -1) { + // Given there is no value available in DeviceConfig, lets not attempt loading it + // from there. + synchronized (mLock) { + loadRefreshRateInLowZone(mDefaultDisplayDeviceConfig, + /* attemptLoadingFromDeviceConfig= */ false); + } + restartObserver(); + } else if (refreshRate != mRefreshRateInLowZone) { mRefreshRateInLowZone = refreshRate; restartObserver(); } } - public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds, + private void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds, int[] ambientThresholds) { if (displayThresholds != null && ambientThresholds != null && displayThresholds.length == ambientThresholds.length) { mHighDisplayBrightnessThresholds = displayThresholds; mHighAmbientBrightnessThresholds = ambientThresholds; } else { - // Invalid or empty. Use device default. - mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray( - R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate); - mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray( - R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate); + DisplayDeviceConfig displayDeviceConfig; + synchronized (mLock) { + displayDeviceConfig = mDefaultDisplayDeviceConfig; + } + mHighDisplayBrightnessThresholds = loadBrightnessThresholds( + () -> mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds(), + () -> displayDeviceConfig.getHighDisplayBrightnessThresholds(), + R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate, + displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); + mHighAmbientBrightnessThresholds = loadBrightnessThresholds( + () -> mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds(), + () -> displayDeviceConfig.getHighAmbientBrightnessThresholds(), + R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate, + displayDeviceConfig, /* attemptLoadingFromDeviceConfig= */ false); } restartObserver(); } @@ -1910,7 +1935,15 @@ public class DisplayModeDirector { * DeviceConfig properties. */ public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) { - if (refreshRate != mRefreshRateInHighZone) { + if (refreshRate == -1) { + // Given there is no value available in DeviceConfig, lets not attempt loading it + // from there. + synchronized (mLock) { + loadRefreshRateInHighZone(mDefaultDisplayDeviceConfig, + /* attemptLoadingFromDeviceConfig= */ false); + } + restartObserver(); + } else if (refreshRate != mRefreshRateInHighZone) { mRefreshRateInHighZone = refreshRate; restartObserver(); } @@ -2870,10 +2903,8 @@ public class DisplayModeDirector { new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds)) .sendToTarget(); - if (refreshRateInLowZone != -1) { - mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, - 0).sendToTarget(); - } + mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, + 0).sendToTarget(); int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds(); int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds(); @@ -2883,10 +2914,8 @@ public class DisplayModeDirector { new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds)) .sendToTarget(); - if (refreshRateInHighZone != -1) { - mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, - 0).sendToTarget(); - } + mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, + 0).sendToTarget(); synchronized (mLock) { final int refreshRateInHbmSunlight = diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d11413937f8d..4df34cafc38b 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -6751,7 +6751,8 @@ public class NotificationManagerService extends SystemService { } // Ensure MediaStyle has correct permissions for remote device extras - if (notification.isStyle(Notification.MediaStyle.class)) { + if (notification.isStyle(Notification.MediaStyle.class) + || notification.isStyle(Notification.DecoratedMediaCustomViewStyle.class)) { int hasMediaContentControlPermission = mPackageManager.checkPermission( android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId); if (hasMediaContentControlPermission != PERMISSION_GRANTED) { diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java index ce1157e1d80c..70932fa50a3c 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java @@ -26,6 +26,7 @@ import android.media.soundtrigger.PhraseRecognitionEvent; import android.media.soundtrigger.PhraseSoundModel; import android.media.soundtrigger.RecognitionConfig; import android.media.soundtrigger.RecognitionEvent; +import android.media.soundtrigger.RecognitionStatus; import android.media.soundtrigger.SoundModel; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerModule; @@ -34,6 +35,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.LatencyTracker; import java.io.PrintWriter; @@ -358,14 +360,19 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt * Starts the latency tracking log for keyphrase hotword invocation. * The measurement covers from when the SoundTrigger HAL emits an event to when the * {@link android.service.voice.VoiceInteractionSession} system UI view is shown. + * + * <p>The session is only started if the {@link PhraseRecognitionEvent} has a status of + * {@link RecognitionStatus#SUCCESS} */ private void startKeyphraseEventLatencyTracking(PhraseRecognitionEvent event) { - String latencyTrackerTag = null; - if (event.phraseExtras.length > 0) { - latencyTrackerTag = "KeyphraseId=" + event.phraseExtras[0].id; + if (event.common.status != RecognitionStatus.SUCCESS + || ArrayUtils.isEmpty(event.phraseExtras)) { + return; } + LatencyTracker latencyTracker = LatencyTracker.getInstance(mContext); - // To avoid adding cancel to all of the different failure modes between here and + String latencyTrackerTag = "KeyphraseId=" + event.phraseExtras[0].id; + // To avoid adding cancel to all the different failure modes between here and // showing the system UI, we defensively cancel once. // Either we hit the LatencyTracker timeout of 15 seconds or we defensively cancel // here if any error occurs. diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java index 4b8a5b7fcf56..26f781f62078 100644 --- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java +++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java @@ -861,7 +861,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener { private static void getLetterBoxBounds(WindowState windowState, Region outRegion) { final Rect letterboxInsets = windowState.mActivityRecord.getLetterboxInsets(); - final Rect nonLetterboxRect = windowState.getBounds(); + final Rect nonLetterboxRect = new Rect(windowState.getBounds()); nonLetterboxRect.inset(letterboxInsets); outRegion.set(windowState.getBounds()); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 7ada2135212c..a8626dfe043a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -8071,6 +8071,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mSizeCompatScale = 1f; mSizeCompatBounds = null; mCompatDisplayInsets = null; + mLetterboxUiController.clearInheritedCompatDisplayInsets(); } @VisibleForTesting @@ -8386,6 +8387,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + @NonNull Rect getScreenResolvedBounds() { + final Configuration resolvedConfig = getResolvedOverrideConfiguration(); + final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); + return mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds; + } + void recomputeConfiguration() { // We check if the current activity is transparent. In that case we need to // recomputeConfiguration of the first opaque activity beneath, to allow a @@ -8585,7 +8592,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A resolvedBounds.set(containingBounds); final float letterboxAspectRatioOverride = - mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(); + mLetterboxUiController.getFixedOrientationLetterboxAspectRatio(newParentConfig); final float desiredAspectRatio = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 41130812d658..aedd2c594b9d 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -200,6 +200,7 @@ public class DisplayPolicy { private final boolean mCarDockEnablesAccelerometer; private final boolean mDeskDockEnablesAccelerometer; + private final boolean mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer; private final AccessibilityManager mAccessibilityManager; private final ImmersiveModeConfirmation mImmersiveModeConfirmation; private final ScreenshotHelper mScreenshotHelper; @@ -435,6 +436,8 @@ public class DisplayPolicy { final Resources r = mContext.getResources(); mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer); mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer); + mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer = + r.getBoolean(R.bool.config_deskRespectsNoSensorAndLockedWithoutAccelerometer); mCanSystemBarsBeShownByUser = !r.getBoolean( R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean( R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction); @@ -755,6 +758,10 @@ public class DisplayPolicy { return mDeskDockEnablesAccelerometer; } + boolean isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer() { + return mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer; + } + public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) { mPersistentVrModeEnabled = persistentVrModeEnabled; } @@ -2662,6 +2669,8 @@ public class DisplayPolicy { pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer); pw.print(" mDeskDockEnablesAccelerometer="); pw.println(mDeskDockEnablesAccelerometer); + pw.print(" mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer="); + pw.println(mDeskDockRespectsNoSensorAndLockedWithoutAccelerometer); pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode)); pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState)); pw.print(prefix); pw.print("mAwake="); pw.print(mAwake); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 3404279d2c59..e9569d8cc064 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -87,6 +87,12 @@ import java.util.Set; */ public class DisplayRotation { private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM; + // Delay to avoid race between fold update and orientation update. + private static final int ORIENTATION_UPDATE_DELAY_MS = 800; + + // Delay in milliseconds when updating config due to folding events. This prevents + // config changes and unexpected jumps while folding the device to closed state. + private static final int FOLDING_RECOMPUTE_CONFIG_DELAY_MS = 800; private static class RotationAnimationPair { @AnimRes @@ -1166,6 +1172,10 @@ public class DisplayRotation { mDisplayPolicy.isCarDockEnablesAccelerometer(); final boolean deskDockEnablesAccelerometer = mDisplayPolicy.isDeskDockEnablesAccelerometer(); + final boolean deskDockRespectsNoSensorAndLockedWithoutAccelerometer = + mDisplayPolicy.isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer() + && (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED + || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); final int preferredRotation; if (!isDefaultDisplay) { @@ -1184,7 +1194,8 @@ public class DisplayRotation { } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK) - && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) { + && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0) + && !deskDockRespectsNoSensorAndLockedWithoutAccelerometer) { // Ignore sensor when in desk dock unless explicitly enabled. // This case can override the behavior of NOSENSOR, and can also // enable 180 degree rotation while docked. @@ -1618,6 +1629,7 @@ public class DisplayRotation { private boolean mInHalfFoldTransition = false; private final boolean mIsDisplayAlwaysSeparatingHinge; private final Set<Integer> mTabletopRotations; + private final Runnable mActivityBoundsUpdateCallback; FoldController() { mTabletopRotations = new ArraySet<>(); @@ -1652,6 +1664,26 @@ public class DisplayRotation { } mIsDisplayAlwaysSeparatingHinge = mContext.getResources().getBoolean( R.bool.config_isDisplayHingeAlwaysSeparating); + + mActivityBoundsUpdateCallback = new Runnable() { + public void run() { + if (mDeviceState == DeviceStateController.DeviceState.OPEN + || mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) { + synchronized (mLock) { + final Task topFullscreenTask = + mDisplayContent.getTask( + t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); + if (topFullscreenTask != null) { + final ActivityRecord top = + topFullscreenTask.topRunningActivity(); + if (top != null) { + top.recomputeConfiguration(); + } + } + } + } + } + }; } boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) { @@ -1713,24 +1745,19 @@ public class DisplayRotation { mDeviceState = newState; // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will // return true, so rotation is unlocked. - mService.updateRotation(false /* alwaysSendConfiguration */, - false /* forceRelayout */); } else { mInHalfFoldTransition = true; mDeviceState = newState; - // Tell the device to update its orientation. - mService.updateRotation(false /* alwaysSendConfiguration */, - false /* forceRelayout */); } + UiThread.getHandler().postDelayed( + () -> { + mService.updateRotation(false /* alwaysSendConfiguration */, + false /* forceRelayout */); + }, ORIENTATION_UPDATE_DELAY_MS); // Alert the activity of possible new bounds. - final Task topFullscreenTask = - mDisplayContent.getTask(t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); - if (topFullscreenTask != null) { - final ActivityRecord top = topFullscreenTask.topRunningActivity(); - if (top != null) { - top.recomputeConfiguration(); - } - } + UiThread.getHandler().removeCallbacks(mActivityBoundsUpdateCallback); + UiThread.getHandler().postDelayed(mActivityBoundsUpdateCallback, + FOLDING_RECOMPUTE_CONFIG_DELAY_MS); } } diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java index 37cf5bc95a23..ec04894b1d42 100644 --- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java +++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java @@ -184,6 +184,10 @@ final class LetterboxConfiguration { // portrait device orientation. private boolean mIsVerticalReachabilityEnabled; + // Whether book mode automatic horizontal reachability positioning is allowed for letterboxed + // fullscreen apps in landscape device orientation. + private boolean mIsAutomaticReachabilityInBookModeEnabled; + // Whether education is allowed for letterboxed fullscreen apps. private boolean mIsEducationEnabled; @@ -277,6 +281,8 @@ final class LetterboxConfiguration { R.bool.config_letterboxIsHorizontalReachabilityEnabled); mIsVerticalReachabilityEnabled = mContext.getResources().getBoolean( R.bool.config_letterboxIsVerticalReachabilityEnabled); + mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean( + R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled); mDefaultPositionForHorizontalReachability = readLetterboxHorizontalReachabilityPositionFromConfig(mContext, false); mDefaultPositionForVerticalReachability = @@ -681,6 +687,14 @@ final class LetterboxConfiguration { return mIsVerticalReachabilityEnabled; } + /* + * Whether automatic horizontal reachability repositioning in book mode is allowed for + * letterboxed fullscreen apps in landscape device orientation. + */ + boolean getIsAutomaticReachabilityInBookModeEnabled() { + return mIsAutomaticReachabilityInBookModeEnabled; + } + /** * Overrides whether horizontal reachability repositioning is allowed for letterboxed fullscreen * apps in landscape device orientation. @@ -698,6 +712,14 @@ final class LetterboxConfiguration { } /** + * Overrides whether automatic horizontal reachability repositioning in book mode is allowed for + * letterboxed fullscreen apps in landscape device orientation. + */ + void setIsAutomaticReachabilityInBookModeEnabled(boolean enabled) { + mIsAutomaticReachabilityInBookModeEnabled = enabled; + } + + /** * Resets whether horizontal reachability repositioning is allowed for letterboxed fullscreen * apps in landscape device orientation to * {@link R.bool.config_letterboxIsHorizontalReachabilityEnabled}. @@ -717,6 +739,16 @@ final class LetterboxConfiguration { R.bool.config_letterboxIsVerticalReachabilityEnabled); } + /** + * Resets whether automatic horizontal reachability repositioning in book mode is + * allowed for letterboxed fullscreen apps in landscape device orientation to + * {@link R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled}. + */ + void resetEnabledAutomaticReachabilityInBookMode() { + mIsAutomaticReachabilityInBookModeEnabled = mContext.getResources().getBoolean( + R.bool.config_letterboxIsAutomaticReachabilityInBookModeEnabled); + } + /* * Gets default horizontal position of the letterboxed app window when horizontal reachability * is enabled. diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 6bffc4c95e64..4d0c7683d621 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -22,6 +22,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FOR import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; +import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA; @@ -38,6 +39,10 @@ import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; import static android.content.pm.ActivityInfo.screenOrientationToString; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.content.res.Configuration.ORIENTATION_UNDEFINED; +import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; +import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; +import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION; import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH; @@ -125,6 +130,14 @@ final class LetterboxUiController { private static final float UNDEFINED_ASPECT_RATIO = 0f; + // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request loop + @VisibleForTesting + static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2; + // Used to determine reset of mSetOrientationRequestCounter if next app requested + // orientation is after timeout value + @VisibleForTesting + static final int SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS = 1000; + private final Point mTmpPoint = new Point(); private final LetterboxConfiguration mLetterboxConfiguration; @@ -163,6 +176,8 @@ final class LetterboxUiController { // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled; + // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED + private final boolean mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled; // Corresponds to OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS private final boolean mIsOverrideEnableCompatFakeFocusEnabled; @@ -187,12 +202,18 @@ final class LetterboxUiController { private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; + // Updated when ActivityRecord#setRequestedOrientation is called + private long mTimeMsLastSetOrientationRequest = 0; + @Configuration.Orientation - private int mInheritedOrientation = Configuration.ORIENTATION_UNDEFINED; + private int mInheritedOrientation = ORIENTATION_UNDEFINED; // The app compat state for the opaque activity if any private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; + // Counter for ActivityRecord#setRequestedOrientation + private int mSetOrientationRequestCounter = 0; + // The CompatDisplayInsets of the opaque activity beneath the translucent one. private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets; @@ -288,6 +309,9 @@ final class LetterboxUiController { mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION); + mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled = + isCompatChangeEnabled( + OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED); mIsOverrideEnableCompatFakeFocusEnabled = isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS); @@ -323,6 +347,10 @@ final class LetterboxUiController { mLetterbox.destroy(); mLetterbox = null; } + if (mLetterboxConfigListener != null) { + mLetterboxConfigListener.onRemoved(); + mLetterboxConfigListener = null; + } } void onMovedToDisplay(int displayId) { @@ -354,35 +382,85 @@ final class LetterboxUiController { * <li>Opt-in component property or per-app override are enabled * <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation} * call from an app or camera compat force rotation treatment is active for the activity. + * <li>Orientation request loop detected and is not letterboxed for fixed orientation * </ul> */ boolean shouldIgnoreRequestedOrientation(@ScreenOrientation int requestedOrientation) { - if (!shouldEnableWithOverrideAndProperty( + if (shouldEnableWithOverrideAndProperty( /* gatingCondition */ mLetterboxConfiguration ::isPolicyForIgnoringRequestedOrientationEnabled, mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled, mBooleanPropertyIgnoreRequestedOrientation)) { - return false; + if (mIsRelauchingAfterRequestedOrientationChanged) { + Slog.w(TAG, "Ignoring orientation update to " + + screenOrientationToString(requestedOrientation) + + " due to relaunching after setRequestedOrientation for " + + mActivityRecord); + return true; + } + DisplayContent displayContent = mActivityRecord.mDisplayContent; + if (displayContent == null) { + return false; + } + if (displayContent.mDisplayRotationCompatPolicy != null + && displayContent.mDisplayRotationCompatPolicy + .isTreatmentEnabledForActivity(mActivityRecord)) { + Slog.w(TAG, "Ignoring orientation update to " + + screenOrientationToString(requestedOrientation) + + " due to camera compat treatment for " + mActivityRecord); + return true; + } } - if (mIsRelauchingAfterRequestedOrientationChanged) { + + if (shouldIgnoreOrientationRequestLoop()) { Slog.w(TAG, "Ignoring orientation update to " + screenOrientationToString(requestedOrientation) - + " due to relaunching after setRequestedOrientation for " + mActivityRecord); + + " as orientation request loop was detected for " + + mActivityRecord); return true; } - DisplayContent displayContent = mActivityRecord.mDisplayContent; - if (displayContent == null) { + return false; + } + + /** + * Whether an app is calling {@link android.app.Activity#setRequestedOrientation} + * in a loop and orientation request should be ignored. + * + * <p>This should only be called once in response to + * {@link android.app.Activity#setRequestedOrientation}. See + * {@link #shouldIgnoreRequestedOrientation} for more details. + * + * <p>This treatment is enabled when the following conditions are met: + * <ul> + * <li>Per-app override is enabled + * <li>App has requested orientation more than 2 times within 1-second + * timer and activity is not letterboxed for fixed orientation + * </ul> + */ + @VisibleForTesting + boolean shouldIgnoreOrientationRequestLoop() { + if (!mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled) { return false; } - if (displayContent.mDisplayRotationCompatPolicy != null - && displayContent.mDisplayRotationCompatPolicy - .isTreatmentEnabledForActivity(mActivityRecord)) { - Slog.w(TAG, "Ignoring orientation update to " - + screenOrientationToString(requestedOrientation) - + " due to camera compat treatment for " + mActivityRecord); - return true; + + final long currTimeMs = System.currentTimeMillis(); + if (currTimeMs - mTimeMsLastSetOrientationRequest + < SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS) { + mSetOrientationRequestCounter += 1; + } else { + // Resets app setOrientationRequest counter if timed out + mSetOrientationRequestCounter = 0; } - return false; + // Update time last called + mTimeMsLastSetOrientationRequest = currTimeMs; + + return mSetOrientationRequestCounter >= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP + && !mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio(); + } + + @VisibleForTesting + int getSetOrientationRequestCounter() { + return mSetOrientationRequestCounter; } /** @@ -749,6 +827,8 @@ final class LetterboxUiController { final Rect innerFrame = hasInheritedLetterboxBehavior() ? mActivityRecord.getBounds() : w.getFrame(); mLetterbox.layout(spaceToFill, innerFrame, mTmpPoint); + // We need to notify Shell that letterbox position has changed. + mActivityRecord.getTask().dispatchTaskInfoChangedIfNeeded(true /* force */); } else if (mLetterbox != null) { mLetterbox.hide(); } @@ -797,13 +877,18 @@ final class LetterboxUiController { float getHorizontalPositionMultiplier(Configuration parentConfiguration) { // Don't check resolved configuration because it may not be updated yet during // configuration change. - boolean bookMode = isDisplayFullScreenAndInPosture( - DeviceStateController.DeviceState.HALF_FOLDED, false /* isTabletop */); + boolean bookModeEnabled = isFullScreenAndBookModeEnabled(); return isHorizontalReachabilityEnabled(parentConfiguration) // Using the last global dynamic position to avoid "jumps" when moving // between apps or activities. - ? mLetterboxConfiguration.getHorizontalMultiplierForReachability(bookMode) - : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(bookMode); + ? mLetterboxConfiguration.getHorizontalMultiplierForReachability(bookModeEnabled) + : mLetterboxConfiguration.getLetterboxHorizontalPositionMultiplier(bookModeEnabled); + } + + private boolean isFullScreenAndBookModeEnabled() { + return isDisplayFullScreenAndInPosture( + DeviceStateController.DeviceState.HALF_FOLDED, false /* isTabletop */) + && mLetterboxConfiguration.getIsAutomaticReachabilityInBookModeEnabled(); } float getVerticalPositionMultiplier(Configuration parentConfiguration) { @@ -818,12 +903,14 @@ final class LetterboxUiController { : mLetterboxConfiguration.getLetterboxVerticalPositionMultiplier(tabletopMode); } - float getFixedOrientationLetterboxAspectRatio() { + float getFixedOrientationLetterboxAspectRatio(@NonNull Configuration parentConfiguration) { + // Don't resize to split screen size when half folded if letterbox position is centered return isDisplayFullScreenAndSeparatingHinge() - ? getSplitScreenAspectRatio() - : mActivityRecord.shouldCreateCompatDisplayInsets() - ? getDefaultMinAspectRatioForUnresizableApps() - : getDefaultMinAspectRatio(); + && getHorizontalPositionMultiplier(parentConfiguration) != 0.5f + ? getSplitScreenAspectRatio() + : mActivityRecord.shouldCreateCompatDisplayInsets() + ? getDefaultMinAspectRatioForUnresizableApps() + : getDefaultMinAspectRatio(); } private float getDefaultMinAspectRatioForUnresizableApps() { @@ -874,6 +961,20 @@ final class LetterboxUiController { return mActivityRecord.mWmService.mContext.getResources(); } + @LetterboxConfiguration.LetterboxVerticalReachabilityPosition + int getLetterboxPositionForVerticalReachability() { + final boolean isInFullScreenTabletopMode = isDisplayFullScreenAndSeparatingHinge(); + return mLetterboxConfiguration.getLetterboxPositionForVerticalReachability( + isInFullScreenTabletopMode); + } + + @LetterboxConfiguration.LetterboxHorizontalReachabilityPosition + int getLetterboxPositionForHorizontalReachability() { + final boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge(); + return mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability( + isInFullScreenBookMode); + } + @VisibleForTesting void handleHorizontalDoubleTap(int x) { if (!isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) { @@ -885,7 +986,8 @@ final class LetterboxUiController { return; } - boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge(); + boolean isInFullScreenBookMode = isDisplayFullScreenAndSeparatingHinge() + && mLetterboxConfiguration.getIsAutomaticReachabilityInBookModeEnabled(); int letterboxPositionForHorizontalReachability = mLetterboxConfiguration .getLetterboxPositionForHorizontalReachability(isInFullScreenBookMode); if (mLetterbox.getInnerFrame().left > x) { @@ -965,6 +1067,8 @@ final class LetterboxUiController { * </ul> */ private boolean isHorizontalReachabilityEnabled(Configuration parentConfiguration) { + // Use screen resolved bounds which uses resolved bounds or size compat bounds + // as activity bounds can sometimes be empty return mLetterboxConfiguration.getIsHorizontalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FULLSCREEN @@ -972,7 +1076,7 @@ final class LetterboxUiController { && mActivityRecord.getOrientationForReachability() == ORIENTATION_PORTRAIT) // Check whether the activity fills the parent vertically. && parentConfiguration.windowConfiguration.getAppBounds().height() - <= mActivityRecord.getBounds().height(); + <= mActivityRecord.getScreenResolvedBounds().height(); } @VisibleForTesting @@ -980,6 +1084,10 @@ final class LetterboxUiController { return isHorizontalReachabilityEnabled(mActivityRecord.getParent().getConfiguration()); } + boolean isLetterboxDoubleTapEducationEnabled() { + return isHorizontalReachabilityEnabled() || isVerticalReachabilityEnabled(); + } + /** * Whether vertical reachability is enabled for an activity in the current configuration. * @@ -992,6 +1100,8 @@ final class LetterboxUiController { * </ul> */ private boolean isVerticalReachabilityEnabled(Configuration parentConfiguration) { + // Use screen resolved bounds which uses resolved bounds or size compat bounds + // as activity bounds can sometimes be empty return mLetterboxConfiguration.getIsVerticalReachabilityEnabled() && parentConfiguration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_FULLSCREEN @@ -999,7 +1109,7 @@ final class LetterboxUiController { && mActivityRecord.getOrientationForReachability() == ORIENTATION_LANDSCAPE) // Check whether the activity fills the parent horizontally. && parentConfiguration.windowConfiguration.getBounds().width() - == mActivityRecord.getBounds().width(); + == mActivityRecord.getScreenResolvedBounds().width(); } @VisibleForTesting @@ -1415,7 +1525,8 @@ final class LetterboxUiController { mLetterboxConfigListener = WindowContainer.overrideConfigurationPropagation( mActivityRecord, firstOpaqueActivityBeneath, (opaqueConfig, transparentConfig) -> { - final Configuration mutatedConfiguration = new Configuration(); + final Configuration mutatedConfiguration = + fromOriginalTranslucentConfig(transparentConfig); final Rect parentBounds = parent.getWindowConfiguration().getBounds(); final Rect bounds = mutatedConfiguration.windowConfiguration.getBounds(); final Rect letterboxBounds = opaqueConfig.windowConfiguration.getBounds(); @@ -1477,6 +1588,10 @@ final class LetterboxUiController { return mInheritedCompatDisplayInsets; } + void clearInheritedCompatDisplayInsets() { + mInheritedCompatDisplayInsets = null; + } + /** * In case of translucent activities, it consumes the {@link ActivityRecord} of the first opaque * activity beneath using the given consumer and returns {@code true}. @@ -1503,6 +1618,22 @@ final class LetterboxUiController { true /* traverseTopToBottom */)); } + // When overriding translucent activities configuration we need to keep some of the + // original properties + private Configuration fromOriginalTranslucentConfig(Configuration translucentConfig) { + final Configuration configuration = new Configuration(translucentConfig); + // The values for the following properties will be defined during the configuration + // resolution in {@link ActivityRecord#resolveOverrideConfiguration} using the + // properties inherited from the first not finishing opaque activity beneath. + configuration.orientation = ORIENTATION_UNDEFINED; + configuration.screenWidthDp = configuration.compatScreenWidthDp = SCREEN_WIDTH_DP_UNDEFINED; + configuration.screenHeightDp = + configuration.compatScreenHeightDp = SCREEN_HEIGHT_DP_UNDEFINED; + configuration.smallestScreenWidthDp = + configuration.compatSmallestScreenWidthDp = SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; + return configuration; + } + private void inheritConfiguration(ActivityRecord firstOpaque) { // To avoid wrong behaviour, we're not forcing a specific aspect ratio to activities // which are not already providing one (e.g. permission dialogs) and presumably also @@ -1522,7 +1653,7 @@ final class LetterboxUiController { mLetterboxConfigListener = null; mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO; mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO; - mInheritedOrientation = Configuration.ORIENTATION_UNDEFINED; + mInheritedOrientation = ORIENTATION_UNDEFINED; mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN; mInheritedCompatDisplayInsets = null; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 18d6dea927c1..aed876d4a5b3 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3479,6 +3479,25 @@ class Task extends TaskFragment { info.isFocused = isFocused(); info.isVisible = hasVisibleChildren(); info.isSleeping = shouldSleepActivities(); + info.isLetterboxDoubleTapEnabled = top != null + && top.mLetterboxUiController.isLetterboxDoubleTapEducationEnabled(); + info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; + info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; + info.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET; + info.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET; + if (info.isLetterboxDoubleTapEnabled) { + info.topActivityLetterboxWidth = top.getBounds().width(); + info.topActivityLetterboxHeight = top.getBounds().height(); + if (info.topActivityLetterboxWidth < info.topActivityLetterboxHeight) { + // Pillarboxed + info.topActivityLetterboxHorizontalPosition = + top.mLetterboxUiController.getLetterboxPositionForHorizontalReachability(); + } else { + // Letterboxed + info.topActivityLetterboxVerticalPosition = + top.mLetterboxUiController.getLetterboxPositionForVerticalReachability(); + } + } } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index a06d84c44f17..adf5310bb97c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -942,6 +942,10 @@ public class WindowManagerShellCommand extends ShellCommand { runSetBooleanFlag(pw, mLetterboxConfiguration ::setIsVerticalReachabilityEnabled); break; + case "--isAutomaticReachabilityInBookModeEnabled": + runSetBooleanFlag(pw, mLetterboxConfiguration + ::setIsAutomaticReachabilityInBookModeEnabled); + break; case "--defaultPositionForHorizontalReachability": runSetLetterboxDefaultPositionForHorizontalReachability(pw); break; @@ -1144,6 +1148,7 @@ public class WindowManagerShellCommand extends ShellCommand { mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier(); mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled(); mLetterboxConfiguration.resetIsVerticalReachabilityEnabled(); + mLetterboxConfiguration.resetEnabledAutomaticReachabilityInBookMode(); mLetterboxConfiguration.resetDefaultPositionForHorizontalReachability(); mLetterboxConfiguration.resetDefaultPositionForVerticalReachability(); mLetterboxConfiguration.resetIsEducationEnabled(); @@ -1179,6 +1184,8 @@ public class WindowManagerShellCommand extends ShellCommand { + mLetterboxConfiguration.getIsHorizontalReachabilityEnabled()); pw.println("Is vertical reachability enabled: " + mLetterboxConfiguration.getIsVerticalReachabilityEnabled()); + pw.println("Is automatic reachability in book mode enabled: " + + mLetterboxConfiguration.getIsAutomaticReachabilityInBookModeEnabled()); pw.println("Default position for horizontal reachability: " + LetterboxConfiguration.letterboxHorizontalReachabilityPositionToString( mLetterboxConfiguration.getDefaultPositionForHorizontalReachability())); diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java index 30ec1632a622..881d1b3d581c 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java @@ -18,6 +18,7 @@ package com.android.server.accounts; import static android.database.sqlite.SQLiteDatabase.deleteDatabase; +import static org.mockito.ArgumentMatchers.contains; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; @@ -708,6 +709,41 @@ public class AccountManagerServiceTest extends AndroidTestCase { } @SmallTest + public void testStartAddAccountSessionWhereAuthenticatorReturnsIntentWithProhibitedFlags() + throws Exception { + unlockSystemUser(); + ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.activityInfo = new ActivityInfo(); + resolveInfo.activityInfo.applicationInfo = new ApplicationInfo(); + when(mMockPackageManager.resolveActivityAsUser( + any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo); + when(mMockPackageManager.checkSignatures( + anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH); + + final CountDownLatch latch = new CountDownLatch(1); + Response response = new Response(latch, mMockAccountManagerResponse); + Bundle options = createOptionsWithAccountName( + AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE); + int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION + | Intent.FLAG_GRANT_WRITE_URI_PERMISSION + | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION + | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; + options.putInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, prohibitedFlags); + + mAms.startAddAccountSession( + response, // response + AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType + "authTokenType", + null, // requiredFeatures + true, // expectActivityLaunch + options); // optionsIn + waitForLatch(latch); + + verify(mMockAccountManagerResponse).onError( + eq(AccountManager.ERROR_CODE_INVALID_RESPONSE), contains("invalid intent")); + } + + @SmallTest public void testStartAddAccountSessionError() throws Exception { unlockSystemUser(); Bundle options = createOptionsWithAccountName( diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java index 73f30d9f9e79..b98a6a891d55 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java +++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java @@ -17,9 +17,6 @@ package com.android.server.accounts; import android.accounts.Account; -import java.util.ArrayList; -import java.util.List; - /** * Constants shared between test AccountAuthenticators and AccountManagerServiceTest. */ @@ -31,6 +28,8 @@ public final class AccountManagerServiceTestFixtures { "account_manager_service_test:account_status_token_key"; public static final String KEY_ACCOUNT_PASSWORD = "account_manager_service_test:account_password_key"; + public static final String KEY_INTENT_FLAGS = + "account_manager_service_test:intent_flags_key"; public static final String KEY_OPTIONS_BUNDLE = "account_manager_service_test:option_bundle_key"; public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com"; diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java index 8106364477d9..924443e9d5cf 100644 --- a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java +++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java @@ -24,8 +24,6 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; -import com.android.frameworks.servicestests.R; - import java.util.concurrent.atomic.AtomicInteger; /** @@ -270,11 +268,13 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator String accountName = null; Bundle sessionBundle = null; String password = null; + int intentFlags = 0; if (options != null) { accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME); sessionBundle = options.getBundle( AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE); password = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD); + intentFlags = options.getInt(AccountManagerServiceTestFixtures.KEY_INTENT_FLAGS, 0); } Bundle result = new Bundle(); @@ -302,6 +302,7 @@ public class TestAccountType1Authenticator extends AbstractAccountAuthenticator intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT, eventualActivityResultData); intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response); + intent.setFlags(intentFlags); result.putParcelable(AccountManager.KEY_INTENT, intent); } else { diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java index 428eaff9e5bc..dea31d764522 100644 --- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java @@ -56,7 +56,9 @@ public class SpatializerHelperTest { mSpyAudioSystem = spy(new NoOpAudioSystemAdapter()); mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem, - false /*headTrackingEnabledByDefault*/); + true /*binauralEnabledDefault*/, + true /*transauralEnabledDefault*/, + false /*headTrackingEnabledDefault*/); } /** 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 ff37564f46a4..58f3db959afe 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java @@ -1905,7 +1905,7 @@ public class DisplayModeDirectorTest { // We don't expect any interaction with DeviceConfig when the director is initialized // because we explicitly avoid doing this as this can lead to a latency spike in the // startup of DisplayManagerService - // Verify all the loaded values are from DisplayDeviceConfig + // Verify all the loaded values are from config.xml assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 45, 0.0); assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 75, 0.0); @@ -1937,6 +1937,7 @@ public class DisplayModeDirectorTest { when(displayDeviceConfig.getDefaultRefreshRateInHbmSunlight()).thenReturn(75); director.defaultDisplayDeviceUpdated(displayDeviceConfig); + // Verify the new values are from the freshly loaded DisplayDeviceConfig. assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0); assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 65, 0.0); @@ -1966,6 +1967,7 @@ public class DisplayModeDirectorTest { config.setRefreshRateInHbmSunlight(80); director.defaultDisplayDeviceUpdated(displayDeviceConfig); + // Verify the values are loaded from the DeviceConfig. assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0); assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 60, 0.0); @@ -1981,6 +1983,35 @@ public class DisplayModeDirectorTest { new int[]{20}); assertEquals(director.getHbmObserver().getRefreshRateInHbmHdr(), 70); assertEquals(director.getHbmObserver().getRefreshRateInHbmSunlight(), 80); + + // Reset the DeviceConfig + config.setDefaultPeakRefreshRate(null); + config.setRefreshRateInHighZone(null); + config.setRefreshRateInLowZone(null); + config.setLowAmbientBrightnessThresholds(new int[]{}); + config.setLowDisplayBrightnessThresholds(new int[]{}); + config.setHighDisplayBrightnessThresholds(new int[]{}); + config.setHighAmbientBrightnessThresholds(new int[]{}); + config.setRefreshRateInHbmHdr(null); + config.setRefreshRateInHbmSunlight(null); + waitForIdleSync(); + + // verify the new values now fallback to DisplayDeviceConfig + assertEquals(director.getSettingsObserver().getDefaultRefreshRate(), 60, 0.0); + assertEquals(director.getSettingsObserver().getDefaultPeakRefreshRate(), 65, + 0.0); + assertEquals(director.getBrightnessObserver().getRefreshRateInHighZone(), 55); + assertEquals(director.getBrightnessObserver().getRefreshRateInLowZone(), 50); + assertArrayEquals(director.getBrightnessObserver().getHighDisplayBrightnessThreshold(), + new int[]{210}); + assertArrayEquals(director.getBrightnessObserver().getHighAmbientBrightnessThreshold(), + new int[]{2100}); + assertArrayEquals(director.getBrightnessObserver().getLowDisplayBrightnessThreshold(), + new int[]{25}); + assertArrayEquals(director.getBrightnessObserver().getLowAmbientBrightnessThreshold(), + new int[]{30}); + assertEquals(director.getHbmObserver().getRefreshRateInHbmHdr(), 65); + assertEquals(director.getHbmObserver().getRefreshRateInHbmSunlight(), 75); } @Test @@ -2140,18 +2171,18 @@ public class DisplayModeDirectorTest { super.addOnPropertiesChangedListener(namespace, executor, listener); } - void setRefreshRateInLowZone(int fps) { + void setRefreshRateInLowZone(Integer fps) { putPropertyAndNotify( DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE, String.valueOf(fps)); } - void setRefreshRateInHbmSunlight(int fps) { + void setRefreshRateInHbmSunlight(Integer fps) { putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, String.valueOf(fps)); } - void setRefreshRateInHbmHdr(int fps) { + void setRefreshRateInHbmHdr(Integer fps) { putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps)); } @@ -2187,13 +2218,13 @@ public class DisplayModeDirectorTest { thresholds); } - void setRefreshRateInHighZone(int fps) { + void setRefreshRateInHighZone(Integer fps) { putPropertyAndNotify( DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE, String.valueOf(fps)); } - void setDefaultPeakRefreshRate(int fps) { + void setDefaultPeakRefreshRate(Integer fps) { putPropertyAndNotify( DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_PEAK_REFRESH_RATE_DEFAULT, String.valueOf(fps)); diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java index b921838e0bfc..4c0361d30d67 100644 --- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java +++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java @@ -263,7 +263,7 @@ public class ShortcutManagerTestUtils { + instrumentation.getContext().getUserId() + " " + RoleManager.ROLE_HOME + " " + packageName + " 0"); waitUntil("Failed to get shortcut access", - () -> hasShortcutAccess(instrumentation, packageName), 20); + () -> hasShortcutAccess(instrumentation, packageName), 60); } public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 99a361c03a2a..874846d333cf 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -4359,6 +4359,43 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertFalse(posted.getNotification().extras .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); + assertFalse(posted.getNotification().extras + .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); + assertFalse(posted.getNotification().extras + .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); + } + + @Test + public void testCustomMediaStyleRemote_noPermission() throws RemoteException { + String deviceName = "device"; + when(mPackageManager.checkPermission( + eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt())) + .thenReturn(PERMISSION_DENIED); + Notification.DecoratedMediaCustomViewStyle style = + new Notification.DecoratedMediaCustomViewStyle(); + style.setRemotePlaybackInfo(deviceName, 0, null); + Notification.Builder nb = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setStyle(style); + + StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, + "testCustomMediaStyleRemoteNoPermission", mUid, 0, + nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(), + nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); + waitForIdle(); + + NotificationRecord posted = mService.findNotificationLocked( + PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); + + assertFalse(posted.getNotification().extras + .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); + assertFalse(posted.getNotification().extras + .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); + assertFalse(posted.getNotification().extras + .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java index ed2b0a36cd5c..26d2a46f768a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java @@ -17,6 +17,8 @@ package com.android.server.wm; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; @@ -748,7 +750,7 @@ public class DisplayRotationTests { // ... until half-fold mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED); assertTrue(waitForUiHandler()); - verify(sMockWm).updateRotation(false, false); + verify(sMockWm).updateRotation(anyBoolean(), anyBoolean()); assertTrue(waitForUiHandler()); assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation( SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); @@ -756,7 +758,7 @@ public class DisplayRotationTests { // ... then transition back to flat mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN); assertTrue(waitForUiHandler()); - verify(sMockWm, atLeast(1)).updateRotation(false, false); + verify(sMockWm, atLeast(1)).updateRotation(anyBoolean(), anyBoolean()); assertTrue(waitForUiHandler()); assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); @@ -824,6 +826,23 @@ public class DisplayRotationTests { } @Test + public void testIgnoresDeskDockRotation_whenNoSensorAndLockedRespected() throws Exception { + mBuilder.setDeskDockRotation(Surface.ROTATION_270).build(); + when(mMockDisplayPolicy.isDeskDockRespectsNoSensorAndLockedWithoutAccelerometer()) + .thenReturn(true); + configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); + + when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_DESK); + + freezeRotation(Surface.ROTATION_90); + + assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_LOCKED, Surface.ROTATION_90)); + assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation( + SCREEN_ORIENTATION_NOSENSOR, Surface.ROTATION_90)); + } + + @Test public void testReturnsUserRotation_FixedToUserRotation_IgnoreIncompatibleAppRequest() throws Exception { mBuilder.build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index 693f1ced78dd..23a3d520ea3e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FOR import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH; import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS; +import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED; import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION; import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE; import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA; @@ -46,6 +47,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wm.LetterboxUiController.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; +import static com.android.server.wm.LetterboxUiController.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -185,6 +188,69 @@ public class LetterboxUiControllerTest extends WindowTestsBase { } @Test + public void testShouldIgnoreOrientationRequestLoop_overrideDisabled_returnsFalse() { + doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio(); + // Request 3 times to simulate orientation request loop + for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) { + assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false, + /* expectedCount */ 0); + } + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED}) + public void testShouldIgnoreOrientationRequestLoop_isLetterboxed_returnsFalse() { + doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio(); + // Request 3 times to simulate orientation request loop + for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) { + assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false, + /* expectedCount */ i); + } + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED}) + public void testShouldIgnoreOrientationRequestLoop_noLoop_returnsFalse() { + doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio(); + // No orientation request loop + assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false, + /* expectedCount */ 0); + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED}) + public void testShouldIgnoreOrientationRequestLoop_timeout_returnsFalse() + throws InterruptedException { + doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio(); + for (int i = MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i > 0; i--) { + assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false, + /* expectedCount */ 0); + Thread.sleep(SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS); + } + } + + @Test + @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED}) + public void testShouldIgnoreOrientationRequestLoop_returnsTrue() { + doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio(); + for (int i = 0; i < MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) { + assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false, + /* expectedCount */ i); + } + assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ true, + /* expectedCount */ MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP); + } + + private void assertShouldIgnoreOrientationRequestLoop(boolean shouldIgnore, int expectedCount) { + if (shouldIgnore) { + assertTrue(mController.shouldIgnoreOrientationRequestLoop()); + } else { + assertFalse(mController.shouldIgnoreOrientationRequestLoop()); + } + assertEquals(expectedCount, mController.getSetOrientationRequestCounter()); + } + + @Test @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH}) public void testShouldIgnoreRequestedOrientation_flagIsDisabled_returnsFalse() { prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 75d65b3a3f8f..4a3f46a567d1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; @@ -51,6 +52,7 @@ import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANG import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED; import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE; +import static com.android.server.wm.ActivityRecord.State.DESTROYED; import static com.android.server.wm.ActivityRecord.State.PAUSED; import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; import static com.android.server.wm.ActivityRecord.State.RESUMED; @@ -63,6 +65,8 @@ import static com.google.common.truth.Truth.assertThat; 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.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -170,6 +174,26 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + public void testCleanLetterboxConfigListenerWhenTranslucentIsDestroyed() { + mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); + setUpDisplaySizeWithApp(2000, 1000); + prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + // Translucent Activity + final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) + .setLaunchedFromUid(mActivity.getUid()) + .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) + .build(); + doReturn(false).when(translucentActivity).fillsParent(); + mTask.addChild(translucentActivity); + + translucentActivity.setState(DESTROYED, "testing"); + translucentActivity.removeImmediately(); + + assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); + } + + @Test public void testHorizontalReachabilityEnabledForTranslucentActivities() { setUpDisplaySizeWithApp(2500, 1000); mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); @@ -349,6 +373,33 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + public void testApplyStrategyToTranslucentActivitiesRetainsWindowConfigurationProperties() { + mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); + setUpDisplaySizeWithApp(2000, 1000); + prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + // Translucent Activity + final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) + .setLaunchedFromUid(mActivity.getUid()) + .build(); + doReturn(false).when(translucentActivity).fillsParent(); + WindowConfiguration translucentWinConf = translucentActivity.getWindowConfiguration(); + translucentActivity.setActivityType(ACTIVITY_TYPE_STANDARD); + translucentActivity.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + translucentActivity.setDisplayWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + translucentActivity.setAlwaysOnTop(true); + + mTask.addChild(translucentActivity); + + // We check the WIndowConfiguration properties + translucentWinConf = translucentActivity.getWindowConfiguration(); + assertEquals(ACTIVITY_TYPE_STANDARD, translucentActivity.getActivityType()); + assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getWindowingMode()); + assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getDisplayWindowingMode()); + assertTrue(translucentWinConf.isAlwaysOnTop()); + } + + @Test public void testApplyStrategyToMultipleTranslucentActivities() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); setUpDisplaySizeWithApp(2000, 1000); @@ -397,7 +448,7 @@ public class SizeCompatTests extends WindowTestsBase { .setLaunchedFromUid(mActivity.getUid()) .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) .build(); - doReturn(true).when(translucentActivity).fillsParent(); + doReturn(false).when(translucentActivity).fillsParent(); mTask.addChild(translucentActivity); // It should not be in SCM assertFalse(translucentActivity.inSizeCompatMode()); @@ -458,6 +509,33 @@ public class SizeCompatTests extends WindowTestsBase { } @Test + public void testTranslucentActivity_clearSizeCompatMode_inheritedCompatDisplayInsetsCleared() { + mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); + setUpDisplaySizeWithApp(2800, 1400); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); + // Rotate to put activity in size compat mode. + rotateDisplay(mActivity.mDisplayContent, ROTATION_90); + assertTrue(mActivity.inSizeCompatMode()); + + // We launch a transparent activity + final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) + .setLaunchedFromUid(mActivity.getUid()) + .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) + .build(); + doReturn(false).when(translucentActivity).fillsParent(); + mTask.addChild(translucentActivity); + + // The transparent activity inherits the compat display insets of the opaque activity + // beneath it + assertNotNull(translucentActivity.getCompatDisplayInsets()); + + // Clearing SCM should also clear the inherited compat display insets + translucentActivity.clearSizeCompatMode(); + assertNull(translucentActivity.getCompatDisplayInsets()); + } + + @Test public void testRestartProcessIfVisible() { setUpDisplaySizeWithApp(1000, 2500); doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity); @@ -3049,12 +3127,44 @@ public class SizeCompatTests extends WindowTestsBase { assertTrue(mActivity.inSizeCompatMode()); // Vertical reachability is disabled because the app does not match parent width - assertNotEquals(mActivity.getBounds().width(), mActivity.mDisplayContent.getBounds() - .width()); + assertNotEquals(mActivity.getScreenResolvedBounds().width(), + mActivity.mDisplayContent.getBounds().width()); assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); } @Test + public void testIsVerticalReachabilityEnabled_emptyBounds_true() { + setUpDisplaySizeWithApp(/* dw */ 1000, /* dh */ 2800); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); + + prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); + + // Set up activity with empty bounds to mock loading of app + mActivity.getWindowConfiguration().setBounds(null); + assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); + + // Vertical reachability is still enabled as resolved bounds is not empty + assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); + } + + @Test + public void testIsHorizontalReachabilityEnabled_emptyBounds_true() { + setUpDisplaySizeWithApp(/* dw */ 2800, /* dh */ 1000); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true); + + prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); + + // Set up activity with empty bounds to mock loading of app + mActivity.getWindowConfiguration().setBounds(null); + assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); + + // Horizontal reachability is still enabled as resolved bounds is not empty + assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); + } + + @Test public void testIsHorizontalReachabilityEnabled_doesNotMatchParentHeight_false() { setUpDisplaySizeWithApp(2800, 1000); mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); @@ -3070,8 +3180,8 @@ public class SizeCompatTests extends WindowTestsBase { assertTrue(mActivity.inSizeCompatMode()); // Horizontal reachability is disabled because the app does not match parent height - assertNotEquals(mActivity.getBounds().height(), mActivity.mDisplayContent.getBounds() - .height()); + assertNotEquals(mActivity.getScreenResolvedBounds().height(), + mActivity.mDisplayContent.getBounds().height()); assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); } @@ -3091,8 +3201,8 @@ public class SizeCompatTests extends WindowTestsBase { assertTrue(mActivity.inSizeCompatMode()); // Horizontal reachability is enabled because the app matches parent height - assertEquals(mActivity.getBounds().height(), mActivity.mDisplayContent.getBounds() - .height()); + assertEquals(mActivity.getScreenResolvedBounds().height(), + mActivity.mDisplayContent.getBounds().height()); assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); } @@ -3112,7 +3222,8 @@ public class SizeCompatTests extends WindowTestsBase { assertTrue(mActivity.inSizeCompatMode()); // Vertical reachability is enabled because the app matches parent width - assertEquals(mActivity.getBounds().width(), mActivity.mDisplayContent.getBounds().width()); + assertEquals(mActivity.getScreenResolvedBounds().width(), + mActivity.mDisplayContent.getBounds().width()); assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); } @@ -3636,7 +3747,6 @@ public class SizeCompatTests extends WindowTestsBase { @Test public void testUpdateResolvedBoundsVerticalPosition_tabletop() { - // Set up a display in portrait with a fixed-orientation LANDSCAPE app setUpDisplaySizeWithApp(1400, 2800); mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); @@ -3658,16 +3768,15 @@ public class SizeCompatTests extends WindowTestsBase { setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */); assertEquals(letterboxNoFold, mActivity.getBounds()); - } @Test - public void testUpdateResolvedBoundsHorizontalPosition_book() { - + public void testUpdateResolvedBoundsHorizontalPosition_bookModeEnabled() { // Set up a display in landscape with a fixed-orientation PORTRAIT app setUpDisplaySizeWithApp(2800, 1400); mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); - mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( + mWm.mLetterboxConfiguration.setIsAutomaticReachabilityInBookModeEnabled(true); + mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 1.0f /*letterboxVerticalPositionMultiplier*/); prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); @@ -3685,7 +3794,28 @@ public class SizeCompatTests extends WindowTestsBase { setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */); assertEquals(letterboxNoFold, mActivity.getBounds()); + } + @Test + public void testUpdateResolvedBoundsHorizontalPosition_bookModeDisabled_centered() { + // Set up a display in landscape with a fixed-orientation PORTRAIT app + setUpDisplaySizeWithApp(2800, 1400); + mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); + mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f); + prepareUnresizable(mActivity, 1.75f, SCREEN_ORIENTATION_PORTRAIT); + + Rect letterboxNoFold = new Rect(1000, 0, 1800, 1400); + assertEquals(letterboxNoFold, mActivity.getBounds()); + + // Make the activity full-screen + mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + + // Stay centered and bounds don't change + setFoldablePosture(true /* isHalfFolded */, false /* isTabletop */); + assertEquals(letterboxNoFold, mActivity.getBounds()); + + setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */); + assertEquals(letterboxNoFold, mActivity.getBounds()); } private void setFoldablePosture(ActivityRecord activity, boolean isHalfFolded, diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java index c35d90f4a495..f7b66a26ff68 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java @@ -34,10 +34,13 @@ import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENT import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__NORMAL_DETECTOR; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP; import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_KEYPHRASE_TRIGGERED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE; +import static com.android.internal.util.LatencyTracker.ACTION_SHOW_VOICE_INTERACTION; +import android.content.Context; import android.service.voice.HotwordDetector; import com.android.internal.util.FrameworkStatsLog; +import com.android.internal.util.LatencyTracker; /** * A utility class for logging hotword statistics event. @@ -116,6 +119,46 @@ public final class HotwordMetricsLogger { metricsDetectorType, event, uid, streamSizeBytes, bundleSizeBytes, streamCount); } + /** + * Starts a {@link LatencyTracker} log for the time it takes to show the + * {@link android.service.voice.VoiceInteractionSession} system UI after a voice trigger. + * + * @see LatencyTracker + * + * @param tag Extra tag to separate different sessions from each other. + */ + public static void startHotwordTriggerToUiLatencySession(Context context, String tag) { + LatencyTracker.getInstance(context).onActionStart(ACTION_SHOW_VOICE_INTERACTION, tag); + } + + /** + * Completes a {@link LatencyTracker} log for the time it takes to show the + * {@link android.service.voice.VoiceInteractionSession} system UI after a voice trigger. + * + * <p>Completing this session will result in logging metric data.</p> + * + * @see LatencyTracker + */ + public static void stopHotwordTriggerToUiLatencySession(Context context) { + LatencyTracker.getInstance(context).onActionEnd(ACTION_SHOW_VOICE_INTERACTION); + } + + /** + * Cancels a {@link LatencyTracker} log for the time it takes to show the + * {@link android.service.voice.VoiceInteractionSession} system UI after a voice trigger. + * + * <p>Cancels typically occur when the VoiceInteraction session UI is shown for reasons outside + * of a {@link android.hardware.soundtrigger.SoundTrigger.RecognitionEvent} such as an + * invocation from an external source or service.</p> + * + * <p>Canceling this session will not result in logging metric data. + * + * @see LatencyTracker + */ + public static void cancelHotwordTriggerToUiLatencySession(Context context) { + LatencyTracker.getInstance(context).onActionCancel(ACTION_SHOW_VOICE_INTERACTION); + } + private static int getCreateMetricsDetectorType(int detectorType) { switch (detectorType) { case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE: diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index bc5c9ec7a29c..56351202564c 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -95,7 +95,6 @@ import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; -import com.android.internal.util.LatencyTracker; import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -404,6 +403,10 @@ public class VoiceInteractionManagerService extends SystemService { final int callingUid = Binder.getCallingUid(); final long caller = Binder.clearCallingIdentity(); try { + // HotwordDetector trigger uses VoiceInteractionService#showSession + // We need to cancel here because UI is not being shown due to a SoundTrigger + // HAL event. + HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext); mImpl.showSessionLocked(options, VoiceInteractionSession.SHOW_SOURCE_ACTIVITY, new IVoiceInteractionSessionShowCallback.Stub() { @@ -954,6 +957,13 @@ public class VoiceInteractionManagerService extends SystemService { Slog.w(TAG, "showSessionFromSession without running voice interaction service"); return false; } + // If the token is null, then the request to show the session is not coming from + // the active VoiceInteractionService session. + // We need to cancel here because UI is not being shown due to a SoundTrigger + // HAL event. + if (token == null) { + HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext); + } final long caller = Binder.clearCallingIdentity(); try { return mImpl.showSessionLocked(sessionArgs, flags, null, null); @@ -1718,6 +1728,11 @@ public class VoiceInteractionManagerService extends SystemService { final long caller = Binder.clearCallingIdentity(); try { + // HotwordDetector trigger uses VoiceInteractionService#showSession + // We need to cancel here because UI is not being shown due to a SoundTrigger + // HAL event. + HotwordMetricsLogger.cancelHotwordTriggerToUiLatencySession(mContext); + return mImpl.showSessionLocked(args, sourceFlags | VoiceInteractionSession.SHOW_WITH_ASSIST @@ -2361,8 +2376,11 @@ public class VoiceInteractionManagerService extends SystemService { public void onVoiceSessionWindowVisibilityChanged(boolean visible) throws RemoteException { if (visible) { - LatencyTracker.getInstance(mContext) - .onActionEnd(LatencyTracker.ACTION_SHOW_VOICE_INTERACTION); + // The AlwaysOnHotwordDetector trigger latency is always completed here even + // if the reason the window was shown was not due to a SoundTrigger HAL + // event. It is expected that the latency will be canceled if shown for + // other invocation reasons, and this call becomes a noop. + HotwordMetricsLogger.stopHotwordTriggerToUiLatencySession(mContext); } } |