diff options
243 files changed, 4963 insertions, 2897 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 9abb308534df..2fd2e33bbc37 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -9,6 +9,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp core/jni/ libs/input/ services/core/jni/ + services/incremental/ [Hook Scripts] checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp index 5cdcdd335a12..2eb7e99a9dab 100644 --- a/apex/permission/service/Android.bp +++ b/apex/permission/service/Android.bp @@ -48,5 +48,5 @@ java_library { name: "service-permission-stubs", srcs: [":service-permission-stubs-srcs"], defaults: ["service-module-stubs-defaults"], - visibility: ["//visibility:private"] + visibility: ["//frameworks/base/services/core"] } diff --git a/api/test-current.txt b/api/test-current.txt index 4eeaaf87ea0d..e289284c5cd6 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1504,6 +1504,13 @@ package android.media { ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String); } + public class AudioSystem { + method public static float getMasterBalance(); + method public static final int getNumStreamTypes(); + method public static int setMasterBalance(float); + field public static final int STREAM_DEFAULT = -1; // 0xffffffff + } + public static final class AudioTrack.MetricsConstants { field public static final String ATTRIBUTES = "android.media.audiotrack.attributes"; field public static final String CHANNEL_MASK = "android.media.audiotrack.channelMask"; @@ -3522,6 +3529,32 @@ package android.service.textclassifier { } +package android.service.watchdog { + + public abstract class ExplicitHealthCheckService extends android.app.Service { + ctor public ExplicitHealthCheckService(); + method public final void notifyHealthCheckPassed(@NonNull String); + method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); + method public abstract void onCancelHealthCheck(@NonNull String); + method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages(); + method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages(); + method public abstract void onRequestHealthCheck(@NonNull String); + method public void setCallback(@Nullable android.os.RemoteCallback); + field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"; + field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService"; + } + + public static final class ExplicitHealthCheckService.PackageConfig implements android.os.Parcelable { + ctor public ExplicitHealthCheckService.PackageConfig(@NonNull String, long); + method public int describeContents(); + method public long getHealthCheckTimeoutMillis(); + method @NonNull public String getPackageName(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> CREATOR; + } + +} + package android.telecom { public final class Call { diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index c7dbf7765286..bd15264c008f 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -8697,13 +8697,12 @@ message RuntimeAppOpAccess { // Name of the package accessing app op optional string package_name = 2; - // operation string id per OPSTR_ constants in AppOpsManager.java - optional string op = 3; + // deprecated - set to empty string + optional string op_deprecated = 3 [deprecated = true]; // attribution_tag; provided by developer when accessing related API, limited at 50 chars by - // API. - // Attributions must be provided through manifest using <attribution> tag available in R and - // above. + // API. Attributions must be provided through manifest using <attribution> tag available in R + // and above. optional string attribution_tag = 4; // message related to app op access, limited to 600 chars by API @@ -8718,6 +8717,9 @@ message RuntimeAppOpAccess { // sampling strategy used to collect this message optional SamplingStrategy sampling_strategy = 6; + + // operation id + optional android.app.AppOpEnum op = 7 [default = APP_OP_NONE]; } /* diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h index 850e2b010f8c..9e21c777e6ff 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -218,9 +218,6 @@ private: * The below three variables are only valid during the execution of * parseBuffer. There are no guarantees about the state of these variables * before/after. - * - * TODO (b/150312423): These shouldn't be member variables. We should pass - * them around as parameters. */ uint8_t* mBuf; uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp index 1cee4d9babdc..bed836a1bd90 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.cpp +++ b/cmds/statsd/src/shell/ShellSubscriber.cpp @@ -152,7 +152,6 @@ void ShellSubscriber::startPull(int64_t myToken) { mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), uids, &data); VLOG("pulled %zu atoms with id %d", data.size(), pullInfo.mPullerMatcher.atom_id()); - // TODO(b/150969574): Don't write to a pipe while holding a lock. if (!writePulledAtomsLocked(data, pullInfo.mPullerMatcher)) { mSubscriptionInfo->mClientAlive = false; mSubscriptionShouldEnd.notify_one(); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index f3759fd611df..67334f554df7 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -47,7 +47,6 @@ import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.KeyEvent; -import android.view.SurfaceControl; import android.view.SurfaceView; import android.view.WindowManager; import android.view.WindowManagerImpl; @@ -1820,6 +1819,13 @@ public abstract class AccessibilityService extends Service { /** * Returns a list of system actions available in the system right now. + * <p> + * System actions that correspond to the global action constants will have matching action IDs. + * For example, an with id {@link #GLOBAL_ACTION_BACK} will perform the back action. + * </p> + * <p> + * These actions should be called by {@link #performGlobalAction}. + * </p> * * @return A list of available system actions. */ @@ -1981,8 +1987,6 @@ public abstract class AccessibilityService extends Service { * to declare the capability to take screenshot by setting the * {@link android.R.styleable#AccessibilityService_canTakeScreenshot} * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. - * This API only will support {@link Display#DEFAULT_DISPLAY} until {@link SurfaceControl} - * supports non-default displays. * </p> * * @param displayId The logic display id, must be {@link Display#DEFAULT_DISPLAY} for @@ -1990,18 +1994,11 @@ public abstract class AccessibilityService extends Service { * @param executor Executor on which to run the callback. * @param callback The callback invoked when taking screenshot has succeeded or failed. * See {@link TakeScreenshotCallback} for details. - * - * @throws IllegalArgumentException if displayId is not {@link Display#DEFAULT_DISPLAY}. */ public void takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor, @NonNull TakeScreenshotCallback callback) { Preconditions.checkNotNull(executor, "executor cannot be null"); Preconditions.checkNotNull(callback, "callback cannot be null"); - - if (displayId != Display.DEFAULT_DISPLAY) { - throw new IllegalArgumentException("DisplayId isn't the default display"); - } - final IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance().getConnection( mConnectionId); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index d6a9f6990abe..c399bc72e438 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -40,6 +40,7 @@ import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.StyleableRes; import android.annotation.XmlRes; +import android.app.Application; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; @@ -58,9 +59,11 @@ import android.util.Log; import android.util.LongSparseArray; import android.util.Pools.SynchronizedPool; import android.util.TypedValue; +import android.view.Display; import android.view.DisplayAdjustments; import android.view.ViewDebug; import android.view.ViewHierarchyEncoder; +import android.view.WindowManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -101,6 +104,12 @@ import java.util.List; * (such as for different languages and screen sizes). This is an important aspect of developing * Android applications that are compatible on different types of devices.</p> * + * <p>After {@link Build.VERSION_CODES#R}, {@link Resources} must be obtained by + * {@link android.app.Activity} or {@link android.content.Context} created with + * {@link android.content.Context#createWindowContext(int, Bundle)}. + * {@link Application#getResources()} may report wrong values in multi-window or on secondary + * displays. + * * <p>For more information about using resources, see the documentation about <a * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p> */ @@ -2024,10 +2033,20 @@ public class Resources { } /** - * Return the current display metrics that are in effect for this resource - * object. The returned object should be treated as read-only. - * - * @return The resource's current display metrics. + * Return the current display metrics that are in effect for this resource + * object. The returned object should be treated as read-only. + * + * <p>Note that the reported value may be different than the window this application is + * interested in.</p> + * + * <p>Best practices are to obtain metrics from {@link WindowManager#getCurrentWindowMetrics()} + * for window bounds, {@link Display#getRealMetrics(DisplayMetrics)} for display bounds and + * obtain density from {@link Configuration#densityDpi}. The value obtained from this API may be + * wrong if the {@link Resources} is from the context which is different than the window is + * attached such as {@link Application#getResources()}. + * <p/> + * + * @return The resource's current display metrics. */ public DisplayMetrics getDisplayMetrics() { return mResourcesImpl.getDisplayMetrics(); diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index ea2b9e79d99c..462110f5a795 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -17,6 +17,7 @@ package android.hardware.display; import android.annotation.Nullable; +import android.graphics.Point; import android.hardware.SensorManager; import android.os.Handler; import android.os.PowerManager; @@ -72,6 +73,15 @@ public abstract class DisplayManagerInternal { public abstract SurfaceControl.ScreenshotGraphicBuffer screenshot(int displayId); /** + * Take a screenshot without secure layer of the specified display and return a buffer. + * + * @param displayId The display id to take the screenshot of. + * @return The buffer or null if we have failed. + */ + public abstract SurfaceControl.ScreenshotGraphicBuffer screenshotWithoutSecureLayer( + int displayId); + + /** * Returns information about the specified logical display. * * @param displayId The logical display id. @@ -81,6 +91,16 @@ public abstract class DisplayManagerInternal { public abstract DisplayInfo getDisplayInfo(int displayId); /** + * Returns the position of the display's projection. + * + * @param displayId The logical display id. + * @return The x, y coordinates of the display, or null if the display does not exist. The + * return object must be treated as immutable. + */ + @Nullable + public abstract Point getDisplayPosition(int displayId); + + /** * Registers a display transaction listener to provide the client a chance to * update its surfaces within the same transaction as any display layout updates. * diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index fe90a8457949..c42dacc187a9 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -624,7 +624,9 @@ public abstract class NetworkAgent { throw new UnsupportedOperationException( "Legacy agents can't call markConnected."); } - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); + // |reason| cannot be used by the non-legacy agents + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */, + mNetworkInfo.getExtraInfo()); queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); } @@ -638,7 +640,9 @@ public abstract class NetworkAgent { if (mIsLegacy) { throw new UnsupportedOperationException("Legacy agents can't call unregister."); } - mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); + // When unregistering an agent nobody should use the extrainfo (or reason) any more. + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */, + null /* extraInfo */); queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9c1fb41ecc96..b7fb280efdc4 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1195,18 +1195,24 @@ public final class NetworkStats implements Parcelable { /** * Remove all rows that match one of specified UIDs. + * This mutates the original structure in place. * @hide */ public void removeUids(int[] uids) { - int nextOutputEntry = 0; - for (int i = 0; i < size; i++) { - if (!ArrayUtils.contains(uids, uid[i])) { - maybeCopyEntry(nextOutputEntry, i); - nextOutputEntry++; - } - } + filter(e -> !ArrayUtils.contains(uids, e.uid)); + } - size = nextOutputEntry; + /** + * Remove all rows that match one of specified UIDs. + * @return the result object. + * @hide + */ + @NonNull + public NetworkStats removeEmptyEntries() { + final NetworkStats ret = this.clone(); + ret.filter(e -> e.rxBytes != 0 || e.rxPackets != 0 || e.txBytes != 0 || e.txPackets != 0 + || e.operations != 0); + return ret; } /** diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index ae65f1d0bd05..5f8c4f5cdf27 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -1268,6 +1268,7 @@ public class Environment { public static boolean isExternalStorageLegacy(@NonNull File path) { final Context context = AppGlobals.getInitialApplication(); final int uid = context.getApplicationInfo().uid; + // Isolated processes and Instant apps are never allowed to be in scoped storage if (Process.isIsolated(uid)) { return false; } @@ -1277,8 +1278,6 @@ public class Environment { return false; } - // TODO(b/150672994): Compat flags do not override instant app and isolated process's - // behavior. boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE); boolean forceEnableScopedStorage = Compatibility.isChangeEnabled( FORCE_ENABLE_SCOPED_STORAGE); diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java index 995014374721..b1647fe0fcf9 100644 --- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java +++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java @@ -21,7 +21,9 @@ import static android.os.Parcelable.Creator; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; +import android.annotation.SuppressLint; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.Service; import android.content.Intent; import android.content.pm.PackageManager; @@ -64,6 +66,7 @@ import java.util.concurrent.TimeUnit; * </pre> * @hide */ +@TestApi @SystemApi public abstract class ExplicitHealthCheckService extends Service { @@ -159,6 +162,15 @@ public abstract class ExplicitHealthCheckService extends Service { } /** + * Sets {@link RemoteCallback}, for testing purpose. + * + * @hide + */ + @TestApi + public void setCallback(@Nullable RemoteCallback callback) { + mCallback = callback; + } + /** * Implementors should call this to notify the system when explicit health check passes * for {@code packageName}; */ @@ -183,6 +195,7 @@ public abstract class ExplicitHealthCheckService extends Service { * * @hide */ + @TestApi @SystemApi public static final class PackageConfig implements Parcelable { private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1); @@ -263,7 +276,7 @@ public abstract class ExplicitHealthCheckService extends Service { } @Override - public void writeToParcel(Parcel parcel, int flags) { + public void writeToParcel(@SuppressLint({"MissingNullability"}) Parcel parcel, int flags) { parcel.writeString(mPackageName); parcel.writeLong(mHealthCheckTimeoutMillis); } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 72ddaca27a76..43c7bede38c2 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -18,6 +18,7 @@ package android.view; import static android.view.InsetsState.ITYPE_CAPTION_BAR; import static android.view.InsetsState.ITYPE_IME; +import static android.view.InsetsState.toInternalType; import static android.view.InsetsState.toPublicType; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.ime; @@ -471,7 +472,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (!localStateChanged && mLastDispachedState.equals(state)) { return false; } - mState.set(state); + updateState(state); mLastDispachedState.set(state, true /* copySources */); applyLocalVisibilityOverride(); if (localStateChanged) { @@ -480,11 +481,25 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (!mState.equals(mLastDispachedState, true /* excludingCaptionInsets */)) { sendStateToWindowManager(); } + return true; + } + + private void updateState(InsetsState newState) { + mState.setDisplayFrame(newState.getDisplayFrame()); + for (int i = newState.getSourcesCount() - 1; i >= 0; i--) { + InsetsSource source = newState.sourceAt(i); + getSourceConsumer(source.getType()).updateSource(source); + } + for (int i = mState.getSourcesCount() - 1; i >= 0; i--) { + InsetsSource source = mState.sourceAt(i); + if (newState.peekSource(source.getType()) == null) { + mState.removeSource(source.getType()); + } + } if (mCaptionInsetsHeight != 0) { mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top, mFrame.right, mFrame.top + mCaptionInsetsHeight)); } - return true; } private boolean captionInsetsUnchanged() { @@ -879,8 +894,15 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation control.cancel(); } for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { - if (mRunningAnimations.get(i).runner == control) { + RunningAnimation runningAnimation = mRunningAnimations.get(i); + if (runningAnimation.runner == control) { mRunningAnimations.remove(i); + ArraySet<Integer> types = toInternalType(control.getTypes()); + for (int j = types.size() - 1; j >= 0; j--) { + if (getSourceConsumer(types.valueAt(j)).notifyAnimationFinished()) { + mViewRoot.notifyInsetsChanged(); + } + } break; } } diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index f74221dc3e3a..69bab4df2cae 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -16,11 +16,13 @@ package android.view; +import static android.view.InsetsController.ANIMATION_TYPE_NONE; import static android.view.InsetsController.AnimationType; import static android.view.InsetsState.toPublicType; import android.annotation.IntDef; import android.annotation.Nullable; +import android.graphics.Rect; import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; @@ -64,6 +66,8 @@ public class InsetsSourceConsumer { private final Supplier<Transaction> mTransactionSupplier; private @Nullable InsetsSourceControl mSourceControl; private boolean mHasWindowFocus; + private Rect mPendingFrame; + private Rect mPendingVisibleFrame; public InsetsSourceConsumer(@InternalInsetsType int type, InsetsState state, Supplier<Transaction> transactionSupplier, InsetsController controller) { @@ -215,6 +219,38 @@ public class InsetsSourceConsumer { // no-op for types that always return ShowResult#SHOW_IMMEDIATELY. } + void updateSource(InsetsSource newSource) { + InsetsSource source = mState.peekSource(mType); + if (source == null || mController.getAnimationType(mType) == ANIMATION_TYPE_NONE + || source.getFrame().equals(newSource.getFrame())) { + mState.addSource(newSource); + return; + } + + // Frame is changing while animating. Keep note of the new frame but keep existing frame + // until animaition is finished. + newSource = new InsetsSource(newSource); + mPendingFrame = new Rect(newSource.getFrame()); + mPendingVisibleFrame = newSource.getVisibleFrame() != null + ? new Rect(newSource.getVisibleFrame()) + : null; + newSource.setFrame(source.getFrame()); + newSource.setVisibleFrame(source.getVisibleFrame()); + mState.addSource(newSource); + } + + boolean notifyAnimationFinished() { + if (mPendingFrame != null) { + InsetsSource source = mState.getSource(mType); + source.setFrame(mPendingFrame); + source.setVisibleFrame(mPendingVisibleFrame); + mPendingFrame = null; + mPendingVisibleFrame = null; + return true; + } + return false; + } + /** * Sets requested visibility from the client, regardless of whether we are able to control it at * the moment. diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index fe70ff7a1dbf..174165c5ba59 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -124,8 +124,14 @@ public class SurfaceControlViewHost { /** @hide */ public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d, @NonNull WindowlessWindowManager wwm) { + this(c, d, wwm, false /* useSfChoreographer */); + } + + /** @hide */ + public SurfaceControlViewHost(@NonNull Context c, @NonNull Display d, + @NonNull WindowlessWindowManager wwm, boolean useSfChoreographer) { mWm = wwm; - mViewRoot = new ViewRootImpl(c, d, mWm); + mViewRoot = new ViewRootImpl(c, d, mWm, useSfChoreographer); mViewRoot.forceDisableBLAST(); mAccessibilityEmbeddedConnection = mViewRoot.getAccessibilityEmbeddedConnection(); } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index c89e0c9fc60e..b677ccd9a618 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1037,7 +1037,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); } - } else if ((layoutSizeChanged || positionChanged) && + } else if ((layoutSizeChanged || positionChanged || visibleChanged) && viewRoot.useBLAST()) { viewRoot.setUseBLASTSyncTransaction(); } @@ -1241,7 +1241,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t, Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); - if (frameNumber > 0 && viewRoot != null && !viewRoot.useBLAST()) { + if (frameNumber > 0 && viewRoot != null && !viewRoot.isDrawingToBLASTTransaction()) { t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(), frameNumber); } @@ -1258,7 +1258,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall private void setParentSpaceRectangle(Rect position, long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); - final boolean useBLAST = viewRoot.useBLAST(); + final boolean useBLAST = viewRoot.isDrawingToBLASTTransaction(); final SurfaceControl.Transaction t = useBLAST ? viewRoot.getBLASTSyncTransaction() : mRtTransaction; @@ -1319,7 +1319,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void positionLost(long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); - boolean useBLAST = viewRoot != null && viewRoot.useBLAST(); + boolean useBLAST = viewRoot != null && viewRoot.isDrawingToBLASTTransaction(); if (DEBUG) { Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d", System.identityHashCode(this), frameNumber)); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3534bb0f763f..1e96a1c21ac3 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -449,7 +449,7 @@ public final class ViewRootImpl implements ViewParent, InputQueue mInputQueue; @UnsupportedAppUsage FallbackEventHandler mFallbackEventHandler; - Choreographer mChoreographer; + final Choreographer mChoreographer; // used in relayout to get SurfaceControl size // for BLAST adapter surface setup @@ -692,11 +692,18 @@ public final class ViewRootImpl implements ViewParent, private SurfaceControl.Transaction mRtBLASTSyncTransaction = new SurfaceControl.Transaction(); private String mTag = TAG; + public ViewRootImpl(Context context, Display display) { - this(context, display, WindowManagerGlobal.getWindowSession()); + this(context, display, WindowManagerGlobal.getWindowSession(), + false /* useSfChoreographer */); } public ViewRootImpl(Context context, Display display, IWindowSession session) { + this(context, display, session, false /* useSfChoreographer */); + } + + public ViewRootImpl(Context context, Display display, IWindowSession session, + boolean useSfChoreographer) { mContext = context; mWindowSession = session; mDisplay = display; @@ -732,7 +739,8 @@ public final class ViewRootImpl implements ViewParent, mDensity = context.getResources().getDisplayMetrics().densityDpi; mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; mFallbackEventHandler = new PhoneFallbackEventHandler(context); - mChoreographer = Choreographer.getInstance(); + mChoreographer = useSfChoreographer + ? Choreographer.getSfInstance() : Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mInsetsController = new InsetsController(this); @@ -9602,4 +9610,12 @@ public final class ViewRootImpl implements ViewParent, boolean useBLAST() { return mUseBLASTAdapter; } + + /** + * Returns true if we are about to or currently processing a draw directed + * in to a BLAST transaction. + */ + boolean isDrawingToBLASTTransaction() { + return mNextReportConsumeBLAST; + } } diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index dc87453bd867..6a109253a27c 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -1275,7 +1275,14 @@ public final class AccessibilityManager { /** * Register the provided {@link RemoteAction} with the given actionId - * + * <p> + * To perform established system actions, an accessibility service uses the GLOBAL_ACTION + * constants in {@link android.accessibilityservice.AccessibilityService}. To provide a + * customized implementation for one of these actions, the id of the registered system action + * must match that of the corresponding GLOBAL_ACTION constant. For example, to register a + * Back action, {@code actionId} must be + * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK} + * </p> * @param action The remote action to be registered with the given actionId as system action. * @param actionId The id uniquely identify the system action. * @hide diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 08b32930971a..fb962103990c 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -43,7 +43,7 @@ import android.os.ServiceManager; import android.util.Log; import android.view.View; import android.view.WindowManager; -import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IAccessibilityManager; import com.android.internal.annotations.GuardedBy; @@ -610,10 +610,10 @@ public class Toast { */ TN(Context context, String packageName, Binder token, List<Callback> callbacks, @Nullable Looper looper) { - WindowManager windowManager = context.getSystemService(WindowManager.class); - AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context); - mPresenter = new ToastPresenter(context, windowManager, accessibilityManager, - getService(), packageName); + IAccessibilityManager accessibilityManager = IAccessibilityManager.Stub.asInterface( + ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)); + mPresenter = new ToastPresenter(context, accessibilityManager, getService(), + packageName); mParams = mPresenter.getLayoutParams(); mPackageName = packageName; mToken = token; diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java index e9d4aa668891..2679c69be4f6 100644 --- a/core/java/android/widget/ToastPresenter.java +++ b/core/java/android/widget/ToastPresenter.java @@ -27,6 +27,7 @@ import android.content.res.Resources; import android.graphics.PixelFormat; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -34,8 +35,10 @@ import android.view.View; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IAccessibilityManager; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; /** @@ -49,12 +52,14 @@ public class ToastPresenter { private static final long SHORT_DURATION_TIMEOUT = 4000; private static final long LONG_DURATION_TIMEOUT = 7000; + @VisibleForTesting + public static final int TEXT_TOAST_LAYOUT = R.layout.transient_notification; + /** * Returns the default text toast view for message {@code text}. */ public static View getTextToastView(Context context, CharSequence text) { - View view = LayoutInflater.from(context).inflate( - R.layout.transient_notification, null); + View view = LayoutInflater.from(context).inflate(TEXT_TOAST_LAYOUT, null); TextView textView = view.findViewById(com.android.internal.R.id.message); textView.setText(text); return view; @@ -70,15 +75,23 @@ public class ToastPresenter { @Nullable private View mView; @Nullable private IBinder mToken; - public ToastPresenter(Context context, WindowManager windowManager, - AccessibilityManager accessibilityManager, + public ToastPresenter(Context context, IAccessibilityManager accessibilityManager, INotificationManager notificationManager, String packageName) { mContext = context; mResources = context.getResources(); - mWindowManager = windowManager; - mAccessibilityManager = accessibilityManager; + mWindowManager = context.getSystemService(WindowManager.class); mNotificationManager = notificationManager; mPackageName = packageName; + + // We obtain AccessibilityManager manually via its constructor instead of using method + // AccessibilityManager.getInstance() for 2 reasons: + // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior. + // 2. getInstance() caches the instance for the process even if we pass a different + // context to it. This is problematic for multi-user because callers can pass a context + // created via Context.createContextAsUser(). + mAccessibilityManager = new AccessibilityManager(context, accessibilityManager, + UserHandle.getCallingUserId()); + mParams = createLayoutParams(); } diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java index 39a0101bbf59..2091c9398e95 100644 --- a/core/java/android/window/TaskOrganizerTaskEmbedder.java +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -254,9 +254,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { mTaskToken = taskInfo.token; mTaskLeash = mTaskToken.getLeash(); mTransaction.reparent(mTaskLeash, mSurfaceControl) - .show(mTaskLeash) - .show(mSurfaceControl) - .apply(); + .show(mSurfaceControl).apply(); if (mPendingNotifyBoundsChanged) { // TODO: Either defer show or hide and synchronize show with the resize notifyBoundsChanged(); diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 553721d75fd6..be43e82c3f88 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -286,6 +286,7 @@ public class AlertController { if (mTitleView != null) { mTitleView.setText(title); } + mWindow.setTitle(title); } /** diff --git a/core/java/com/android/internal/app/ChooserActivityLogger.java b/core/java/com/android/internal/app/ChooserActivityLogger.java index dc482443040a..088973cde3e9 100644 --- a/core/java/com/android/internal/app/ChooserActivityLogger.java +++ b/core/java/com/android/internal/app/ChooserActivityLogger.java @@ -191,6 +191,9 @@ public interface ChooserActivityLogger { * ChooserActivity. */ default int typeFromIntentString(String intent) { + if (intent == null) { + return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_DEFAULT; + } switch (intent) { case Intent.ACTION_VIEW: return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_VIEW; diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 5b79b184b6a4..38f5f3279c8e 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -204,8 +204,8 @@ oneway interface IStatusBar /** * Displays a text toast. */ - void showToast(String packageName, IBinder token, CharSequence text, IBinder windowToken, - int duration, @nullable ITransientNotificationCallback callback); + void showToast(int uid, String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, @nullable ITransientNotificationCallback callback); /** * Cancels toast with token {@code token} in {@code packageName}. diff --git a/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java b/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java deleted file mode 100644 index 924b3f704f5b..000000000000 --- a/core/java/com/android/internal/view/SurfaceFlingerVsyncChoreographer.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.internal.view; - -import android.os.Handler; -import android.os.Message; -import android.view.Choreographer; -import android.view.Display; - -/** - * Utility class to schedule things at vsync-sf instead of vsync-app - * @hide - */ -public class SurfaceFlingerVsyncChoreographer { - - private static final long ONE_MS_IN_NS = 1000000; - private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000; - - private final Handler mHandler; - private final Choreographer mChoreographer; - - /** - * The offset between vsync-app and vsync-surfaceflinger. See - * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary. - */ - private long mSurfaceFlingerOffsetMs; - - public SurfaceFlingerVsyncChoreographer(Handler handler, Display display, - Choreographer choreographer) { - mHandler = handler; - mChoreographer = choreographer; - mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(display); - } - - public long getSurfaceFlingerOffsetMs() { - return mSurfaceFlingerOffsetMs; - } - - /** - * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app - * is a couple of milliseconds before vsync-sf, a touch or animation event that causes a surface - * flinger transaction are sometimes processed before the vsync-sf tick, and sometimes after, - * which leads to jank. Figure out this difference here and then post all the touch/animation - * events to start being processed at vsync-sf. - * - * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf. - */ - private long calculateAppSurfaceFlingerVsyncOffsetMs(Display display) { - - // Calculate vsync offset from SurfaceFlinger. - // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs - long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate()); - long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS); - return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS); - } - - public void scheduleAtSfVsync(Runnable r) { - final long delay = calculateDelay(); - if (delay <= 0) { - r.run(); - } else { - mHandler.postDelayed(r, delay); - } - } - - public void scheduleAtSfVsync(Handler h, Message m) { - final long delay = calculateDelay(); - if (delay <= 0) { - h.handleMessage(m); - } else { - m.setAsynchronous(true); - h.sendMessageDelayed(m, delay); - } - } - - private long calculateDelay() { - final long sinceFrameStart = System.nanoTime() - mChoreographer.getLastFrameTimeNanos(); - return mSurfaceFlingerOffsetMs - sinceFrameStart / 1000000; - } -} diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index d40924b603a5..21ca948fa89c 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -229,6 +229,7 @@ public class SystemConfig { private ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>(); private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>(); + private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>(); /** * Map of system pre-defined, uniquely named actors; keys are namespace, @@ -394,6 +395,10 @@ public class SystemConfig { return mRollbackWhitelistedPackages; } + public Set<String> getWhitelistedStagedInstallers() { + return mWhitelistedStagedInstallers; + } + public ArraySet<String> getAppDataIsolationWhitelistedApps() { return mAppDataIsolationWhitelistedApps; } @@ -1137,6 +1142,20 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; + case "whitelisted-staged-installer": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mWhitelistedStagedInstallers.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; default: { Slog.w(TAG, "Tag " + name + " is unknown in " + permFile + " at " + parser.getPositionDescription()); diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index ab57e3dcdc53..6321651c1345 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2669,4 +2669,9 @@ enum PageId { // Open: Settings > Sound > Do Not Disturb > Apps > <Choose App> // OS: R DND_APPS_BYPASSING = 1840; + + // OPEN: Settings > Battery > Advanced battery option + // CATEGORY: SETTINGS + // OS: R + FUELGAUGE_ADVANCED_BATTERY_OPTION = 1842; } diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index b9c71a2a207c..cbb379bf8207 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -32,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 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; @@ -638,7 +639,31 @@ public class InsetsControllerTest { }); } + @Test + public void testFrameUpdateDuringAnimation() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + + mController.onControlsChanged(createSingletonControl(ITYPE_IME)); + // Pretend IME is calling + mController.show(ime(), true /* fromIme */); + + InsetsState copy = new InsetsState(mController.getState(), true /* copySources */); + copy.getSource(ITYPE_IME).setFrame(0, 1, 2, 3); + copy.getSource(ITYPE_IME).setVisibleFrame(new Rect(4, 5, 6, 7)); + mController.onStateChanged(copy); + assertNotEquals(new Rect(0, 1, 2, 3), + mController.getState().getSource(ITYPE_IME).getFrame()); + assertNotEquals(new Rect(4, 5, 6, 7), + mController.getState().getSource(ITYPE_IME).getVisibleFrame()); + mController.cancelExistingAnimation(); + assertEquals(new Rect(0, 1, 2, 3), + mController.getState().getSource(ITYPE_IME).getFrame()); + assertEquals(new Rect(4, 5, 6, 7), + mController.getState().getSource(ITYPE_IME).getVisibleFrame()); + }); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } @Test public void testCaptionInsetsStateAssemble() { diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index b75370486afe..07cf41560cf3 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -25,6 +25,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "-2101985723": { + "message": "Failed looking up window session=%s callers=%s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, "-2072089308": { "message": "Attempted to add window with token that is a sub-window: %s. Aborting.", "level": "WARN", @@ -655,12 +661,6 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "-747671114": { - "message": "Failed looking up window callers=%s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, "-714291355": { "message": "Losing delayed focus: %s", "level": "INFO", diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 155eb1cfbd46..c11762bcdb40 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -44,46 +44,56 @@ import java.util.Set; /** * @hide */ +@TestApi public class AudioSystem { private static final boolean DEBUG_VOLUME = false; private static final String TAG = "AudioSystem"; + + // private constructor to prevent instantiating AudioSystem + private AudioSystem() { + throw new UnsupportedOperationException("Trying to instantiate AudioSystem"); + } + /* These values must be kept in sync with system/audio.h */ /* * If these are modified, please also update Settings.System.VOLUME_SETTINGS * and attrs.xml and AudioManager.java. */ - /** Used to identify the default audio stream volume */ + /** @hide Used to identify the default audio stream volume */ + @TestApi public static final int STREAM_DEFAULT = -1; - /** Used to identify the volume of audio streams for phone calls */ + /** @hide Used to identify the volume of audio streams for phone calls */ public static final int STREAM_VOICE_CALL = 0; - /** Used to identify the volume of audio streams for system sounds */ + /** @hide Used to identify the volume of audio streams for system sounds */ public static final int STREAM_SYSTEM = 1; - /** Used to identify the volume of audio streams for the phone ring and message alerts */ + /** @hide Used to identify the volume of audio streams for the phone ring and message alerts */ public static final int STREAM_RING = 2; - /** Used to identify the volume of audio streams for music playback */ + /** @hide Used to identify the volume of audio streams for music playback */ public static final int STREAM_MUSIC = 3; - /** Used to identify the volume of audio streams for alarms */ + /** @hide Used to identify the volume of audio streams for alarms */ public static final int STREAM_ALARM = 4; - /** Used to identify the volume of audio streams for notifications */ + /** @hide Used to identify the volume of audio streams for notifications */ public static final int STREAM_NOTIFICATION = 5; - /** Used to identify the volume of audio streams for phone calls when connected on bluetooth */ + /** @hide + * Used to identify the volume of audio streams for phone calls when connected on bluetooth */ public static final int STREAM_BLUETOOTH_SCO = 6; - /** Used to identify the volume of audio streams for enforced system sounds in certain + /** @hide Used to identify the volume of audio streams for enforced system sounds in certain * countries (e.g camera in Japan) */ @UnsupportedAppUsage public static final int STREAM_SYSTEM_ENFORCED = 7; - /** Used to identify the volume of audio streams for DTMF tones */ + /** @hide Used to identify the volume of audio streams for DTMF tones */ public static final int STREAM_DTMF = 8; - /** Used to identify the volume of audio streams exclusively transmitted through the + /** @hide Used to identify the volume of audio streams exclusively transmitted through the * speaker (TTS) of the device */ public static final int STREAM_TTS = 9; - /** Used to identify the volume of audio streams for accessibility prompts */ + /** @hide Used to identify the volume of audio streams for accessibility prompts */ public static final int STREAM_ACCESSIBILITY = 10; - /** Used to identify the volume of audio streams for virtual assistant */ + /** @hide Used to identify the volume of audio streams for virtual assistant */ public static final int STREAM_ASSISTANT = 11; /** + * @hide * @deprecated Use {@link #numStreamTypes() instead} */ public static final int NUM_STREAMS = 5; @@ -96,9 +106,16 @@ public class AudioSystem // Expose only the getter method publicly so we can change it in the future private static final int NUM_STREAM_TYPES = 12; + + /** + * @hide + * @return total number of stream types + */ @UnsupportedAppUsage + @TestApi public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; } + /** @hide */ public static final String[] STREAM_NAMES = new String[] { "STREAM_VOICE_CALL", "STREAM_SYSTEM", @@ -114,7 +131,8 @@ public class AudioSystem "STREAM_ASSISTANT" }; - /* + /** + * @hide * Sets the microphone mute on or off. * * @param on set <var>true</var> to mute the microphone; @@ -124,7 +142,8 @@ public class AudioSystem @UnsupportedAppUsage public static native int muteMicrophone(boolean on); - /* + /** + * @hide * Checks whether the microphone mute is on or off. * * @return true if microphone is muted, false if it's not @@ -133,15 +152,24 @@ public class AudioSystem public static native boolean isMicrophoneMuted(); /* modes for setPhoneState, must match AudioSystem.h audio_mode */ + /** @hide */ public static final int MODE_INVALID = -2; + /** @hide */ public static final int MODE_CURRENT = -1; + /** @hide */ public static final int MODE_NORMAL = 0; + /** @hide */ public static final int MODE_RINGTONE = 1; + /** @hide */ public static final int MODE_IN_CALL = 2; + /** @hide */ public static final int MODE_IN_COMMUNICATION = 3; + /** @hide */ public static final int MODE_CALL_SCREENING = 4; + /** @hide */ public static final int NUM_MODES = 5; + /** @hide */ public static String modeToString(int mode) { switch (mode) { case MODE_CURRENT: return "MODE_CURRENT"; @@ -156,15 +184,23 @@ public class AudioSystem } /* Formats for A2DP codecs, must match system/audio-base.h audio_format_t */ + /** @hide */ public static final int AUDIO_FORMAT_INVALID = 0xFFFFFFFF; + /** @hide */ public static final int AUDIO_FORMAT_DEFAULT = 0; + /** @hide */ public static final int AUDIO_FORMAT_AAC = 0x04000000; + /** @hide */ public static final int AUDIO_FORMAT_SBC = 0x1F000000; + /** @hide */ public static final int AUDIO_FORMAT_APTX = 0x20000000; + /** @hide */ public static final int AUDIO_FORMAT_APTX_HD = 0x21000000; + /** @hide */ public static final int AUDIO_FORMAT_LDAC = 0x23000000; /** + * @hide * Convert audio format enum values to Bluetooth codec values */ public static int audioFormatToBluetoothSourceCodec(int audioFormat) { @@ -179,25 +215,27 @@ public class AudioSystem } /* Routing bits for the former setRouting/getRouting API */ - /** @deprecated */ + /** @hide @deprecated */ @Deprecated public static final int ROUTE_EARPIECE = (1 << 0); - /** @deprecated */ + /** @hide @deprecated */ @Deprecated public static final int ROUTE_SPEAKER = (1 << 1); - /** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */ + /** @hide @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */ @Deprecated public static final int ROUTE_BLUETOOTH = (1 << 2); - /** @deprecated */ + /** @hide @deprecated */ @Deprecated public static final int ROUTE_BLUETOOTH_SCO = (1 << 2); - /** @deprecated */ + /** @hide @deprecated */ @Deprecated public static final int ROUTE_HEADSET = (1 << 3); - /** @deprecated */ + /** @hide @deprecated */ @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4); - /** @deprecated */ + /** @hide @deprecated */ @Deprecated public static final int ROUTE_ALL = 0xFFFFFFFF; // Keep in sync with system/media/audio/include/system/audio.h + /** @hide */ public static final int AUDIO_SESSION_ALLOCATE = 0; - /* + /** + * @hide * Checks whether the specified stream type is active. * * return true if any track playing on this stream is active. @@ -205,7 +243,8 @@ public class AudioSystem @UnsupportedAppUsage public static native boolean isStreamActive(int stream, int inPastMs); - /* + /** + * @hide * Checks whether the specified stream type is active on a remotely connected device. The notion * of what constitutes a remote device is enforced by the audio policy manager of the platform. * @@ -213,7 +252,8 @@ public class AudioSystem */ public static native boolean isStreamActiveRemotely(int stream, int inPastMs); - /* + /** + * @hide * Checks whether the specified audio source is active. * * return true if any recorder using this source is currently recording @@ -221,23 +261,27 @@ public class AudioSystem @UnsupportedAppUsage public static native boolean isSourceActive(int source); - /* + /** + * @hide * Returns a new unused audio session ID */ public static native int newAudioSessionId(); - /* + /** + * @hide * Returns a new unused audio player ID */ public static native int newAudioPlayerId(); /** + * @hide * Returns a new unused audio recorder ID */ public static native int newAudioRecorderId(); - /* + /** + * @hide * Sets a group generic audio configuration parameters. The use of these parameters * are platform dependent, see libaudio * @@ -247,7 +291,8 @@ public class AudioSystem @UnsupportedAppUsage public static native int setParameters(String keyValuePairs); - /* + /** + * @hide * Gets a group generic audio configuration parameters. The use of these parameters * are platform dependent, see libaudio * @@ -259,16 +304,16 @@ public class AudioSystem public static native String getParameters(String keys); // These match the enum AudioError in frameworks/base/core/jni/android_media_AudioSystem.cpp - /* Command sucessful or Media server restarted. see ErrorCallback */ + /** @hide Command successful or Media server restarted. see ErrorCallback */ public static final int AUDIO_STATUS_OK = 0; - /* Command failed or unspecified audio error. see ErrorCallback */ + /** @hide Command failed or unspecified audio error. see ErrorCallback */ public static final int AUDIO_STATUS_ERROR = 1; - /* Media server died. see ErrorCallback */ + /** @hide Media server died. see ErrorCallback */ public static final int AUDIO_STATUS_SERVER_DIED = 100; - private static ErrorCallback mErrorCallback; + private static ErrorCallback sErrorCallback; - /* + /** @hide * Handles the audio error callback. */ public interface ErrorCallback @@ -283,7 +328,8 @@ public class AudioSystem void onError(int error); }; - /* + /** + * @hide * Registers a callback to be invoked when an error occurs. * @param cb the callback to run */ @@ -291,7 +337,7 @@ public class AudioSystem public static void setErrorCallback(ErrorCallback cb) { synchronized (AudioSystem.class) { - mErrorCallback = cb; + sErrorCallback = cb; if (cb != null) { cb.onError(checkAudioFlinger()); } @@ -303,8 +349,8 @@ public class AudioSystem { ErrorCallback errorCallback = null; synchronized (AudioSystem.class) { - if (mErrorCallback != null) { - errorCallback = mErrorCallback; + if (sErrorCallback != null) { + errorCallback = sErrorCallback; } } if (errorCallback != null) { @@ -313,6 +359,7 @@ public class AudioSystem } /** + * @hide * Handles events from the audio policy manager about dynamic audio policies * @see android.media.audiopolicy.AudioPolicy */ @@ -326,6 +373,7 @@ public class AudioSystem private static DynamicPolicyCallback sDynPolicyCallback; + /** @hide */ public static void setDynamicPolicyCallback(DynamicPolicyCallback cb) { synchronized (AudioSystem.class) { @@ -355,6 +403,7 @@ public class AudioSystem } /** + * @hide * Handles events from the audio policy manager about recording events * @see android.media.AudioManager.AudioRecordingCallback */ @@ -386,6 +435,7 @@ public class AudioSystem private static AudioRecordingCallback sRecordingCallback; + /** @hide */ public static void setRecordingCallback(AudioRecordingCallback cb) { synchronized (AudioSystem.class) { sRecordingCallback = cb; @@ -434,13 +484,21 @@ public class AudioSystem * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...) * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h */ + /** @hide */ public static final int SUCCESS = 0; + /** @hide */ public static final int ERROR = -1; + /** @hide */ public static final int BAD_VALUE = -2; + /** @hide */ public static final int INVALID_OPERATION = -3; + /** @hide */ public static final int PERMISSION_DENIED = -4; + /** @hide */ public static final int NO_INIT = -5; + /** @hide */ public static final int DEAD_OBJECT = -6; + /** @hide */ public static final int WOULD_BLOCK = -7; /** @hide */ @@ -458,6 +516,7 @@ public class AudioSystem public @interface AudioSystemError {} /** + * @hide * Convert an int error value to its String value for readability. * Accepted error values are the java AudioSystem errors, matching android_media_AudioErrors.h, * which map onto the native status_t type. @@ -494,74 +553,113 @@ public class AudioSystem // // audio device definitions: must be kept in sync with values in system/core/audio.h // - + /** @hide */ public static final int DEVICE_NONE = 0x0; // reserved bits + /** @hide */ public static final int DEVICE_BIT_IN = 0x80000000; + /** @hide */ public static final int DEVICE_BIT_DEFAULT = 0x40000000; // output devices, be sure to update AudioManager.java also + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_EARPIECE = 0x1; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_SPEAKER = 0x2; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_WIRED_HEADSET = 0x4; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_AUX_DIGITAL = 0x400; + /** @hide */ public static final int DEVICE_OUT_HDMI = DEVICE_OUT_AUX_DIGITAL; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_USB_DEVICE = 0x4000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_TELEPHONY_TX = 0x10000; + /** @hide */ public static final int DEVICE_OUT_LINE = 0x20000; + /** @hide */ public static final int DEVICE_OUT_HDMI_ARC = 0x40000; + /** @hide */ public static final int DEVICE_OUT_SPDIF = 0x80000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_FM = 0x100000; + /** @hide */ public static final int DEVICE_OUT_AUX_LINE = 0x200000; + /** @hide */ public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000; + /** @hide */ public static final int DEVICE_OUT_IP = 0x800000; + /** @hide */ public static final int DEVICE_OUT_BUS = 0x1000000; + /** @hide */ public static final int DEVICE_OUT_PROXY = 0x2000000; + /** @hide */ public static final int DEVICE_OUT_USB_HEADSET = 0x4000000; + /** @hide */ public static final int DEVICE_OUT_HEARING_AID = 0x8000000; + /** @hide */ public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; // Deprecated in R because multiple device types are no longer accessed as a bit mask. // Removing this will get lint warning about changing hidden apis. + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY | DEVICE_OUT_USB_DEVICE | DEVICE_OUT_USB_HEADSET); + /** @hide */ public static final Set<Integer> DEVICE_OUT_ALL_SET; + /** @hide */ public static final Set<Integer> DEVICE_OUT_ALL_A2DP_SET; + /** @hide */ public static final Set<Integer> DEVICE_OUT_ALL_SCO_SET; + /** @hide */ public static final Set<Integer> DEVICE_OUT_ALL_USB_SET; + /** @hide */ public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET; + /** @hide */ public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET; static { DEVICE_OUT_ALL_SET = new HashSet<>(); @@ -621,53 +719,85 @@ public class AudioSystem } // input devices + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_COMMUNICATION = DEVICE_BIT_IN | 0x1; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_AMBIENT = DEVICE_BIT_IN | 0x2; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_BUILTIN_MIC = DEVICE_BIT_IN | 0x4; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = DEVICE_BIT_IN | 0x8; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_WIRED_HEADSET = DEVICE_BIT_IN | 0x10; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_AUX_DIGITAL = DEVICE_BIT_IN | 0x20; + /** @hide */ public static final int DEVICE_IN_HDMI = DEVICE_IN_AUX_DIGITAL; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_VOICE_CALL = DEVICE_BIT_IN | 0x40; + /** @hide */ public static final int DEVICE_IN_TELEPHONY_RX = DEVICE_IN_VOICE_CALL; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_BACK_MIC = DEVICE_BIT_IN | 0x80; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_REMOTE_SUBMIX = DEVICE_BIT_IN | 0x100; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_ANLG_DOCK_HEADSET = DEVICE_BIT_IN | 0x200; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_DGTL_DOCK_HEADSET = DEVICE_BIT_IN | 0x400; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_USB_ACCESSORY = DEVICE_BIT_IN | 0x800; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_USB_DEVICE = DEVICE_BIT_IN | 0x1000; + /** @hide */ public static final int DEVICE_IN_FM_TUNER = DEVICE_BIT_IN | 0x2000; + /** @hide */ public static final int DEVICE_IN_TV_TUNER = DEVICE_BIT_IN | 0x4000; + /** @hide */ public static final int DEVICE_IN_LINE = DEVICE_BIT_IN | 0x8000; + /** @hide */ public static final int DEVICE_IN_SPDIF = DEVICE_BIT_IN | 0x10000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_BLUETOOTH_A2DP = DEVICE_BIT_IN | 0x20000; + /** @hide */ public static final int DEVICE_IN_LOOPBACK = DEVICE_BIT_IN | 0x40000; + /** @hide */ public static final int DEVICE_IN_IP = DEVICE_BIT_IN | 0x80000; + /** @hide */ public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000; + /** @hide */ public static final int DEVICE_IN_PROXY = DEVICE_BIT_IN | 0x1000000; + /** @hide */ public static final int DEVICE_IN_USB_HEADSET = DEVICE_BIT_IN | 0x2000000; + /** @hide */ public static final int DEVICE_IN_BLUETOOTH_BLE = DEVICE_BIT_IN | 0x4000000; + /** @hide */ public static final int DEVICE_IN_HDMI_ARC = DEVICE_BIT_IN | 0x8000000; + /** @hide */ public static final int DEVICE_IN_ECHO_REFERENCE = DEVICE_BIT_IN | 0x10000000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT; + /** @hide */ public static final Set<Integer> DEVICE_IN_ALL_SET; + /** @hide */ public static final Set<Integer> DEVICE_IN_ALL_SCO_SET; + /** @hide */ public static final Set<Integer> DEVICE_IN_ALL_USB_SET; static { DEVICE_IN_ALL_SET = new HashSet<>(); @@ -708,15 +838,19 @@ public class AudioSystem DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET); } + /** @hide */ public static final String LEGACY_REMOTE_SUBMIX_ADDRESS = "0"; // device states, must match AudioSystem::device_connection_state + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_STATE_UNAVAILABLE = 0; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_STATE_AVAILABLE = 1; private static final int NUM_DEVICE_STATES = 1; + /** @hide */ public static String deviceStateToString(int state) { switch (state) { case DEVICE_STATE_UNAVAILABLE: return "DEVICE_STATE_UNAVAILABLE"; @@ -725,63 +859,65 @@ public class AudioSystem } } - public static final String DEVICE_OUT_EARPIECE_NAME = "earpiece"; - public static final String DEVICE_OUT_SPEAKER_NAME = "speaker"; - public static final String DEVICE_OUT_WIRED_HEADSET_NAME = "headset"; - public static final String DEVICE_OUT_WIRED_HEADPHONE_NAME = "headphone"; - public static final String DEVICE_OUT_BLUETOOTH_SCO_NAME = "bt_sco"; - public static final String DEVICE_OUT_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs"; - public static final String DEVICE_OUT_BLUETOOTH_SCO_CARKIT_NAME = "bt_sco_carkit"; - public static final String DEVICE_OUT_BLUETOOTH_A2DP_NAME = "bt_a2dp"; + /** @hide */ public static final String DEVICE_OUT_EARPIECE_NAME = "earpiece"; + /** @hide */ public static final String DEVICE_OUT_SPEAKER_NAME = "speaker"; + /** @hide */ public static final String DEVICE_OUT_WIRED_HEADSET_NAME = "headset"; + /** @hide */ public static final String DEVICE_OUT_WIRED_HEADPHONE_NAME = "headphone"; + /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_SCO_NAME = "bt_sco"; + /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs"; + /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_SCO_CARKIT_NAME = "bt_sco_carkit"; + /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_A2DP_NAME = "bt_a2dp"; + /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME = "bt_a2dp_hp"; - public static final String DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME = "bt_a2dp_spk"; - public static final String DEVICE_OUT_AUX_DIGITAL_NAME = "aux_digital"; - public static final String DEVICE_OUT_HDMI_NAME = "hdmi"; - public static final String DEVICE_OUT_ANLG_DOCK_HEADSET_NAME = "analog_dock"; - public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock"; - public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory"; - public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device"; - public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix"; - public static final String DEVICE_OUT_TELEPHONY_TX_NAME = "telephony_tx"; - public static final String DEVICE_OUT_LINE_NAME = "line"; - public static final String DEVICE_OUT_HDMI_ARC_NAME = "hmdi_arc"; - public static final String DEVICE_OUT_SPDIF_NAME = "spdif"; - public static final String DEVICE_OUT_FM_NAME = "fm_transmitter"; - public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line"; - public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe"; - public static final String DEVICE_OUT_IP_NAME = "ip"; - public static final String DEVICE_OUT_BUS_NAME = "bus"; - public static final String DEVICE_OUT_PROXY_NAME = "proxy"; - public static final String DEVICE_OUT_USB_HEADSET_NAME = "usb_headset"; - public static final String DEVICE_OUT_HEARING_AID_NAME = "hearing_aid_out"; - - public static final String DEVICE_IN_COMMUNICATION_NAME = "communication"; - public static final String DEVICE_IN_AMBIENT_NAME = "ambient"; - public static final String DEVICE_IN_BUILTIN_MIC_NAME = "mic"; - public static final String DEVICE_IN_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs"; - public static final String DEVICE_IN_WIRED_HEADSET_NAME = "headset"; - public static final String DEVICE_IN_AUX_DIGITAL_NAME = "aux_digital"; - public static final String DEVICE_IN_TELEPHONY_RX_NAME = "telephony_rx"; - public static final String DEVICE_IN_BACK_MIC_NAME = "back_mic"; - public static final String DEVICE_IN_REMOTE_SUBMIX_NAME = "remote_submix"; - public static final String DEVICE_IN_ANLG_DOCK_HEADSET_NAME = "analog_dock"; - public static final String DEVICE_IN_DGTL_DOCK_HEADSET_NAME = "digital_dock"; - public static final String DEVICE_IN_USB_ACCESSORY_NAME = "usb_accessory"; - public static final String DEVICE_IN_USB_DEVICE_NAME = "usb_device"; - public static final String DEVICE_IN_FM_TUNER_NAME = "fm_tuner"; - public static final String DEVICE_IN_TV_TUNER_NAME = "tv_tuner"; - public static final String DEVICE_IN_LINE_NAME = "line"; - public static final String DEVICE_IN_SPDIF_NAME = "spdif"; - public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp"; - public static final String DEVICE_IN_LOOPBACK_NAME = "loopback"; - public static final String DEVICE_IN_IP_NAME = "ip"; - public static final String DEVICE_IN_BUS_NAME = "bus"; - public static final String DEVICE_IN_PROXY_NAME = "proxy"; - public static final String DEVICE_IN_USB_HEADSET_NAME = "usb_headset"; - public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble"; - public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference"; - public static final String DEVICE_IN_HDMI_ARC_NAME = "hdmi_arc"; + /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME = "bt_a2dp_spk"; + /** @hide */ public static final String DEVICE_OUT_AUX_DIGITAL_NAME = "aux_digital"; + /** @hide */ public static final String DEVICE_OUT_HDMI_NAME = "hdmi"; + /** @hide */ public static final String DEVICE_OUT_ANLG_DOCK_HEADSET_NAME = "analog_dock"; + /** @hide */ public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock"; + /** @hide */ public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory"; + /** @hide */ public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device"; + /** @hide */ public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix"; + /** @hide */ public static final String DEVICE_OUT_TELEPHONY_TX_NAME = "telephony_tx"; + /** @hide */ public static final String DEVICE_OUT_LINE_NAME = "line"; + /** @hide */ public static final String DEVICE_OUT_HDMI_ARC_NAME = "hmdi_arc"; + /** @hide */ public static final String DEVICE_OUT_SPDIF_NAME = "spdif"; + /** @hide */ public static final String DEVICE_OUT_FM_NAME = "fm_transmitter"; + /** @hide */ public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line"; + /** @hide */ public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe"; + /** @hide */ public static final String DEVICE_OUT_IP_NAME = "ip"; + /** @hide */ public static final String DEVICE_OUT_BUS_NAME = "bus"; + /** @hide */ public static final String DEVICE_OUT_PROXY_NAME = "proxy"; + /** @hide */ public static final String DEVICE_OUT_USB_HEADSET_NAME = "usb_headset"; + /** @hide */ public static final String DEVICE_OUT_HEARING_AID_NAME = "hearing_aid_out"; + + /** @hide */ public static final String DEVICE_IN_COMMUNICATION_NAME = "communication"; + /** @hide */ public static final String DEVICE_IN_AMBIENT_NAME = "ambient"; + /** @hide */ public static final String DEVICE_IN_BUILTIN_MIC_NAME = "mic"; + /** @hide */ public static final String DEVICE_IN_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs"; + /** @hide */ public static final String DEVICE_IN_WIRED_HEADSET_NAME = "headset"; + /** @hide */ public static final String DEVICE_IN_AUX_DIGITAL_NAME = "aux_digital"; + /** @hide */ public static final String DEVICE_IN_TELEPHONY_RX_NAME = "telephony_rx"; + /** @hide */ public static final String DEVICE_IN_BACK_MIC_NAME = "back_mic"; + /** @hide */ public static final String DEVICE_IN_REMOTE_SUBMIX_NAME = "remote_submix"; + /** @hide */ public static final String DEVICE_IN_ANLG_DOCK_HEADSET_NAME = "analog_dock"; + /** @hide */ public static final String DEVICE_IN_DGTL_DOCK_HEADSET_NAME = "digital_dock"; + /** @hide */ public static final String DEVICE_IN_USB_ACCESSORY_NAME = "usb_accessory"; + /** @hide */ public static final String DEVICE_IN_USB_DEVICE_NAME = "usb_device"; + /** @hide */ public static final String DEVICE_IN_FM_TUNER_NAME = "fm_tuner"; + /** @hide */ public static final String DEVICE_IN_TV_TUNER_NAME = "tv_tuner"; + /** @hide */ public static final String DEVICE_IN_LINE_NAME = "line"; + /** @hide */ public static final String DEVICE_IN_SPDIF_NAME = "spdif"; + /** @hide */ public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp"; + /** @hide */ public static final String DEVICE_IN_LOOPBACK_NAME = "loopback"; + /** @hide */ public static final String DEVICE_IN_IP_NAME = "ip"; + /** @hide */ public static final String DEVICE_IN_BUS_NAME = "bus"; + /** @hide */ public static final String DEVICE_IN_PROXY_NAME = "proxy"; + /** @hide */ public static final String DEVICE_IN_USB_HEADSET_NAME = "usb_headset"; + /** @hide */ public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble"; + /** @hide */ public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference"; + /** @hide */ public static final String DEVICE_IN_HDMI_ARC_NAME = "hdmi_arc"; + /** @hide */ @UnsupportedAppUsage public static String getOutputDeviceName(int device) { @@ -848,6 +984,7 @@ public class AudioSystem } } + /** @hide */ public static String getInputDeviceName(int device) { switch(device) { @@ -910,6 +1047,7 @@ public class AudioSystem } /** + * @hide * Returns a human readable name for a given device type * @param device a native device type, NOT an AudioDeviceInfo type * @return a string describing the device type @@ -922,35 +1060,31 @@ public class AudioSystem } // phone state, match audio_mode??? - public static final int PHONE_STATE_OFFCALL = 0; - public static final int PHONE_STATE_RINGING = 1; - public static final int PHONE_STATE_INCALL = 2; + /** @hide */ public static final int PHONE_STATE_OFFCALL = 0; + /** @hide */ public static final int PHONE_STATE_RINGING = 1; + /** @hide */ public static final int PHONE_STATE_INCALL = 2; // device categories config for setForceUse, must match audio_policy_forced_cfg_t - @UnsupportedAppUsage - public static final int FORCE_NONE = 0; - public static final int FORCE_SPEAKER = 1; - public static final int FORCE_HEADPHONES = 2; - public static final int FORCE_BT_SCO = 3; - public static final int FORCE_BT_A2DP = 4; - public static final int FORCE_WIRED_ACCESSORY = 5; - @UnsupportedAppUsage - public static final int FORCE_BT_CAR_DOCK = 6; - @UnsupportedAppUsage - public static final int FORCE_BT_DESK_DOCK = 7; - @UnsupportedAppUsage - public static final int FORCE_ANALOG_DOCK = 8; - @UnsupportedAppUsage - public static final int FORCE_DIGITAL_DOCK = 9; - public static final int FORCE_NO_BT_A2DP = 10; - public static final int FORCE_SYSTEM_ENFORCED = 11; - public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12; - public static final int FORCE_ENCODED_SURROUND_NEVER = 13; - public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14; - public static final int FORCE_ENCODED_SURROUND_MANUAL = 15; - public static final int NUM_FORCE_CONFIG = 16; - public static final int FORCE_DEFAULT = FORCE_NONE; + /** @hide */ @UnsupportedAppUsage public static final int FORCE_NONE = 0; + /** @hide */ public static final int FORCE_SPEAKER = 1; + /** @hide */ public static final int FORCE_HEADPHONES = 2; + /** @hide */ public static final int FORCE_BT_SCO = 3; + /** @hide */ public static final int FORCE_BT_A2DP = 4; + /** @hide */ public static final int FORCE_WIRED_ACCESSORY = 5; + /** @hide */ @UnsupportedAppUsage public static final int FORCE_BT_CAR_DOCK = 6; + /** @hide */ @UnsupportedAppUsage public static final int FORCE_BT_DESK_DOCK = 7; + /** @hide */ @UnsupportedAppUsage public static final int FORCE_ANALOG_DOCK = 8; + /** @hide */ @UnsupportedAppUsage public static final int FORCE_DIGITAL_DOCK = 9; + /** @hide */ public static final int FORCE_NO_BT_A2DP = 10; + /** @hide */ public static final int FORCE_SYSTEM_ENFORCED = 11; + /** @hide */ public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12; + /** @hide */ public static final int FORCE_ENCODED_SURROUND_NEVER = 13; + /** @hide */ public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14; + /** @hide */ public static final int FORCE_ENCODED_SURROUND_MANUAL = 15; + /** @hide */ public static final int NUM_FORCE_CONFIG = 16; + /** @hide */ public static final int FORCE_DEFAULT = FORCE_NONE; + /** @hide */ public static String forceUseConfigToString(int config) { switch (config) { case FORCE_NONE: return "FORCE_NONE"; @@ -974,16 +1108,17 @@ public class AudioSystem } // usage for setForceUse, must match audio_policy_force_use_t - public static final int FOR_COMMUNICATION = 0; - public static final int FOR_MEDIA = 1; - public static final int FOR_RECORD = 2; - public static final int FOR_DOCK = 3; - public static final int FOR_SYSTEM = 4; - public static final int FOR_HDMI_SYSTEM_AUDIO = 5; - public static final int FOR_ENCODED_SURROUND = 6; - public static final int FOR_VIBRATE_RINGING = 7; + /** @hide */ public static final int FOR_COMMUNICATION = 0; + /** @hide */ public static final int FOR_MEDIA = 1; + /** @hide */ public static final int FOR_RECORD = 2; + /** @hide */ public static final int FOR_DOCK = 3; + /** @hide */ public static final int FOR_SYSTEM = 4; + /** @hide */ public static final int FOR_HDMI_SYSTEM_AUDIO = 5; + /** @hide */ public static final int FOR_ENCODED_SURROUND = 6; + /** @hide */ public static final int FOR_VIBRATE_RINGING = 7; private static final int NUM_FORCE_USE = 8; + /** @hide */ public static String forceUseUsageToString(int usage) { switch (usage) { case FOR_COMMUNICATION: return "FOR_COMMUNICATION"; @@ -998,7 +1133,7 @@ public class AudioSystem } } - /** Wrapper for native methods called from AudioService */ + /** @hide Wrapper for native methods called from AudioService */ public static int setStreamVolumeIndexAS(int stream, int index, int device) { if (DEBUG_VOLUME) { Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream] @@ -1008,10 +1143,11 @@ public class AudioSystem } // usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t - public static final int SYNC_EVENT_NONE = 0; - public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1; + /** @hide */ public static final int SYNC_EVENT_NONE = 0; + /** @hide */ public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1; /** + * @hide * @return command completion status, one of {@link #AUDIO_STATUS_OK}, * {@link #AUDIO_STATUS_ERROR} or {@link #AUDIO_STATUS_SERVER_DIED} */ @@ -1019,12 +1155,15 @@ public class AudioSystem public static native int setDeviceConnectionState(int device, int state, String device_address, String device_name, int codecFormat); + /** @hide */ @UnsupportedAppUsage public static native int getDeviceConnectionState(int device, String device_address); + /** @hide */ public static native int handleDeviceConfigChange(int device, String device_address, String device_name, int codecFormat); + /** @hide */ @UnsupportedAppUsage public static int setPhoneState(int state) { Log.w(TAG, "Do not use this method! Use AudioManager.setMode() instead."); @@ -1038,14 +1177,18 @@ public class AudioSystem * @return command completion status. */ public static native int setPhoneState(int state, int uid); + /** @hide */ @UnsupportedAppUsage public static native int setForceUse(int usage, int config); + /** @hide */ @UnsupportedAppUsage public static native int getForceUse(int usage); + /** @hide */ @UnsupportedAppUsage public static native int initStreamVolume(int stream, int indexMin, int indexMax); @UnsupportedAppUsage private static native int setStreamVolumeIndex(int stream, int index, int device); + /** @hide */ public static native int getStreamVolumeIndex(int stream, int device); /** * @hide @@ -1082,16 +1225,22 @@ public class AudioSystem */ public static native int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attributes); + /** @hide */ public static native int setMasterVolume(float value); + /** @hide */ public static native float getMasterVolume(); + /** @hide */ @UnsupportedAppUsage public static native int setMasterMute(boolean mute); + /** @hide */ @UnsupportedAppUsage public static native boolean getMasterMute(); + /** @hide */ @UnsupportedAppUsage public static native int getDevicesForStream(int stream); /** + * @hide * Do not use directly, see {@link AudioManager#getDevicesForAttributes(AudioAttributes)} * Get the audio devices that would be used for the routing of the given audio attributes. * @param attributes the {@link AudioAttributes} for which the routing is being queried @@ -1136,31 +1285,43 @@ public class AudioSystem /** @hide returns master balance value in range -1.f -> 1.f, where 0.f is dead center. */ @TestApi public static native float getMasterBalance(); - /** @hide changes the audio balance of the device. */ + /** @hide Changes the audio balance of the device. */ @TestApi public static native int setMasterBalance(float balance); // helpers for android.media.AudioManager.getProperty(), see description there for meaning + /** @hide */ @UnsupportedAppUsage(trackingBug = 134049522) public static native int getPrimaryOutputSamplingRate(); + /** @hide */ @UnsupportedAppUsage(trackingBug = 134049522) public static native int getPrimaryOutputFrameCount(); + /** @hide */ @UnsupportedAppUsage public static native int getOutputLatency(int stream); + /** @hide */ public static native int setLowRamDevice(boolean isLowRamDevice, long totalMemory); + /** @hide */ @UnsupportedAppUsage public static native int checkAudioFlinger(); + /** @hide */ public static native int listAudioPorts(ArrayList<AudioPort> ports, int[] generation); + /** @hide */ public static native int createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks); + /** @hide */ public static native int releaseAudioPatch(AudioPatch patch); + /** @hide */ public static native int listAudioPatches(ArrayList<AudioPatch> patches, int[] generation); + /** @hide */ public static native int setAudioPortConfig(AudioPortConfig config); + /** @hide */ public static native int startAudioSource(AudioPortConfig config, AudioAttributes audioAttributes); + /** @hide */ public static native int stopAudioSource(int handle); // declare this instance as having a dynamic policy callback handler @@ -1169,36 +1330,42 @@ public class AudioSystem private static native final void native_register_recording_callback(); // must be kept in sync with value in include/system/audio.h - public static final int AUDIO_HW_SYNC_INVALID = 0; + /** @hide */ public static final int AUDIO_HW_SYNC_INVALID = 0; + /** @hide */ public static native int getAudioHwSyncForSession(int sessionId); + /** @hide */ public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register); - /** see AudioPolicy.setUidDeviceAffinities() */ + /** @hide see AudioPolicy.setUidDeviceAffinities() */ public static native int setUidDeviceAffinities(int uid, @NonNull int[] types, @NonNull String[] addresses); - /** see AudioPolicy.removeUidDeviceAffinities() */ + /** @hide see AudioPolicy.removeUidDeviceAffinities() */ public static native int removeUidDeviceAffinities(int uid); - /** see AudioPolicy.setUserIdDeviceAffinities() */ + /** @hide see AudioPolicy.setUserIdDeviceAffinities() */ public static native int setUserIdDeviceAffinities(int userId, @NonNull int[] types, @NonNull String[] addresses); - /** see AudioPolicy.removeUserIdDeviceAffinities() */ + /** @hide see AudioPolicy.removeUserIdDeviceAffinities() */ public static native int removeUserIdDeviceAffinities(int userId); + /** @hide */ public static native int systemReady(); + /** @hide */ public static native float getStreamVolumeDB(int stream, int index, int device); /** + * @hide * Communicate supported system usages to audio policy service. */ public static native int setSupportedSystemUsages(int[] systemUsages); /** + * @hide * @see AudioManager#setAllowedCapturePolicy() */ public static native int setAllowedCapturePolicy(int uid, int flags); @@ -1212,45 +1379,57 @@ public class AudioSystem private static native boolean native_is_offload_supported(int encoding, int sampleRate, int channelMask, int channelIndexMask, int streamType); + /** @hide */ public static native int getMicrophones(ArrayList<MicrophoneInfo> microphonesInfo); + /** @hide */ public static native int getSurroundFormats(Map<Integer, Boolean> surroundFormats, boolean reported); /** + * @hide * Returns a list of audio formats (codec) supported on the A2DP offload path. */ public static native int getHwOffloadEncodingFormatsSupportedForA2DP( ArrayList<Integer> formatList); + /** @hide */ public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled); /** + * @hide * Communicate UID of active assistant to audio policy service. */ public static native int setAssistantUid(int uid); + /** + * @hide * Communicate UIDs of active accessibility services to audio policy service. */ public static native int setA11yServicesUids(int[] uids); + /** + * @hide * Communicate UID of current InputMethodService to audio policy service. */ public static native int setCurrentImeUid(int uid); /** + * @hide * @see AudioManager#isHapticPlaybackSupported() */ public static native boolean isHapticPlaybackSupported(); /** + * @hide * Send audio HAL server process pids to native audioserver process for use * when generating audio HAL servers tombstones */ public static native int setAudioHalPids(int[] pids); /** + * @hide * @see AudioManager#isCallScreeningModeSupported() */ public static native boolean isCallScreeningModeSupported(); @@ -1258,6 +1437,7 @@ public class AudioSystem // use case routing by product strategy /** + * @hide * Sets the preferred device to use for a given audio strategy in the audio policy engine * @param strategy the id of the strategy to configure * @param device the device type and address to route to when available @@ -1270,6 +1450,7 @@ public class AudioSystem device.getAddress()); } /** + * @hide * Set device routing per product strategy. * @param strategy the id of the strategy to configure * @param deviceType the native device type, NOT AudioDeviceInfo types @@ -1280,6 +1461,7 @@ public class AudioSystem int strategy, int deviceType, String deviceAddress); /** + * @hide * Remove preferred routing for the strategy * @param strategy the id of the strategy to configure * @return {@link #SUCCESS} if successfully removed @@ -1287,6 +1469,7 @@ public class AudioSystem public static native int removePreferredDeviceForStrategy(int strategy); /** + * @hide * Query previously set preferred device for a strategy * @param strategy the id of the strategy to query for * @param device an array of size 1 that will contain the preferred device, or null if @@ -1300,6 +1483,7 @@ public class AudioSystem // Items shared with audio service /** + * @hide * The delay before playing a sound. This small period exists so the user * can press another key (non-volume keys, too) to have it NOT be audible. * <p> @@ -1308,6 +1492,7 @@ public class AudioSystem public static final int PLAY_SOUND_DELAY = 300; /** + * @hide * Constant to identify a focus stack entry that is used to hold the focus while the phone * is ringing or during a call. Used by com.android.internal.telephony.CallManager when * entering and exiting calls. @@ -1315,6 +1500,7 @@ public class AudioSystem public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; /** + * @hide * @see AudioManager#setVibrateSetting(int, int) */ public static int getValueForVibrateSetting(int existingValue, int vibrateType, @@ -1330,10 +1516,12 @@ public class AudioSystem return existingValue; } + /** @hide */ public static int getDefaultStreamVolume(int streamType) { return DEFAULT_STREAM_VOLUME[streamType]; } + /** @hide */ public static int[] DEFAULT_STREAM_VOLUME = new int[] { 4, // STREAM_VOICE_CALL 7, // STREAM_SYSTEM @@ -1349,20 +1537,22 @@ public class AudioSystem 5, // STREAM_ASSISTANT }; + /** @hide */ public static String streamToString(int stream) { if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream]; if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE"; return "UNKNOWN_STREAM_" + stream; } - /** The platform has no specific capabilities */ + /** @hide The platform has no specific capabilities */ public static final int PLATFORM_DEFAULT = 0; - /** The platform is voice call capable (a phone) */ + /** @hide The platform is voice call capable (a phone) */ public static final int PLATFORM_VOICE = 1; - /** The platform is a television or a set-top box */ + /** @hide The platform is a television or a set-top box */ public static final int PLATFORM_TELEVISION = 2; /** + * @hide * Return the platform type that this is running on. One of: * <ul> * <li>{@link #PLATFORM_VOICE}</li> @@ -1392,6 +1582,7 @@ public class AudioSystem } /** + * @hide * Return a set of audio device types from a bit mask audio device type, which may * represent multiple audio device types. * FIXME: Remove this when getting ride of bit mask usage of audio device types. @@ -1409,6 +1600,7 @@ public class AudioSystem } /** + * @hide * Return the intersection of two audio device types collections. */ public static Set<Integer> intersectionAudioDeviceTypes( @@ -1419,12 +1611,14 @@ public class AudioSystem } /** + * @hide * Return true if the audio device types collection only contains the given device type. */ public static boolean isSingleAudioDeviceType(@NonNull Set<Integer> types, int type) { return types.size() == 1 && types.contains(type); } + /** @hide */ public static final int DEFAULT_MUTE_STREAMS_AFFECTED = (1 << STREAM_MUSIC) | (1 << STREAM_RING) | @@ -1434,6 +1628,7 @@ public class AudioSystem (1 << STREAM_BLUETOOTH_SCO); /** + * @hide * Event posted by AudioTrack and AudioRecord JNI (JNIDeviceCallback) when routing changes. * Keep in sync with core/jni/android_media_DeviceCallback.h. */ diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java index 9ce895e25b49..9913d23b3301 100644 --- a/media/java/android/media/tv/tuner/Lnb.java +++ b/media/java/android/media/tv/tuner/Lnb.java @@ -20,12 +20,12 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.content.Context; import android.hardware.tv.tuner.V1_0.Constants; import android.media.tv.tuner.Tuner.Result; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * LNB (low-noise block downconverter) for satellite tuner. @@ -145,7 +145,8 @@ public class Lnb implements AutoCloseable { int mId; LnbCallback mCallback; - Context mContext; + Executor mExecutor; + private native int nativeSetVoltage(int voltage); private native int nativeSetTone(int tone); @@ -159,10 +160,20 @@ public class Lnb implements AutoCloseable { mId = id; } - void setCallback(@Nullable LnbCallback callback) { + void setCallback(Executor executor, @Nullable LnbCallback callback) { mCallback = callback; - if (mCallback == null) { - return; + mExecutor = executor; + } + + private void onEvent(int eventType) { + if (mExecutor != null && mCallback != null) { + mExecutor.execute(() -> mCallback.onEvent(eventType)); + } + } + + private void onDiseqcMessage(byte[] diseqcMessage) { + if (mExecutor != null && mCallback != null) { + mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage)); } } @@ -218,6 +229,9 @@ public class Lnb implements AutoCloseable { * Releases the LNB instance. */ public void close() { - nativeClose(); + int res = nativeClose(); + if (res != Tuner.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "Failed to close LNB"); + } } } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index cf1f1b509ad6..48aed349c39a 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -45,6 +45,7 @@ import android.media.tv.tuner.frontend.ScanCallback; import android.media.tv.tunerresourcemanager.ResourceClientProfile; import android.media.tv.tunerresourcemanager.TunerDemuxRequest; import android.media.tv.tunerresourcemanager.TunerDescramblerRequest; +import android.media.tv.tunerresourcemanager.TunerFrontendInfo; import android.media.tv.tunerresourcemanager.TunerFrontendRequest; import android.media.tv.tunerresourcemanager.TunerLnbRequest; import android.media.tv.tunerresourcemanager.TunerResourceManager; @@ -256,6 +257,36 @@ public class Tuner implements AutoCloseable { mTunerResourceManager.registerClientProfile( profile, new HandlerExecutor(mHandler), mResourceListener, clientId); mClientId = clientId[0]; + + setFrontendInfoList(); + setLnbIds(); + } + + private void setFrontendInfoList() { + List<Integer> ids = nativeGetFrontendIds(); + if (ids == null) { + return; + } + TunerFrontendInfo[] infos = new TunerFrontendInfo[ids.size()]; + for (int i = 0; i < ids.size(); i++) { + int id = ids.get(i); + FrontendInfo frontendInfo = nativeGetFrontendInfo(id); + if (frontendInfo == null) { + continue; + } + TunerFrontendInfo tunerFrontendInfo = new TunerFrontendInfo( + id, frontendInfo.getType(), frontendInfo.getExclusiveGroupId()); + infos[i] = tunerFrontendInfo; + } + mTunerResourceManager.setFrontendInfoList(infos); + } + + private void setLnbIds() { + int[] ids = nativeGetLnbIds(); + if (ids == null) { + return; + } + mTunerResourceManager.setLnbInfoList(ids); } /** @@ -358,7 +389,7 @@ public class Tuner implements AutoCloseable { private native Filter nativeOpenFilter(int type, int subType, long bufferSize); private native TimeFilter nativeOpenTimeFilter(); - private native List<Integer> nativeGetLnbIds(); + private native int[] nativeGetLnbIds(); private native Lnb nativeOpenLnbByHandle(int handle); private native Lnb nativeOpenLnbByName(String name); @@ -829,6 +860,9 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB); + if (mLnb != null) { + mLnb.setCallback(executor, cb); + } return mLnb; } @@ -847,7 +881,11 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(name, "LNB name must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); - return nativeOpenLnbByName(name); + mLnb = nativeOpenLnbByName(name); + if (mLnb != null) { + mLnb.setCallback(executor, cb); + } + return mLnb; } private boolean requestLnb() { @@ -872,12 +910,6 @@ public class Tuner implements AutoCloseable { return nativeOpenTimeFilter(); } - private void onLnbEvent(int eventType) { - if (mHandler != null) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_LNB_EVENT, eventType, 0)); - } - } - /** * Opens a Descrambler in tuner. * diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java index 547a4923cf7b..c1589cf3fb1d 100644 --- a/media/java/android/media/tv/tuner/TunerUtils.java +++ b/media/java/android/media/tv/tuner/TunerUtils.java @@ -137,6 +137,8 @@ public final class TunerUtils { msg = ""; } switch (r) { + case Tuner.RESULT_SUCCESS: + return; case Tuner.RESULT_INVALID_ARGUMENT: throw new IllegalArgumentException(msg); case Tuner.RESULT_INVALID_STATE: diff --git a/media/java/android/media/tv/tuner/filter/TimeFilter.java b/media/java/android/media/tv/tuner/filter/TimeFilter.java index da77b50bc3e5..93599e65d170 100644 --- a/media/java/android/media/tv/tuner/filter/TimeFilter.java +++ b/media/java/android/media/tv/tuner/filter/TimeFilter.java @@ -83,7 +83,7 @@ public class TimeFilter implements AutoCloseable { @Result public int clearTimestamp() { int res = nativeClearTimestamp(); - if (res == 0) { + if (res == Tuner.RESULT_SUCCESS) { mEnable = false; } return res; diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java index 63a71e272e53..2c8899cfca78 100644 --- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java @@ -390,7 +390,7 @@ public class TunerResourceManager { * <li>If no Lnb system can be granted, the API would return false. * <ul> * - * <p><strong>Note:</strong> {@link #setLnbInfos(int[])} must be called before this request. + * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this request. * * @param request {@link TunerLnbRequest} information of the current request. * @param lnbId a one-element array to return the granted Lnb id. @@ -479,7 +479,7 @@ public class TunerResourceManager { * * <p>Client must call this whenever it releases an Lnb. * - * <p><strong>Note:</strong> {@link #setLnbInfos(int[])} must be called before this release. + * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this release. * * @param lnbId the id of the released Tuner Lnb. */ diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 312e5fe14c37..ac7fe5d0403d 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -155,6 +155,7 @@ struct fields_t { jmethodID onFilterEventID; jmethodID lnbInitID; jmethodID onLnbEventID; + jmethodID onLnbDiseqcMessageID; jmethodID onDvrRecordStatusID; jmethodID onDvrPlaybackStatusID; jmethodID descramblerInitID; @@ -170,19 +171,31 @@ static int IP_V6_LENGTH = 16; namespace android { /////////////// LnbCallback /////////////////////// -LnbCallback::LnbCallback(jweak tunerObj, LnbId id) : mObject(tunerObj), mId(id) {} +LnbCallback::LnbCallback(jobject lnbObj, LnbId id) : mId(id) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + mLnb = env->NewWeakGlobalRef(lnbObj); +} Return<void> LnbCallback::onEvent(LnbEventType lnbEventType) { ALOGD("LnbCallback::onEvent, type=%d", lnbEventType); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod( - mObject, + mLnb, gFields.onLnbEventID, (jint)lnbEventType); return Void(); } -Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) { +Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) { ALOGD("LnbCallback::onDiseqcMessage"); + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jbyteArray array = env->NewByteArray(diseqcMessage.size()); + env->SetByteArrayRegion( + array, 0, diseqcMessage.size(), reinterpret_cast<jbyte*>(diseqcMessage[0])); + + env->CallVoidMethod( + mLnb, + gFields.onLnbDiseqcMessageID, + array); return Void(); } @@ -875,6 +888,10 @@ jobject JTuner::openFrontendById(int id) { return NULL; } mFe = fe; + mFeId = id; + if (mDemux != NULL) { + mDemux->setFrontendDataSource(mFeId); + } sp<FrontendCallback> feCb = new FrontendCallback(mObject, id); fe->setCallback(feCb); @@ -1062,43 +1079,40 @@ jobject JTuner::getFrontendInfo(int id) { maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps); } -jobject JTuner::getLnbIds() { +jintArray JTuner::getLnbIds() { ALOGD("JTuner::getLnbIds()"); - mTuner->getLnbIds([&](Result, const hidl_vec<FrontendId>& lnbIds) { - mLnbIds = lnbIds; + Result res; + hidl_vec<LnbId> lnbIds; + mTuner->getLnbIds([&](Result r, const hidl_vec<LnbId>& ids) { + lnbIds = ids; + res = r; }); - if (mLnbIds.size() == 0) { + if (res != Result::SUCCESS || mLnbIds.size() == 0) { ALOGW("Lnb isn't available"); return NULL; } + mLnbIds = lnbIds; JNIEnv *env = AndroidRuntime::getJNIEnv(); - jclass arrayListClazz = env->FindClass("java/util/ArrayList"); - jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z"); - jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V")); - jclass integerClazz = env->FindClass("java/lang/Integer"); - jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V"); + jintArray ids = env->NewIntArray(mLnbIds.size()); + env->SetIntArrayRegion(ids, 0, mLnbIds.size(), reinterpret_cast<jint*>(&mLnbIds[0])); - for (int i=0; i < mLnbIds.size(); i++) { - jobject idObj = env->NewObject(integerClazz, intInit, mLnbIds[i]); - env->CallBooleanMethod(obj, arrayListAdd, idObj); - } - return obj; + return ids; } jobject JTuner::openLnbById(int id) { sp<ILnb> iLnbSp; - mTuner->openLnbById(id, [&](Result, const sp<ILnb>& lnb) { + Result r; + mTuner->openLnbById(id, [&](Result res, const sp<ILnb>& lnb) { + r = res; iLnbSp = lnb; }); - if (iLnbSp == nullptr) { + if (r != Result::SUCCESS || iLnbSp == nullptr) { ALOGE("Failed to open lnb"); return NULL; } mLnb = iLnbSp; - sp<LnbCallback> lnbCb = new LnbCallback(mObject, id); - mLnb->setCallback(lnbCb); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject lnbObj = env->NewObject( @@ -1106,6 +1120,9 @@ jobject JTuner::openLnbById(int id) { gFields.lnbInitID, (jint) id); + sp<LnbCallback> lnbCb = new LnbCallback(lnbObj, id); + mLnb->setCallback(lnbCb); + sp<Lnb> lnbSp = new Lnb(iLnbSp, lnbObj); lnbSp->incStrong(lnbObj); env->SetLongField(lnbObj, gFields.lnbContext, (jlong) lnbSp.get()); @@ -1129,14 +1146,15 @@ jobject JTuner::openLnbByName(jstring name) { return NULL; } mLnb = iLnbSp; - sp<LnbCallback> lnbCb = new LnbCallback(mObject, id); - mLnb->setCallback(lnbCb); jobject lnbObj = env->NewObject( env->FindClass("android/media/tv/tuner/Lnb"), gFields.lnbInitID, id); + sp<LnbCallback> lnbCb = new LnbCallback(lnbObj, id); + mLnb->setCallback(lnbCb); + sp<Lnb> lnbSp = new Lnb(iLnbSp, lnbObj); lnbSp->incStrong(lnbObj); env->SetLongField(lnbObj, gFields.lnbContext, (jlong) lnbSp.get()); @@ -1206,12 +1224,21 @@ Result JTuner::openDemux() { return Result::SUCCESS; } Result res; + uint32_t id; + sp<IDemux> demuxSp; mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) { - mDemux = demux; - mDemuxId = demuxId; + demuxSp = demux; + id = demuxId; res = r; ALOGD("open demux, id = %d", demuxId); }); + if (res == Result::SUCCESS) { + mDemux = demuxSp; + mDemuxId = id; + if (mFe != NULL) { + mDemux->setFrontendDataSource(mFeId); + } + } return res; } @@ -2242,8 +2269,6 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V"); - gFields.onLnbEventID = env->GetMethodID(clazz, "onLnbEvent", "(I)V"); - jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend"); gFields.frontendInitID = env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V"); @@ -2251,6 +2276,8 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { jclass lnbClazz = env->FindClass("android/media/tv/tuner/Lnb"); gFields.lnbContext = env->GetFieldID(lnbClazz, "mNativeContext", "J"); gFields.lnbInitID = env->GetMethodID(lnbClazz, "<init>", "(I)V"); + gFields.onLnbEventID = env->GetMethodID(lnbClazz, "onEvent", "(I)V"); + gFields.onLnbDiseqcMessageID = env->GetMethodID(lnbClazz, "onDiseqcMessage", "([B)V"); jclass filterClazz = env->FindClass("android/media/tv/tuner/filter/Filter"); gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J"); @@ -2375,7 +2402,7 @@ static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thi return tuner->getFrontendInfo(id); } -static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) { +static jintArray android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) { sp<JTuner> tuner = getTuner(env, thiz); return tuner->getLnbIds(); } @@ -3204,8 +3231,14 @@ static int android_media_tv_Tuner_lnb_send_diseqc_msg(JNIEnv* env, jobject lnb, return (jint) r; } -static int android_media_tv_Tuner_close_lnb(JNIEnv*, jobject) { - return 0; +static int android_media_tv_Tuner_close_lnb(JNIEnv* env, jobject lnb) { + sp<Lnb> lnbSp = getLnb(env, lnb); + Result r = lnbSp->getILnb()->close(); + if (r == Result::SUCCESS) { + lnbSp->decStrong(lnb); + env->SetLongField(lnb, gFields.lnbContext, 0); + } + return (jint) r; } static void android_media_tv_Tuner_dvr_set_fd(JNIEnv *env, jobject dvr, jobject jfd) { @@ -3379,8 +3412,7 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_open_filter }, { "nativeOpenTimeFilter", "()Landroid/media/tv/tuner/filter/TimeFilter;", (void *)android_media_tv_Tuner_open_time_filter }, - { "nativeGetLnbIds", "()Ljava/util/List;", - (void *)android_media_tv_Tuner_get_lnb_ids }, + { "nativeGetLnbIds", "()[I", (void *)android_media_tv_Tuner_get_lnb_ids }, { "nativeOpenLnbByHandle", "(I)Landroid/media/tv/tuner/Lnb;", (void *)android_media_tv_Tuner_open_lnb_by_handle }, { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;", diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index e6f10b24c840..73fc38dbdec8 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -70,7 +70,7 @@ struct LnbCallback : public ILnbCallback { LnbCallback(jweak tunerObj, LnbId id); virtual Return<void> onEvent(LnbEventType lnbEventType); virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage); - jweak mObject; + jweak mLnb; LnbId mId; }; @@ -179,7 +179,7 @@ struct JTuner : public RefBase { int stopScan(); int setLnb(int id); int setLna(bool enable); - jobject getLnbIds(); + jintArray getLnbIds(); jobject openLnbById(int id); jobject openLnbByName(jstring name); jobject openFilter(DemuxFilterType type, int bufferSize); @@ -199,6 +199,7 @@ private: static sp<ITuner> mTuner; hidl_vec<FrontendId> mFeIds; sp<IFrontend> mFe; + int mFeId; hidl_vec<LnbId> mLnbIds; sp<ILnb> mLnb; sp<IDemux> mDemux; diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index 43e2918bd98d..0b56d05cc66f 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -32,6 +32,10 @@ <!-- Disable normal notification rendering; we handle that ourselves --> <bool name="config_renderNotifications">false</bool> + <!-- Whether navigationBar touch events should be consumed before reaching the CarFacetButton \ + when the notification panel is open. --> + <bool name="config_consumeNavigationBarTouchWhenNotificationPanelOpen">false</bool> + <!-- Whether heads-up notifications should be shown when shade is open. --> <bool name="config_enableHeadsUpNotificationWhenNotificationShadeOpen">true</bool> <!-- Whether heads-up notifications should be shown on the bottom. If false, heads-up diff --git a/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java index f11eff851aa3..d84b2f958feb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java @@ -28,7 +28,6 @@ import dagger.Module; @Module(includes = { DefaultActivityBinder.class, DefaultBroadcastReceiverBinder.class, - DefaultServiceBinder.class, - CarSystemUIBinder.class}) + DefaultServiceBinder.class}) public class CarComponentBinder { } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 5547fee0159c..c275536e4d92 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -65,7 +65,7 @@ import dagger.Module; import dagger.Provides; @Module(includes = {DividerModule.class}) -abstract class CarSystemUIModule { +public abstract class CarSystemUIModule { @Singleton @Provides diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java index 7d544c9a9bd7..0e923f7164bb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java @@ -40,6 +40,6 @@ import dagger.Component; CarSystemUIModule.class, CarSystemUIBinder.class }) -interface CarSystemUIRootComponent extends SystemUIRootComponent { +public interface CarSystemUIRootComponent extends SystemUIRootComponent { } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java index 9d98479dfeff..1901a2db879d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java @@ -599,6 +599,11 @@ public class NotificationPanelViewController extends OverlayViewController { } } + /** Returns {@code true} if the notification panel is expanded. */ + public boolean isPanelExpanded() { + return mPanelExpanded; + } + /** Sets the unseen count listener. */ public void setOnUnseenCountUpdateListener(OnUnseenCountUpdateListener listener) { mUnseenCountUpdateListener = listener; diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java index 1cfc83293acb..110c2ee8854b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java @@ -20,7 +20,6 @@ import android.car.hardware.power.CarPowerManager; import android.content.res.Configuration; import com.android.systemui.car.CarDeviceProvisionedController; -import com.android.systemui.car.CarServiceProvider; import com.android.systemui.navigationbar.car.CarNavigationBarController; import com.android.systemui.statusbar.car.PowerManagerHelper; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -36,7 +35,6 @@ public class NotificationPanelViewMediator implements OverlayViewMediator, private final CarNavigationBarController mCarNavigationBarController; private final NotificationPanelViewController mNotificationPanelViewController; - private final CarServiceProvider mCarServiceProvider; private final PowerManagerHelper mPowerManagerHelper; private final CarDeviceProvisionedController mCarDeviceProvisionedController; private final ConfigurationController mConfigurationController; @@ -46,7 +44,6 @@ public class NotificationPanelViewMediator implements OverlayViewMediator, CarNavigationBarController carNavigationBarController, NotificationPanelViewController notificationPanelViewController, - CarServiceProvider carServiceProvider, PowerManagerHelper powerManagerHelper, CarDeviceProvisionedController carDeviceProvisionedController, @@ -54,7 +51,6 @@ public class NotificationPanelViewMediator implements OverlayViewMediator, ) { mCarNavigationBarController = carNavigationBarController; mNotificationPanelViewController = notificationPanelViewController; - mCarServiceProvider = carServiceProvider; mPowerManagerHelper = powerManagerHelper; mCarDeviceProvisionedController = carDeviceProvisionedController; mConfigurationController = configurationController; @@ -72,7 +68,17 @@ public class NotificationPanelViewMediator implements OverlayViewMediator, mNotificationPanelViewController.getNavBarNotificationTouchListener()); mCarNavigationBarController.registerNotificationController( - () -> mNotificationPanelViewController.toggle()); + new CarNavigationBarController.NotificationsShadeController() { + @Override + public void togglePanel() { + mNotificationPanelViewController.toggle(); + } + + @Override + public boolean isNotificationPanelOpen() { + return mNotificationPanelViewController.isPanelExpanded(); + } + }); } @Override diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java index 67e9da429c36..fbcd8787135d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java @@ -314,6 +314,9 @@ public class CarNavigationBarController { public interface NotificationsShadeController { /** Toggles the visibility of the notifications shade. */ void togglePanel(); + + /** Returns {@code true} if the panel is open. */ + boolean isNotificationPanelOpen(); } private void checkAllBars(boolean isSetUp) { diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java index 28da16932fc4..5b99f53af9f9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java @@ -35,10 +35,11 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; * in a linear layout. */ public class CarNavigationBarView extends LinearLayout { + private final boolean mConsumeTouchWhenPanelOpen; + private View mNavButtons; private CarNavigationButton mNotificationsButton; private NotificationsShadeController mNotificationsShadeController; - private Context mContext; private View mLockScreenButtons; // used to wire in open/close gestures for notifications private OnTouchListener mStatusBarWindowTouchListener; @@ -46,7 +47,8 @@ public class CarNavigationBarView extends LinearLayout { public CarNavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); - mContext = context; + mConsumeTouchWhenPanelOpen = getResources().getBoolean( + R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen); } @Override @@ -77,9 +79,16 @@ public class CarNavigationBarView extends LinearLayout { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (mStatusBarWindowTouchListener != null) { + boolean shouldConsumeEvent = mNotificationsShadeController == null ? false + : mNotificationsShadeController.isNotificationPanelOpen(); + // Forward touch events to the status bar window so it can drag // windows if required (Notification shade) mStatusBarWindowTouchListener.onTouch(this, ev); + + if (mConsumeTouchWhenPanelOpen && shouldConsumeEvent) { + return true; + } } return super.onInterceptTouchEvent(ev); } diff --git a/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml b/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml new file mode 100644 index 000000000000..b0ca8dc4cd34 --- /dev/null +++ b/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml @@ -0,0 +1,58 @@ +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<com.android.systemui.navigationbar.car.CarNavigationBarView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/system_bar_background" + android:orientation="vertical"> + <!--The 20dp padding is the difference between the background selected icon size and the ripple + that was chosen, thus it's a hack to make it look pretty and not an official margin value--> + <LinearLayout + android:id="@id/nav_buttons" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingStart="20dp" + android:paddingEnd="20dp" + android:gravity="center"> + + <com.android.systemui.navigationbar.car.CarNavigationButton + android:id="@+id/home" + style="@style/NavigationBarButton" + systemui:componentNames="com.android.car.carlauncher/.CarLauncher" + systemui:icon="@drawable/car_ic_overview" + systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end" + systemui:selectedIcon="@drawable/car_ic_overview_selected" + systemui:highlightWhenSelected="true" + /> + + </LinearLayout> + + <LinearLayout + android:id="@+id/lock_screen_nav_buttons" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingStart="@dimen/car_keyline_1" + android:paddingEnd="@dimen/car_keyline_1" + android:gravity="center" + android:visibility="gone" + /> + +</com.android.systemui.navigationbar.car.CarNavigationBarView> diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarViewTest.java new file mode 100644 index 000000000000..9e2131c9ccfb --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarViewTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.navigationbar.car; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; + +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; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class CarNavigationBarViewTest extends SysuiTestCase { + + private CarNavigationBarView mNavBarView; + + @Mock + private CarNavigationBarController.NotificationsShadeController mNotificationsShadeController; + + @Mock + private View.OnTouchListener mNavBarTouchListener; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @After + public void tearDown() { + getContext().getOrCreateTestableResources().addOverride( + R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, false); + } + + @Test + public void dispatchTouch_shadeOpen_flagOff_doesNotConsumeTouch() { + getContext().getOrCreateTestableResources().addOverride( + R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, false); + when(mNotificationsShadeController.isNotificationPanelOpen()).thenReturn(true); + mNavBarView = (CarNavigationBarView) LayoutInflater.from(getContext()).inflate( + R.layout.car_navigation_bar_view_test, /* root= */ null); + mNavBarView.setNotificationsPanelController(mNotificationsShadeController); + mNavBarView.setStatusBarWindowTouchListener(mNavBarTouchListener); + + boolean consume = mNavBarView.onInterceptTouchEvent( + MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300, + MotionEvent.ACTION_MOVE, mNavBarView.getX(), + mNavBarView.getY(), /* metaState= */ 0)); + + assertThat(consume).isFalse(); + } + + @Test + public void dispatchTouch_shadeOpen_flagOn_consumesTouch() { + getContext().getOrCreateTestableResources().addOverride( + R.bool.config_consumeNavigationBarTouchWhenNotificationPanelOpen, true); + when(mNotificationsShadeController.isNotificationPanelOpen()).thenReturn(true); + mNavBarView = (CarNavigationBarView) LayoutInflater.from(getContext()).inflate( + R.layout.car_navigation_bar_view_test, /* root= */ null); + mNavBarView.setNotificationsPanelController(mNotificationsShadeController); + mNavBarView.setStatusBarWindowTouchListener(mNavBarTouchListener); + + boolean consume = mNavBarView.onInterceptTouchEvent( + MotionEvent.obtain(/* downTime= */ 200, /* eventTime= */ 300, + MotionEvent.ACTION_MOVE, mNavBarView.getX(), + mNavBarView.getY(), /* metaState= */ 0)); + + assertThat(consume).isTrue(); + } +} diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 1681fdbcef06..126efcc9bbd4 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -206,11 +206,11 @@ <string name="enable_adb" msgid="8072776357237289039">"የUSB አራሚ"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB ሲያያዝ የአርም ሁኔታ"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"የዩ ኤስ ቢ ስህተት ማረም ፈቀዳዎችን ይሻሩ"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"ገመድ-አልባ ማረም"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"ገመድ-አልባ debugging"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi-Fi ሲገናኝ የማረም ሁነታ"</string> <string name="adb_wireless_error" msgid="721958772149779856">"ስህተት"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"ገመድ-አልባ ማረም"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"የሚገኙ መሣሪያዎችን ለመመልከትና ለመጠቀም ገመድ-አልባ ማረምን ያብሩ"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"ገመድ-አልባ debugging"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"የሚገኙ መሣሪያዎችን ለመመልከትና ለመጠቀም ገመድ-አልባ debuggingን ያብሩ"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"የQR ኮድን በመጠቀም መሣሪያን ያጣምሩ"</string> <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"የQR ኮድ መቃኛን በመጠቀም አዲስ መሣሪያዎችን ያጣምሩ"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"የማጣመሪያ ኮድን በመጠቀም መሣሪያን ያጣምሩ"</string> @@ -300,8 +300,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"የሃርድዌር ማቀላጠፊያን ማስተሳሰርን የሚገኝ ከሆነ ይጠቀሙ"</string> <string name="adb_warning_title" msgid="7708653449506485728">"የUSB ማረሚያ ይፈቀድ?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"የUSB አድስ ለግንባታ አላማ ብቻ የታሰበ ነው። ከኮምፒዩተርህ ወደ መሳሪያህ ውሂብ ለመገልበጥ፣ መሣሪያህ ላይ ያለ ማሳወቂያ መተግበሪያዎችን መጫን፣ እና ማስታወሻ ውሂብ ማንበብ ለመጠቀም ይቻላል።"</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"ገመድ-አልባ ማረም ይፈቀድ?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"ገመድ-አልባ ማረም ለግንባታ አላማዎች ብቻ የታሰበ ነው። ውሂብን ከኮምፒዩተርዎ ወደ መሳሪያዎ ለመቅዳት፣ መሣሪያዎ ላይ ያለማሳወቂያ መተግበሪያዎችን ለመጫን እና የምዝግብ ማስታወሻ ውሂብን ለማንበብ ይጠቀሙበት።"</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"ገመድ-አልባ debugging ይፈቀድ?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"ገመድ-አልባ debugging ለግንባታ አላማዎች ብቻ የታሰበ ነው። ውሂብን ከኮምፒዩተርዎ ወደ መሳሪያዎ ለመቅዳት፣ መሣሪያዎ ላይ ያለማሳወቂያ መተግበሪያዎችን ለመጫን እና የምዝግብ ማስታወሻ ውሂብን ለማንበብ ይጠቀሙበት።"</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"የዩ ኤስ ቢ ማረም መዳረሻ ከዚህ ቀደም ፍቃድ ከሰጧቸው ኮምፒውተሮች ላይ ይሻሩ?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"የግንባታ ቅንብሮችን ፍቀድ?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"እነዚህ ቅንብሮች የታሰቡት ለግንባታ አጠቃቀም ብቻ ናቸው። መሳሪያህን እና በሱ ላይ ያሉትን መተግበሪያዎች እንዲበለሹ ወይም በትክክል እንዳይሰሩ ሊያደርጉ ይችላሉ።"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index abd1e03590f2..88d4c0304396 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -232,8 +232,7 @@ <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"عنوان IP والمنفذ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"المسح الضوئي لرمز الاستجابة السريعة"</string> <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"إقران الجهاز من خلال شبكة Wi‑Fi عن طريق المسح الضوئي لرمز استجابة سريعة"</string> - <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) --> - <skip /> + <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"يُرجى الاتصال بشبكة Wi-Fi."</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb، تصحيح الأخطاء، مطور برامج"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"اختصار تقرير الأخطاء"</string> <string name="bugreport_in_power_summary" msgid="1885529649381831775">"عرض زر في قائمة خيارات التشغيل لإعداد تقرير بالأخطاء"</string> @@ -432,8 +431,7 @@ <string name="power_discharge_by" msgid="4113180890060388350">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> <string name="power_discharge_by_only" msgid="92545648425937000">"قد تكفي طاقة البطارية حتى حوالي الساعة <xliff:g id="TIME">%1$s</xliff:g>."</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"حتى <xliff:g id="TIME">%1$s</xliff:g>"</string> - <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) --> - <skip /> + <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"قد ينفد شحن البطارية قبل <xliff:g id="TIME">%1$s</xliff:g>."</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"يتبقى أقل من <xliff:g id="THRESHOLD">%1$s</xliff:g>."</string> <string name="power_remaining_less_than_duration" msgid="1812668275239801236">"يتبقى أقل من <xliff:g id="THRESHOLD">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> <string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"يتبقى أكثر من <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)."</string> @@ -515,32 +513,21 @@ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"مكبر صوت الهاتف"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"حدثت مشكلة أثناء الاتصال. يُرجى إيقاف الجهاز ثم إعادة تشغيله."</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"جهاز سماعي سلكي"</string> - <!-- no translation found for help_label (3528360748637781274) --> - <skip /> - <!-- no translation found for storage_category (2287342585424631813) --> - <skip /> - <!-- no translation found for shared_data_title (1017034836800864953) --> - <skip /> - <!-- no translation found for shared_data_summary (5516326713822885652) --> - <skip /> + <string name="help_label" msgid="3528360748637781274">"المساعدة والتعليقات"</string> + <string name="storage_category" msgid="2287342585424631813">"مساحة التخزين"</string> + <string name="shared_data_title" msgid="1017034836800864953">"البيانات المشتركة"</string> + <string name="shared_data_summary" msgid="5516326713822885652">"عرض البيانات المشتركة وتعديلها"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ما مِن بيانات مشتركة لهذا المستخدم."</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"حدث خطأ أثناء جلب البيانات المشتركة. يُرجى إعادة المحاولة."</string> - <!-- no translation found for blob_id_text (8680078988996308061) --> - <skip /> - <!-- no translation found for blob_expires_text (7882727111491739331) --> - <skip /> + <string name="blob_id_text" msgid="8680078988996308061">"معرّف البيانات المشتركة: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> + <string name="blob_expires_text" msgid="7882727111491739331">"تنتهي صلاحيتها في <xliff:g id="DATE">%s</xliff:g>."</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"حدث خطأ أثناء حذف البيانات المشتركة."</string> <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ما مِن عمليات تأجير مطلوبة لهذه المعلومات المشتركة. هل تريد حذفها؟"</string> - <!-- no translation found for accessor_info_title (8289823651512477787) --> - <skip /> - <!-- no translation found for accessor_no_description_text (7510967452505591456) --> - <skip /> - <!-- no translation found for accessor_expires_text (4625619273236786252) --> - <skip /> - <!-- no translation found for delete_blob_text (2819192607255625697) --> - <skip /> - <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) --> - <skip /> + <string name="accessor_info_title" msgid="8289823651512477787">"التطبيقات التي تشارك البيانات"</string> + <string name="accessor_no_description_text" msgid="7510967452505591456">"لم يوفّر التطبيق وصفًا."</string> + <string name="accessor_expires_text" msgid="4625619273236786252">"تنتهي صلاحية العقد في <xliff:g id="DATE">%s</xliff:g>."</string> + <string name="delete_blob_text" msgid="2819192607255625697">"حذف البيانات المشتركة"</string> + <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"هل فعلاً تريد حذف هذه البيانات المشتركة؟"</string> <string name="user_add_user_item_summary" msgid="5748424612724703400">"المستخدمون لديهم تطبيقات ومحتوى خاص بهم"</string> <string name="user_add_profile_item_summary" msgid="5418602404308968028">"يمكنك تقييد الدخول إلى التطبيقات والمحتوى من حسابك"</string> <string name="user_add_user_item_title" msgid="2394272381086965029">"المستخدم"</string> @@ -560,12 +547,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"معلومات الملف الشخصي"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"قبل أن تتمكن من إنشاء ملف شخصي مقيد، يلزمك إعداد تأمين للشاشة لحماية تطبيقاتك وبياناتك الشخصية."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"تعيين التأمين"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"التبديل إلى <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"إضافة ضيف"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"إزالة جلسة الضيف"</string> + <string name="guest_nickname" msgid="6332276931583337261">"ضيف"</string> </resources> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index a1c00a385339..73a5e7c031d7 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"প্ৰ\'ফাইলৰ তথ্য"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"আপুনি সীমিত প্ৰ\'ফাইল এটা সৃষ্টি কৰাৰ আগেয়ে, আপোনাৰ ব্যক্তিগত ডেটা আৰু এপবিলাকক সুৰক্ষিত কৰিবলৈ স্ক্ৰীণ লক এটা নিৰ্ধাৰণ কৰিব লাগিব।"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"লক ছেট কৰক"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>লৈ সলনি কৰক"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string> + <string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string> </resources> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 50451e1126e8..4cb4017fcc06 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profil info"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Məhdudlaşdırılmış profil yaratmadan öncə, Siz tətbiqlərinizi və şəxsi datanızı qorumaq üçün ekran kilidi quraşdırmalısınız."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Kilid ayarlayın"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> adlı istifadəçiyə keçin"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string> </resources> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 0e39d7f99f29..839b85aca0aa 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -544,12 +544,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Podaci o profilu"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Da biste mogli da napravite ograničeni profil, treba da podesite zaključavanje ekrana da biste zaštitili aplikacije i lične podatke."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Podesi zaključavanje"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Pređi na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string> </resources> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index 328762c5361f..cc0d28645856 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Звесткi профiлю"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Перш чым вы зможаце стварыць профіль з абмежаваннямi, вам трэба наладзіць блакiроўку экрана для абароны сваiх дадаткаў і асабістай інфармацыі."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Усталёўка блакiроўкi"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Пераключыцца на карыстальніка <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Дадаць госця"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Выдаліць госця"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Госць"</string> </resources> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 690cc493ebe5..ef0951c623bf 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Инф. за потр. профил"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Преди да можете да създадете потребителски профил с ограничена функционалност, трябва да настроите заключения екран, за да защитите приложенията и личните си данни."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Задаване на заключване"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Превключване към <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Гост"</string> </resources> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 017936fc7b5e..1cd8eeae5ead 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"প্রোফাইল তথ্য"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"আপনি একটি সীমাবদ্ধযুক্ত প্রোফাইল তৈরি করার আগে, আপনাকে আপনার অ্যাপ্লিকেশন এবং ব্যক্তিগত ডেটা সুরক্ষিত করার জন্য একটি স্ক্রিন লক সেট-আপ করতে হবে।"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"লক সেট করুন"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>-এ পাল্টান"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ করুন"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি সরান"</string> + <string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string> </resources> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index a1b1afc77b06..c72411cc10e6 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -544,8 +544,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Podaci o profilu"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Prije nego vam se omogući kreiranje ograničenog profila, morate postaviti zaključavanje ekrana da biste zaštitili svoje aplikacije i lične podatke."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Postaviti zaključavanje"</string> - <string name="user_switch_to_user" msgid="6975428297154968543">"Prelazak na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string> - <string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string> - <string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string> + <string name="user_switch_to_user" msgid="6975428297154968543">"Prebaci na korisnika <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string> <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string> </resources> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index a1b2da8124dc..765d44259ce4 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Informació de perfil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Per crear un perfil restringit, has de configurar una pantalla de bloqueig per protegir les aplicacions i les dades personals."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Defineix un bloqueig"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Canvia a <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string> </resources> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index bbf29bb00303..ed2db3a730e7 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Informace o profilu"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Před vytvořením omezeného profilu je nutné nejprve nastavit zámek obrazovky k ochraně aplikací a dat."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Nastavit zámek"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Přepnout na uživatele <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Host"</string> </resources> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 20b7ae15eae5..f682b15deb98 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profiloplysninger"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Før du kan oprette en begrænset profil, skal du oprette en skærmlås for at beskytte dine apps og personlige data."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurer låseskærmen"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Skift til <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæsten"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gæst"</string> </resources> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 1a2898508a7d..7918022e5a37 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profilinformationen"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Vor dem Erstellen eines eingeschränkten Profils musst du eine Displaysperre einrichten, um deine Apps und personenbezogenen Daten zu schützen."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Sperre einrichten"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Zu <xliff:g id="USER_NAME">%s</xliff:g> wechseln"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gast"</string> </resources> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 9c1842a0d284..b4d7c875bf62 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Πληροφορίες προφίλ"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Προκειμένου να μπορέσετε να δημιουργήσετε ένα περιορισμένο προφίλ, θα πρέπει να δημιουργήσετε ένα κλείδωμα οθόνης για την προστασία των εφαρμογών και των προσωπικών δεδομένων σας."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Ορισμός κλειδώματος"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Εναλλαγή σε <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string> </resources> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index cc3cd11c8658..6cb975f799ab 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Datos del perfil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar un bloqueo de pantalla que proteja tus aplicaciones y datos personales."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Configurar bloqueo"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string> </resources> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index e85187b7443d..d77772364f77 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Información del perfil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restringido, debes configurar una pantalla de bloqueo que proteja tus aplicaciones y datos personales."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string> </resources> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index c9bd7a090e51..1fa41596a3ac 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profiili teave"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Enne piiratud profiili loomist peate seadistama lukustusekraani, et oma rakendusi ja isiklikke andmeid kaitsta."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Määra lukk"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Lülita kasutajale <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string> </resources> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 42c702aa3a8a..2700162afc03 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -235,7 +235,7 @@ <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Konektatu wifi-sare batera"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, araztu, gailua"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"Akatsen txostenerako lasterbidea"</string> - <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Bateriaren menuan, erakutsi akatsen txostena sortzeko botoia"</string> + <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Pizteko menuan, erakutsi akatsen txostena sortzeko botoia"</string> <string name="keep_screen_on" msgid="1187161672348797558">"Mantendu aktibo"</string> <string name="keep_screen_on_summary" msgid="1510731514101925829">"Pantaila ez da ezarriko inoiz inaktibo kargatu bitartean"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Gaitu Bluetooth HCI miatze-erregistroa"</string> @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profileko informazioa"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Profil murriztua sortu aurretik, aplikazioak eta datu pertsonalak babesteko, pantaila blokeatzeko metodo bat konfiguratu beharko duzu."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Ezarri blokeoa"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Aldatu <xliff:g id="USER_NAME">%s</xliff:g> erabiltzailera"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string> </resources> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 2a284ee2e6ce..1c32926772f9 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"اطلاعات نمایه"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"قبل از ایجاد یک نمایه محدود، باید یک قفل صفحه را برای محافظت از برنامهها و دادههای شخصی خود تنظیم کنید."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"تنظیم قفل"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"رفتن به <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"افزودن مهمان"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"حذف مهمان"</string> + <string name="guest_nickname" msgid="6332276931583337261">"مهمان"</string> </resources> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 76e8f5b72e4d..765e08edd552 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profiilin tiedot"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Ennen kuin voit luoda rajoitetun profiilin, määritä näytön lukitus, joka suojelee sovelluksiasi ja henkilökohtaisia tietojasi."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Aseta lukitus"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Vaihda tähän: <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string> </resources> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 4c599f0826ff..d118e1fcb013 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Informations de profil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applications et vos données personnelles."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Invité"</string> </resources> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 8e8f09dda20c..f2dcbbaed91b 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Informations de profil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Avant de créer un profil limité, vous devez définir un écran de verrouillage pour protéger vos applications et vos données personnelles."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Définir verrouillage écran"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Passer à <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Invité"</string> </resources> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index e17da89088c3..9ee490f09ae2 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Información do perfil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Para poder crear un perfil restrinxido, precisarás configurar un bloqueo da pantalla para protexer as túas aplicacións e datos persoais."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Establecer bloqueo"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Cambiar a <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string> </resources> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 207e07f70af5..2fced2bdb6cf 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"પ્રોફાઇલ માહિતી"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"તમે પ્રતિબંધિત પ્રોફાઇલ બનાવી શકો તે પહેલાં, તમારે તમારી ઍપ્લિકેશનો અને વ્યક્તિગત ડેટાની સુરક્ષા માટે એક લૉક સ્ક્રીન સેટ કરવાની જરૂર પડશે."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"લૉક સેટ કરો"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> પર સ્વિચ કરો"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string> + <string name="guest_nickname" msgid="6332276931583337261">"અતિથિ"</string> </resources> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 0c953137e33a..cb4110017241 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -514,7 +514,7 @@ <string name="shared_data_title" msgid="1017034836800864953">"शेयर किया गया डेटा"</string> <string name="shared_data_summary" msgid="5516326713822885652">"शेयर किए गए डेटा को देखें और उसमें बदलाव करें"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"इस उपयोगकर्ता के साथ किसी तरह का डेटा शेयर नहीं किया गया है."</string> - <string name="shared_data_query_failure_text" msgid="3489828881998773687">"शेयर किए गए इस डेटा को लाने में कोई गड़बड़ी हुई है. फिर से कोशिश करें."</string> + <string name="shared_data_query_failure_text" msgid="3489828881998773687">"शेयर किए गए डेटा को लाने में कोई गड़बड़ी हुई है. फिर से कोशिश करें."</string> <string name="blob_id_text" msgid="8680078988996308061">"शेयर किए गए डेटा का आईडी: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> <string name="blob_expires_text" msgid="7882727111491739331">"डेटा का ऐक्सेस <xliff:g id="DATE">%s</xliff:g> को खत्म हो जाएगा"</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"शेयर किए गए डेटा को मिटाने में कोई गड़बड़ी हुई."</string> @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफ़ाइल की जानकारी"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"इससे पहले कि आप कोई प्रतिबंधित प्रोफ़ाइल बनाएं, आपको अपने ऐप्लिकेशन और व्यक्तिगत डेटा की सुरक्षा करने के लिए एक स्क्रीन लॉक सेट करना होगा."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करें"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> पर जाएं"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string> + <string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string> </resources> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index d0fff2130aff..bb2f17cecab7 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profiladatok"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Mielőtt létrehozhatna egy korlátozott profilt, be kell állítania egy képernyőzárat, hogy megvédje alkalmazásait és személyes adatait."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Képernyőzár beállítása"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Váltás erre: <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string> </resources> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index a884c84e4a6f..9cc883a928d5 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Պրոֆիլի տեղեկություններ"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Նախքան դուք կկարողանաք ստեղծել սահմանափակ պրոֆիլ, դուք պետք է կարգավորեք էկրանի կողպումը` ձեր ծրագրերը և անձնական տվյալները պաշտպանելու համար:"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Կարգավորել կողպումը"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Անցնել <xliff:g id="USER_NAME">%s</xliff:g> պրոֆիլին"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Հյուր"</string> </resources> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 4022babee384..d80eba24066f 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -88,7 +88,7 @@ <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Akses Internet"</string> <string name="bluetooth_profile_pbap" msgid="7064307749579335765">"Berbagi kontak"</string> <string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"Gunakan untuk berbagi kontak"</string> - <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Berbagi sambungan internet"</string> + <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Berbagi koneksi internet"</string> <string name="bluetooth_profile_map" msgid="8907204701162107271">"SMS"</string> <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Akses SIM"</string> <string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"Audio HD: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string> @@ -103,7 +103,7 @@ <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Tidak tersambung kepada server transfer file"</string> <string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Terhubung ke perangkat masukan"</string> <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Terhubung ke perangkat untuk akses internet"</string> - <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Berbagi sambungan internet lokal dengan perangkat"</string> + <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Berbagi koneksi internet lokal dengan perangkat"</string> <string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"Digunakan untuk akses internet"</string> <string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Gunakan untuk peta"</string> <string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"Gunakan untuk akses SIM"</string> @@ -169,11 +169,11 @@ <string name="tts_install_data_title" msgid="1829942496472751703">"Instal data suara"</string> <string name="tts_install_data_summary" msgid="3608874324992243851">"Instal data suara yang dibutuhkan untuk sintesis suara"</string> <string name="tts_engine_security_warning" msgid="3372432853837988146">"Mesin sintesis suara ini mungkin dapat mengumpulkan semua teks yang akan diucapkan, termasuk di antaranya data pribadi seperti sandi dan nomor kartu kredit. Berasal dari <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> aplikasi. Gunakan metode masukan ini?"</string> - <string name="tts_engine_network_required" msgid="8722087649733906851">"Bahasa ini perlu sambungan jaringan yang bekerja untuk keluaran text-to-speech."</string> + <string name="tts_engine_network_required" msgid="8722087649733906851">"Bahasa ini perlu koneksi jaringan yang bekerja untuk keluaran text-to-speech."</string> <string name="tts_default_sample_string" msgid="6388016028292967973">"Ini adalah contoh sintesis suara"</string> <string name="tts_status_title" msgid="8190784181389278640">"Status bahasa default"</string> <string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> didukung sepenuhnya"</string> - <string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> membutuhkan sambungan jaringan"</string> + <string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> membutuhkan koneksi jaringan"</string> <string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> tidak didukung"</string> <string name="tts_status_checking" msgid="8026559918948285013">"Memeriksa…"</string> <string name="tts_engine_settings_title" msgid="7849477533103566291">"Setelan untuk <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string> @@ -514,11 +514,11 @@ <string name="shared_data_title" msgid="1017034836800864953">"Data bersama"</string> <string name="shared_data_summary" msgid="5516326713822885652">"Lihat dan ubah data bersama"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Tidak ada data yang dibagikan untuk pengguna ini."</string> - <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Terjadi kesalahan saat mengambil data yang dibagikan. Coba lagi."</string> + <string name="shared_data_query_failure_text" msgid="3489828881998773687">"Terjadi error saat mengambil data yang dibagikan. Coba lagi."</string> <string name="blob_id_text" msgid="8680078988996308061">"ID data bersama: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> <string name="blob_expires_text" msgid="7882727111491739331">"Berlaku sampai <xliff:g id="DATE">%s</xliff:g>"</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Terjadi error saat menghapus data yang dibagikan."</string> - <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Tidak ada sewa yang diperoleh dari data yang dibagikan. Apakah Anda ingin menghapusnya?"</string> + <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Tidak ada lease yang diperoleh dari data yang dibagikan ini. Apakah Anda ingin menghapusnya?"</string> <string name="accessor_info_title" msgid="8289823651512477787">"Aplikasi yang berbagi data"</string> <string name="accessor_no_description_text" msgid="7510967452505591456">"Tidak ada deskripsi yang disediakan oleh aplikasi."</string> <string name="accessor_expires_text" msgid="4625619273236786252">"Lease akan berakhir pada <xliff:g id="DATE">%s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 437e8262f156..2e96446f974d 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Upplýsingar um snið"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Áður en þú getur búið til takmarkað snið þarftu að setja upp skjálás til að vernda forritin þín og persónuleg gögn."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Velja lás"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Skipta yfir í <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string> </resources> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 86374f4bfe45..61f35abbe526 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"פרטי פרופיל"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"לפני שתוכל ליצור פרופיל מוגבל, תצטרך להגדיר נעילת מסך כדי להגן על האפליקציות ועל הנתונים האישיים שלך."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"הגדרת נעילה"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"מעבר אל <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"הוספת אורח"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"הסרת אורח"</string> + <string name="guest_nickname" msgid="6332276931583337261">"אורח"</string> </resources> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index ba8418bbe736..ea9cfd8a7d51 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"プロファイル情報"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"制限付きプロファイルを作成する場合は、アプリや個人データを保護するように画面ロックを設定しておく必要があります。"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"ロックを設定"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> に切り替え"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"ゲストを追加"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"ゲストを削除"</string> + <string name="guest_nickname" msgid="6332276931583337261">"ゲスト"</string> </resources> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index da5ff9b8a6f6..106bc18f8451 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ინფორმაცია პროფილზე"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"შეზღუდული პროფილის შექმნამდე, საკუთარი აპლიკაციებისა და პირადი მონაცემების დასაცავად, უნდა დაბლოკოთ ეკრანი."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"საკეტის დაყენება"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>-ზე გადართვა"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"სტუმრის დამატება"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"სტუმრის ამოშლა"</string> + <string name="guest_nickname" msgid="6332276931583337261">"სტუმარი"</string> </resources> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index e74f52b02ce1..0ef83bb183cb 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Профильдік ақпарат"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Шектелген профайл жасақтауға дейін қолданбалар мен жеке деректерді қорғау үшін экран бекітпесін тағайындау қажет."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Бекітпе тағайындау"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> атты пайдаланушыға ауысу"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Қонақты енгізу"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты өшіру"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string> </resources> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index c51f9a69f39c..4cf8beda4098 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -518,7 +518,7 @@ <string name="blob_id_text" msgid="8680078988996308061">"លេខសម្គាល់ទិន្នន័យដែលបានចែករំលែក៖ <xliff:g id="BLOB_ID">%d</xliff:g>"</string> <string name="blob_expires_text" msgid="7882727111491739331">"ផុតកំណត់នៅថ្ងៃទី <xliff:g id="DATE">%s</xliff:g>"</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"មានបញ្ហាក្នុងការលុបទិន្នន័យដែលបានចែករំលែក។"</string> - <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"មិនមានការជួលដែលបានទទួលសម្រាប់ទិន្នន័យដែលបានចែករំលែកនេះទេ។ តើអ្នកចង់លុបទិន្នន័យនេះដែរទេ?"</string> + <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"មិនមានភតិសន្យាដែលបានទទួលសម្រាប់ទិន្នន័យដែលបានចែករំលែកនេះទេ។ តើអ្នកចង់លុបទិន្នន័យនេះដែរទេ?"</string> <string name="accessor_info_title" msgid="8289823651512477787">"កម្មវិធីដែលកំពុងចែករំលែកទិន្នន័យ"</string> <string name="accessor_no_description_text" msgid="7510967452505591456">"គ្មានការពណ៌នាដែលផ្ដល់ដោយកម្មវិធីទេ។"</string> <string name="accessor_expires_text" msgid="4625619273236786252">"ភតិសន្យាផុតកំណត់នៅថ្ងៃទី <xliff:g id="DATE">%s</xliff:g>"</string> @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ព័ត៌មានប្រវត្តិរូប"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"មុនពេលអ្នកអាចបង្កើតប្រវត្តិរូបបានដាក់កម្រិត អ្នកត្រូវរៀបចំការចាក់សោអេក្រង់ ដើម្បីការពារកម្មវិធី និងទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នក។"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"កំណត់ការចាក់សោ"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"ប្ដូរទៅ <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូលភ្ញៀវ"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"លុបភ្ញៀវ"</string> + <string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string> </resources> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 9e37fbc9c5fa..ed854ac3af49 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -232,8 +232,7 @@ <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ವಿಳಾಸ ಮತ್ತು ಪೋರ್ಟ್"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR ಕೋಡ್ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string> <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"QR ಕೋಡ್ ಅನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡುವ ಮೂಲಕ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ನಲ್ಲಿ ಸಾಧನವನ್ನು ಜೋಡಿಸಿ"</string> - <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) --> - <skip /> + <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸಂಪರ್ಕಿಸಿ"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ಡೀಬಗ್, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ದೋಷ ವರದಿಯ ಶಾರ್ಟ್ಕಟ್"</string> <string name="bugreport_in_power_summary" msgid="1885529649381831775">"ದೋಷ ವರದಿ ಮಾಡಲು ಪವರ್ ಮೆನುನಲ್ಲಿ ಬಟನ್ ತೋರಿಸು"</string> @@ -432,8 +431,7 @@ <string name="power_discharge_by" msgid="4113180890060388350">"<xliff:g id="TIME">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>) ಸಮಯದವರೆಗೆ ಫೋನ್ ರನ್ ಆಗಬೇಕು"</string> <string name="power_discharge_by_only" msgid="92545648425937000">"<xliff:g id="TIME">%1$s</xliff:g> ಸಮಯದವರೆಗೆ ಫೋನ್ ರನ್ ಆಗಬೇಕು"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> ರವರೆಗೆ"</string> - <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) --> - <skip /> + <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"<xliff:g id="TIME">%1$s</xliff:g> ಗಳಲ್ಲಿ ಬ್ಯಾಟರಿ ಮುಕ್ತಾಯವಾಗಬಹುದು"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ನಿಮಿಷಕ್ಕಿಂತ ಕಡಿಮೆ ಸಮಯ ಉಳಿದಿದೆ"</string> <string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ಕ್ಕಿಂತ ಕಡಿಮೆ (<xliff:g id="LEVEL">%2$s</xliff:g>) ಬಾಕಿ"</string> <string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಕ್ಕಿಂತ ಹೆಚ್ಚು (<xliff:g id="LEVEL">%2$s</xliff:g>) ಬಾಕಿ"</string> @@ -511,32 +509,21 @@ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ಫೋನ್ ಸ್ಪೀಕರ್"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ಕನೆಕ್ಟ್ ಮಾಡುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ ಸಾಧನವನ್ನು ಆಫ್ ಮಾಡಿ ಹಾಗೂ ನಂತರ ಪುನಃ ಆನ್ ಮಾಡಿ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ವೈರ್ ಹೊಂದಿರುವ ಆಡಿಯೋ ಸಾಧನ"</string> - <!-- no translation found for help_label (3528360748637781274) --> - <skip /> - <!-- no translation found for storage_category (2287342585424631813) --> - <skip /> - <!-- no translation found for shared_data_title (1017034836800864953) --> - <skip /> - <!-- no translation found for shared_data_summary (5516326713822885652) --> - <skip /> + <string name="help_label" msgid="3528360748637781274">"ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"</string> + <string name="storage_category" msgid="2287342585424631813">"ಸಂಗ್ರಹಣೆ"</string> + <string name="shared_data_title" msgid="1017034836800864953">"ಹಂಚಿಕೊಳ್ಳಲಾದ ಡೇಟಾ"</string> + <string name="shared_data_summary" msgid="5516326713822885652">"ಹಂಚಿಕೊಳ್ಳಲಾದ ಡೇಟಾವನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಮಾರ್ಪಡಿಸಿ"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ಈ ಬಳಕೆದಾರರಿಗೆ ಯಾವುದೇ ಹಂಚಿದ ಡೇಟಾ ಇಲ್ಲ."</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"ಹಂಚಿದ ಡೇಟಾವನ್ನು ಪಡೆಯುವಲ್ಲಿ ದೋಷ ಕಂಡುಬಂದಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> - <!-- no translation found for blob_id_text (8680078988996308061) --> - <skip /> - <!-- no translation found for blob_expires_text (7882727111491739331) --> - <skip /> + <string name="blob_id_text" msgid="8680078988996308061">"ಹಂಚಿಕೊಳ್ಳಲಾದ ಡೇಟಾ ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> + <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> ರಂದು ಅವಧಿ ಮುಕ್ತಾಯವಾಗಲಿದೆ"</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"ಹಂಚಿದ ಡೇಟಾವನ್ನು ಅಳಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ."</string> <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ಈ ಹಂಚಿದ ಡೇಟಾವನ್ನು ಗುತ್ತಿಗೆಗೆ ಪಡೆದಿಲ್ಲ. ನೀವು ಅದನ್ನು ಅಳಿಸಲು ಬಯಸುವಿರಾ?"</string> - <!-- no translation found for accessor_info_title (8289823651512477787) --> - <skip /> - <!-- no translation found for accessor_no_description_text (7510967452505591456) --> - <skip /> - <!-- no translation found for accessor_expires_text (4625619273236786252) --> - <skip /> - <!-- no translation found for delete_blob_text (2819192607255625697) --> - <skip /> - <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) --> - <skip /> + <string name="accessor_info_title" msgid="8289823651512477787">"ಹಂಚಿಕೊಂಡ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸುವ ಆ್ಯಪ್ಗಳು"</string> + <string name="accessor_no_description_text" msgid="7510967452505591456">"ಆ್ಯಪ್ನಿಂದ ಯಾವುದೇ ವಿವರಣೆಯನ್ನು ಒದಗಿಸಲಾಗಿಲ್ಲ."</string> + <string name="accessor_expires_text" msgid="4625619273236786252">"<xliff:g id="DATE">%s</xliff:g> ರಂದು ಗುತ್ತಿಗೆ ಅವಧಿ ಮುಗಿಯುತ್ತದೆ"</string> + <string name="delete_blob_text" msgid="2819192607255625697">"ಹಂಚಿಕೊಳ್ಳಲಾದ ಡೇಟಾವನ್ನು ಅಳಿಸಿ"</string> + <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"ಈ ಹಂಚಿಕೊಳ್ಳಲಾದ ಡೇಟಾವನ್ನು ಅಳಿಸಲು ನೀವು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?"</string> <string name="user_add_user_item_summary" msgid="5748424612724703400">"ಬಳಕೆದಾರರು ತಮ್ಮದೇ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವಿಷಯವನ್ನು ಹೊಂದಿದ್ದಾರೆ"</string> <string name="user_add_profile_item_summary" msgid="5418602404308968028">"ನಿಮ್ಮ ಖಾತೆಯಿಂದ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವಿಷಯಕ್ಕೆ ಪ್ರವೇಶವನ್ನು ನೀವು ನಿರ್ಬಂಧಿಸಬಹುದು"</string> <string name="user_add_user_item_title" msgid="2394272381086965029">"ಬಳಕೆದಾರ"</string> @@ -556,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ಪ್ರೊಫೈಲ್ ಮಾಹಿತಿ"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ನೀವು ನಿರ್ಬಂಧಿತ ಪ್ರೊಫೈಲ್ ಅನ್ನು ರಚಿಸಬಹುದಾದರ ಮೊದಲು, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ನೀವು ಪರದೆಯ ಲಾಕ್ ಹೊಂದಿಸುವ ಅಗತ್ಯವಿದೆ."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> ಗೆ ಬದಲಿಸಿ"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string> + <string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string> </resources> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index cd69dd6779cd..6f642c3f59ee 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"프로필 정보"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"제한된 프로필을 만들기 전에 화면 잠금을 설정하여 앱과 개인 데이터를 보호해야 합니다."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"잠금 설정"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>(으)로 전환"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"게스트 추가"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"게스트 삭제"</string> + <string name="guest_nickname" msgid="6332276931583337261">"게스트"</string> </resources> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index c05fd66e0343..417e5115ba5a 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Профилдин чоо-жайы"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Чектелген профайл түзөөрдөн мурун, сиз өзүңүздүн колдонмолоруңузду жана жеке маалыматтарыңызды коргош үчүн, бөгөттөө көшөгөсүн орнотушуңуз керек болот."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Бөгөт коюу"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> аккаунтуна которулуу"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Конок кошуу"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Конокту өчүрүү"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Конок"</string> </resources> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 4591ca0d9fe1..94800ea8b3a7 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profilio informacija"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Prieš kuriant apribotą profilį reikės nustatyti ekrano užraktą, kad apsaugotumėte programas ir asmeninius duomenis."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Nustatyti užraktą"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Perjungti į <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string> </resources> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index c36b7f4487dc..d7816aa54a1a 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -544,12 +544,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profila informācija"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Lai varētu izveidot ierobežotu profilu, jums jāiestata ekrāna bloķēšana, kas aizsargās jūsu lietotni un personas datus."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Iestatīt bloķēšanu"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Pārslēgties uz: <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string> </resources> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index bde3e9267173..c593bee5e1f6 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"പ്രൊഫൈൽ വിവരം"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ഒരു നിയന്ത്രിത പ്രൊഫൈൽ സൃഷ്ടിക്കുന്നതിനുമുമ്പ്, നിങ്ങളുടെ അപ്ലിക്കേഷനുകളും വ്യക്തിഗത ഡാറ്റയും പരിരക്ഷിക്കുന്നതിന് ഒരു സ്ക്രീൻ ലോക്ക് സജ്ജീകരിക്കേണ്ടതുണ്ട്."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"ലോക്ക് സജ്ജീകരിക്കുക"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> എന്നതിലേക്ക് മാറുക"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string> + <string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string> </resources> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 38c8b8662ee2..d3e41f727409 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Профайлын мэдээлэл"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Та хязгаарлагдсан профайл үүсгэхийн өмнө өөрийн апп-ууд болон хувийн өгөгдлийг хамгаалахын тулд дэлгэцийн түгжээг тохируулах шаардлагатай."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Түгжээг тохируулах"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> руу сэлгэх"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string> </resources> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 746ef576cff3..c222bd353890 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफाइल माहिती"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"तुम्ही एक प्रतिबंधित प्रोफाईल तयार करु शकण्यापूर्वी तुम्हाला तुमचे अॅप्स आणि वैयक्तिक डेटा संरक्षित करण्यासाठी एक स्क्रीन लॉक सेट करण्याची आवश्यकता राहील."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"लॉक सेट करा"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> वर स्विच करा"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string> + <string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string> </resources> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 5e400e37194d..1dc3dc4fbdb2 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Maklumat profil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Sebelum anda boleh membuat profil yang terhad, anda perlu menyediakan kunci skrin untuk melindungi apl dan data peribadi anda."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Tetapkan kunci"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Tukar kepada <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Tetamu"</string> </resources> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index b71f842d1783..58213a7cef04 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profilinformasjon"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Før du kan opprette en begrenset profil, må du konfigurere skjermlåsen for å beskytte appene og de personlige dataene dine."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Angi lås"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Bytt til <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string> </resources> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 79fd4698c1ae..cc26483b791b 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -431,7 +431,7 @@ <string name="power_discharge_by" msgid="4113180890060388350">"ब्याट्री लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="92545648425937000">"लगभग <xliff:g id="TIME">%1$s</xliff:g> सम्म टिक्नु पर्छ"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> सम्म"</string> - <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"ब्याट्री <xliff:g id="TIME">%1$s</xliff:g> बजेभित्र सकिन सक्छ"</string> + <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"ब्याट्री <xliff:g id="TIME">%1$s</xliff:g> बजेसम्ममा सकिन सक्छ"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी छ"</string> <string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g> भन्दा कम समय बाँकी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> भन्दा बढी समय बाँकी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -513,16 +513,12 @@ <string name="storage_category" msgid="2287342585424631813">"भण्डारण"</string> <string name="shared_data_title" msgid="1017034836800864953">"साझा डेटा"</string> <string name="shared_data_summary" msgid="5516326713822885652">"साझा डेटा हेर्नुहोस् र परिमार्जन गर्नुहोस्"</string> - <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) --> - <skip /> - <!-- no translation found for shared_data_query_failure_text (3489828881998773687) --> - <skip /> + <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"यो प्रयोगकर्तासँग कुनै पनि डेटा सेयर गरिएको छैन।"</string> + <string name="shared_data_query_failure_text" msgid="3489828881998773687">"सेयर गरिएको डेटा प्राप्त गर्ने क्रममा कुनै त्रुटि भयो। फेरि प्रयास गर्नुहोस्।"</string> <string name="blob_id_text" msgid="8680078988996308061">"साझा डेटाको ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g> मा म्याद सकिन्छ"</string> - <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) --> - <skip /> - <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) --> - <skip /> + <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"सेयर गरिएको डेटा मेट्ने क्रममा त्रुटि भयो।"</string> + <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"सेयर गरिएको यो डेटाका लागि कुनै ठेक्का पट्टा लिएको छैन। तपाईं यसलाई मेट्न चाहनुहुन्छ?"</string> <string name="accessor_info_title" msgid="8289823651512477787">"साझा डेटा प्रयोग गर्ने अनुप्रयोगहरू"</string> <string name="accessor_no_description_text" msgid="7510967452505591456">"यो अनुप्रयोगले कुनै विवरण प्रदान गरेको छैन।"</string> <string name="accessor_expires_text" msgid="4625619273236786252">"लिजको म्याद <xliff:g id="DATE">%s</xliff:g> मा सकिन्छ"</string> @@ -547,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"प्रोफाइल जानकारी"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"निषेधयुक्त प्रोफाइल बनाउनु अघि तपाईँको अनुप्रयोग र व्यक्तिगत डेटा सुरक्षा गर्नाका लागि तपाईँले स्क्रिन लक सेटअप गर्नु पर्दछ ।"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"लक सेट गर्नुहोस्"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"प्रयोगकर्ता बदलेर <xliff:g id="USER_NAME">%s</xliff:g> पार्नुहोस्"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"अतिथि हटाउनुहोस्"</string> + <string name="guest_nickname" msgid="6332276931583337261">"अतिथि"</string> </resources> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index c780d6ae633f..57fc87aa8d6f 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profielinfo"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Voordat je een beperkt profiel kunt maken, moet je een schermvergrendeling instellen om je apps en persoonsgegevens te beschermen."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Vergrendeling instellen"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Overschakelen naar <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gast"</string> </resources> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 82cfbe3a6ce8..3a7f2c5acaa6 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -232,8 +232,7 @@ <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP ଠିକଣା ଓ ପୋର୍ଟ"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR କୋଡ୍ ସ୍କାନ୍ କରନ୍ତୁ"</string> <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"ଏକ QR କୋଡ୍ ସ୍କାନ୍ କରି ୱାଇ-ଫାଇରେ ଡିଭାଇସ୍ ପେୟାର୍ କରନ୍ତୁ"</string> - <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) --> - <skip /> + <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"ଦୟାକରି ଏକ ୱାଇ-ଫାଇ ନେଟୱାର୍କରେ ସଂଯୋଗ କରନ୍ତୁ"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, ଡିବଗ୍, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"ବଗ୍ ରିପୋର୍ଟ ସର୍ଟକଟ୍"</string> <string name="bugreport_in_power_summary" msgid="1885529649381831775">"ବଗ୍ ରିପୋର୍ଟ ଦେବାପାଇଁ ପାୱାର୍ ମେନୁରେ ଏକ ବଟନ୍ ଦେଖନ୍ତୁ"</string> @@ -432,8 +431,7 @@ <string name="power_discharge_by" msgid="4113180890060388350">"ବ୍ୟାଟେରୀ ପାଖାପାଖି <xliff:g id="TIME">%1$s</xliff:g> ଚାଲିବ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="92545648425937000">"ବ୍ୟାଟେରୀ <xliff:g id="TIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ ଚାଲିବ"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> ପର୍ଯ୍ୟନ୍ତ"</string> - <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) --> - <skip /> + <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"<xliff:g id="TIME">%1$s</xliff:g> ସୁଦ୍ଧା ବ୍ୟାଟେରୀର ଚାର୍ଜ ଶେଷ ହୋଇ ଯାଇପାରେ"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g>ରୁ କମ୍ ସମୟ ବଳକା ଅଛି"</string> <string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g> ରୁ କମ୍ ସମୟ ବଳକା ଅଛି (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g>ରୁ ଅଧିକ ସମୟ ବଳକା ଅଛି(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -511,32 +509,21 @@ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ଫୋନ୍ ସ୍ପିକର୍"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"ସଂଯୋଗ କରିବାରେ ସମସ୍ୟା ହେଉଛି। ଡିଭାଇସ୍ ବନ୍ଦ କରି ପୁଣି ଚାଲୁ କରନ୍ତୁ"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"ତାରଯୁକ୍ତ ଅଡିଓ ଡିଭାଇସ୍"</string> - <!-- no translation found for help_label (3528360748637781274) --> - <skip /> - <!-- no translation found for storage_category (2287342585424631813) --> - <skip /> - <!-- no translation found for shared_data_title (1017034836800864953) --> - <skip /> - <!-- no translation found for shared_data_summary (5516326713822885652) --> - <skip /> + <string name="help_label" msgid="3528360748637781274">"ସାହାଯ୍ୟ ଓ ମତାମତ"</string> + <string name="storage_category" msgid="2287342585424631813">"ଷ୍ଟୋରେଜ୍"</string> + <string name="shared_data_title" msgid="1017034836800864953">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା"</string> + <string name="shared_data_summary" msgid="5516326713822885652">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଦେଖନ୍ତୁ ଏବଂ ଏହାକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ଏହି ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ପାଇଁ କୌଣସି ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ନାହିଁ।"</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଫେଚ୍ କରିବା ସମୟରେ ଏକ ତ୍ରୁଟି ହୋଇଥିଲା। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> - <!-- no translation found for blob_id_text (8680078988996308061) --> - <skip /> - <!-- no translation found for blob_expires_text (7882727111491739331) --> - <skip /> + <string name="blob_id_text" msgid="8680078988996308061">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> + <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g>ରେ ମିଆଦ ଶେଷ ହେଉଛି"</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଡିଲିଟ୍ କରିବା ସମୟରେ ଏକ ତ୍ରୁଟି ହୋଇଥିଲା।"</string> <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ସେୟାର୍ କରାଯାଇଥିବା ଏହି ଡାଟା ପାଇଁ କୌଣସି ଲିଜ୍ ପ୍ରାପ୍ତ ହୋଇନାହିଁ। ଆପଣ ଏହା ଡିଲିଟ୍ କରିବାକୁ ଚାହୁଁଛନ୍ତି କି?"</string> - <!-- no translation found for accessor_info_title (8289823651512477787) --> - <skip /> - <!-- no translation found for accessor_no_description_text (7510967452505591456) --> - <skip /> - <!-- no translation found for accessor_expires_text (4625619273236786252) --> - <skip /> - <!-- no translation found for delete_blob_text (2819192607255625697) --> - <skip /> - <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) --> - <skip /> + <string name="accessor_info_title" msgid="8289823651512477787">"ଡାଟା ସେୟାର୍ କରୁଥିବା ଆପଗୁଡ଼ିକ"</string> + <string name="accessor_no_description_text" msgid="7510967452505591456">"ଆପ୍ ଦ୍ୱାରା କୌଣସି ବର୍ଣ୍ଣନା ପ୍ରଦାନ କରାଯାଇନାହିଁ।"</string> + <string name="accessor_expires_text" msgid="4625619273236786252">"<xliff:g id="DATE">%s</xliff:g>ରେ ଲିଜର ମିଆଦ ଶେଷ ହେଉଛି"</string> + <string name="delete_blob_text" msgid="2819192607255625697">"ସେୟାର୍ କରାଯାଇଥିବା ଡାଟା ଡିଲିଟ୍ କରନ୍ତୁ"</string> + <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"ଆପଣ ସେୟାର୍ କରାଯାଇଥିବା ଏହି ଡାଟା ଡିଲିଟ୍ କରିବାକୁ ଚାହୁଁଥିବା ନିଶ୍ଚିତ କି?"</string> <string name="user_add_user_item_summary" msgid="5748424612724703400">"ଉପଯୋଗକର୍ତ୍ତାମାନଙ୍କ ପାଖରେ ନିଜର ଆପ୍ ଓ କଣ୍ଟେଣ୍ଟ ଅଛି"</string> <string name="user_add_profile_item_summary" msgid="5418602404308968028">"ନିଜ ଆକାଉଣ୍ଟରୁ ଆପ୍ ତଥା କଣ୍ଟେଣ୍ଟକୁ ଆପଣ ଆକ୍ସେସ୍ ରୋକିପାରିବେ"</string> <string name="user_add_user_item_title" msgid="2394272381086965029">"ଉପଯୋଗକର୍ତ୍ତା"</string> @@ -556,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ପ୍ରୋଫାଇଲ୍ ସୂଚନା"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ପ୍ରତିବନ୍ଧିତ ପ୍ରୋଫାଇଲ୍ ତିଆରି କରିବାବେଳେ, ନିଜ ଆପ୍ ଓ ବ୍ୟକ୍ତିଗତ ତଥ୍ୟର ସୁରକ୍ଷା ପାଇଁ ଏକ ସ୍କ୍ରୀନ୍ ଲକ୍ ସେଟ୍ କରନ୍ତୁ।"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"ଲକ୍ ସେଟ୍ କରନ୍ତୁ"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>କୁ ସ୍ୱିଚ୍ କରନ୍ତୁ"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"ଅତିଥି ଯୋଗ କରନ୍ତୁ"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"ଅତିଥିଙ୍କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string> + <string name="guest_nickname" msgid="6332276931583337261">"ଅତିଥି"</string> </resources> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 52ba6045c634..980225710156 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ਪ੍ਰੋਫਾਈਲ ਜਾਣਕਾਰੀ"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ਇਸਤੋਂ ਪਹਿਲਾਂ ਕਿ ਤੁਸੀਂ ਇੱਕ ਪ੍ਰਤਿਬੰਧਿਤ ਪ੍ਰੋਫਾਈਲ ਬਣਾ ਸਕੋ, ਤੁਹਾਨੂੰ ਆਪਣੀਆਂ ਐਪਾਂ ਅਤੇ ਨਿੱਜੀ ਡਾਟਾ ਸੁਰੱਖਿਅਤ ਕਰਨ ਲਈ ਇੱਕ ਸਕ੍ਰੀਨ ਲਾਕ ਸੈੱਟ ਅੱਪ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।"</string> <string name="user_set_lock_button" msgid="1427128184982594856">" ਲਾਕ ਸੈੱਟ ਕਰੋ"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> \'ਤੇ ਜਾਓ"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"ਮਹਿਮਾਨ ਸ਼ਾਮਲ ਕਰੋ"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"ਮਹਿਮਾਨ ਹਟਾਓ"</string> + <string name="guest_nickname" msgid="6332276931583337261">"ਮਹਿਮਾਨ"</string> </resources> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 602e1796155e..734b25757bfc 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Informacje o profilu"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Zanim utworzysz profil z ograniczeniami, musisz skonfigurować ekran blokady, by chronić aplikacje i osobiste dane."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Ustaw blokadę"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Przełącz na: <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gość"</string> </resources> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 90ce2a973762..586040944b9e 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -544,12 +544,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Informații de profil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Înainte de a putea crea un profil cu permisiuni limitate, va trebui să configurați blocarea ecranului pentru a vă proteja aplicațiile și datele personale."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Configurați blocarea"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Comutați la <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string> </resources> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 71b231c5be6f..ab230b768f20 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -278,7 +278,7 @@ <string name="private_dns_mode_off" msgid="7065962499349997041">"Отключено"</string> <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Автоматический режим"</string> <string name="private_dns_mode_provider" msgid="3619040641762557028">"Имя хоста поставщика персонального DNS-сервера"</string> - <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Введите имя хоста поставщика услуг DNS"</string> + <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Введите имя хоста поставщика DNS"</string> <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Ошибка подключения"</string> <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Показывать параметры сертификации беспроводных мониторов"</string> <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Вести подробный журнал, показывать RSSI для каждого SSID при выборе сети"</string> @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Информация о профиле"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Чтобы создать профиль с ограниченным доступом, необходимо предварительно настроить блокировку экрана для защиты приложений и личных данных"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Включить блокировку"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Переключиться на этот аккаунт: <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Добавить аккаунт гостя"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Гость"</string> </resources> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 0e2cd8499122..73cfce1d73d7 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Informácie o profile"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Pred vytvorením obmedzeného profilu je nutné najprv nastaviť zámku obrazovky na ochranu aplikácií a osobných údajov."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Nastaviť uzamknutie"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Prepnúť na používateľa <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string> </resources> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index f3bba52594a9..8e3782c1b11c 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Podatki za profil"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Preden lahko ustvarite profil z omejitvami, morate nastaviti zaklepanje zaslona, da zaščitite aplikacije in osebne podatke."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Nastavi zaklepanje"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Preklop na račun <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gost"</string> </resources> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 2cd2393ab374..6d1e80a0f341 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Inform. i profilit"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Para se të mund të krijosh një profil të kufizuar, duhet të konfigurosh një kyçje të ekranit për të mbrojtur aplikacionet dhe të dhënat e tua personale."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Cakto kyçjen"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Kalo te <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string> + <string name="guest_nickname" msgid="6332276931583337261">"I ftuar"</string> </resources> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 102d9252b629..775b7d504e1e 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -544,12 +544,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Подаци о профилу"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Да бисте могли да направите ограничени профил, треба да подесите закључавање екрана да бисте заштитили апликације и личне податке."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Подеси закључавање"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Пређи на корисника <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Гост"</string> </resources> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index 50297a7dd97d..e40ba29eadc1 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profilinfo"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Innan du skapar en begränsad profil måste du konfigurera ett skärmlås för att skydda dina appar och personliga data."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Konfigurera lås"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Byt till <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string> </resources> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index bfa120867901..815896df5512 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Maelezo ya wasifu"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Kabla uunde wasifu uliowekekwa vikwazo, utahitajika kuweka skrini iliyofungwa ili kulinda programu zako na data binafsi."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Weka ufunguo"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Badili utumie <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Weka mgeni"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Mgeni"</string> </resources> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 98bb0caf95ee..5080c31c27d7 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -418,8 +418,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"வண்ணத்திருத்தம்"</string> - <!-- no translation found for accessibility_display_daltonizer_preference_subtitle (1284746051652993443) --> - <skip /> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"வண்ணத் திருத்தத்தைப் பயன்படுத்தி உங்கள் சாதனத்தில் வண்ணம் காண்பிக்கப்படும் விதத்தைச் சரிசெய்யலாம்"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index a36b6a3d764c..0e763ddc7207 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -232,8 +232,7 @@ <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP చిరునామా & పోర్ట్"</string> <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR కోడ్ను స్కాన్ చేయండి"</string> <string name="adb_wireless_qrcode_pairing_description" msgid="8578868049289910131">"పరికరాన్ని Wi-Fi ద్వారా పెయిర్ చేయడానికి QR కోడ్ను స్కాన్ చేయండి"</string> - <!-- no translation found for adb_wireless_no_network_msg (2365795244718494658) --> - <skip /> + <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"దయచేసి Wi-Fi నెట్వర్క్కు కనెక్ట్ చేయండి"</string> <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, డీబగ్, dev"</string> <string name="bugreport_in_power" msgid="8664089072534638709">"బగ్ నివేదిక షార్ట్కట్"</string> <string name="bugreport_in_power_summary" msgid="1885529649381831775">"బగ్ నివేదికను తీసుకోవడానికి పవర్ మెనూలో బటన్ను చూపు"</string> @@ -418,7 +417,7 @@ <string name="daltonizer_mode_protanomaly" msgid="7805583306666608440">"ప్రొటానోమలీ (ఎరుపు-ఆకుపచ్చ రంగు)"</string> <string name="daltonizer_mode_tritanomaly" msgid="7135266249220732267">"ట్రైటనోమలీ (నీలం-పసుపు రంగు)"</string> <string name="accessibility_display_daltonizer_preference_title" msgid="1810693571332381974">"రంగు సవరణ"</string> - <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"రంగుల సరి చేసే ఫీచర్తో మీరు మీ పరికరంలో రంగులో కనిపించే పద్ధతిని సర్దుబాటు చేయగలుగుతారు"</string> + <string name="accessibility_display_daltonizer_preference_subtitle" msgid="1284746051652993443">"రంగులు సరి చేసే ఫీచర్ సాయంతో, మీ పరికరంలో రంగులు కనిపించే పద్ధతిని మీరు సర్దుబాటు చేయగలుగుతారు"</string> <string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ద్వారా భర్తీ చేయబడింది"</string> <string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string> <string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string> @@ -432,8 +431,7 @@ <string name="power_discharge_by" msgid="4113180890060388350">"దాదాపు <xliff:g id="TIME">%1$s</xliff:g> వరకు ఉండాలి (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_discharge_by_only" msgid="92545648425937000">"దాదాపు <xliff:g id="TIME">%1$s</xliff:g> వరకు ఉండాలి"</string> <string name="power_discharge_by_only_short" msgid="5883041507426914446">"<xliff:g id="TIME">%1$s</xliff:g> వరకు"</string> - <!-- no translation found for power_suggestion_battery_run_out (6332089307827787087) --> - <skip /> + <string name="power_suggestion_battery_run_out" msgid="6332089307827787087">"బ్యాటరీ <xliff:g id="TIME">%1$s</xliff:g> సమయానికి ఖాళీ అవ్వచ్చు"</string> <string name="power_remaining_less_than_duration_only" msgid="5802195288324091585">"<xliff:g id="THRESHOLD">%1$s</xliff:g> కంటే తక్కువ సమయం మిగిలి ఉంది"</string> <string name="power_remaining_less_than_duration" msgid="1812668275239801236">"<xliff:g id="THRESHOLD">%1$s</xliff:g> కంటే తక్కువ సమయం మిగిలి ఉంది (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> <string name="power_remaining_more_than_subtext" msgid="7919119719242734848">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> కంటే ఎక్కువ సమయం మిగిలి ఉంది (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string> @@ -511,32 +509,21 @@ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"ఫోన్ స్పీకర్"</string> <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"కనెక్ట్ చేయడంలో సమస్య ఉంది. పరికరాన్ని ఆఫ్ చేసి, ఆపై తిరిగి ఆన్ చేయండి"</string> <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"వైర్ గల ఆడియో పరికరం"</string> - <!-- no translation found for help_label (3528360748637781274) --> - <skip /> - <!-- no translation found for storage_category (2287342585424631813) --> - <skip /> - <!-- no translation found for shared_data_title (1017034836800864953) --> - <skip /> - <!-- no translation found for shared_data_summary (5516326713822885652) --> - <skip /> + <string name="help_label" msgid="3528360748637781274">"సహాయం & అభిప్రాయం"</string> + <string name="storage_category" msgid="2287342585424631813">"నిల్వ"</string> + <string name="shared_data_title" msgid="1017034836800864953">"షేర్ చేసిన డేటా"</string> + <string name="shared_data_summary" msgid="5516326713822885652">"షేర్ చేసిన డేటాను చూసి, సవరించండి"</string> <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ఈ యూజర్ కోసం షేర్ చేసిన డేటా ఏదీ లేదు."</string> <string name="shared_data_query_failure_text" msgid="3489828881998773687">"షేర్ చేసిన డేటా పొందడంలో ఎర్రర్ ఏర్పడింది. మళ్లీ ట్రై చేయండి."</string> - <!-- no translation found for blob_id_text (8680078988996308061) --> - <skip /> - <!-- no translation found for blob_expires_text (7882727111491739331) --> - <skip /> + <string name="blob_id_text" msgid="8680078988996308061">"షేర్ చేసిన డేటా ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> + <string name="blob_expires_text" msgid="7882727111491739331">"<xliff:g id="DATE">%s</xliff:g>న గడువు ముగుస్తుంది"</string> <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"షేర్ చేసిన డేటాను తొలగించడంలో ఎర్రర్ ఏర్పడింది."</string> <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ఈ షేర్ చేసిన డేటాకు సేకరించబడిన లీజులు ఏవీ లేవు. దీన్ని మీరు తొలగించాలనుకుంటున్నారా?"</string> - <!-- no translation found for accessor_info_title (8289823651512477787) --> - <skip /> - <!-- no translation found for accessor_no_description_text (7510967452505591456) --> - <skip /> - <!-- no translation found for accessor_expires_text (4625619273236786252) --> - <skip /> - <!-- no translation found for delete_blob_text (2819192607255625697) --> - <skip /> - <!-- no translation found for delete_blob_confirmation_text (7807446938920827280) --> - <skip /> + <string name="accessor_info_title" msgid="8289823651512477787">"యాప్ల షేరింగ్ డేటా"</string> + <string name="accessor_no_description_text" msgid="7510967452505591456">"యాప్ ద్వారా ఎలాంటి వివరణ అందించబడలేదు."</string> + <string name="accessor_expires_text" msgid="4625619273236786252">"లీజు గడువు <xliff:g id="DATE">%s</xliff:g>తో ముగుస్తుంది"</string> + <string name="delete_blob_text" msgid="2819192607255625697">"షేర్ చేసిన డేటాను తొలగించు"</string> + <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"మీరు ఖచ్చితంగా ఈ షేర్ చేసిన డేటాను తొలగించాలనుకుంటున్నారా?"</string> <string name="user_add_user_item_summary" msgid="5748424612724703400">"వినియోగదారులు వారి స్వంత అనువర్తనాలను మరియు కంటెంట్ను కలిగి ఉన్నారు"</string> <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి అనువర్తనాలకు మరియు కంటెంట్కు ప్రాప్యతను పరిమితం చేయవచ్చు"</string> <string name="user_add_user_item_title" msgid="2394272381086965029">"వినియోగదారు"</string> @@ -556,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ప్రొఫైల్ సమాచారం"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"మీరు పరిమితం చేయబడిన ప్రొఫైల్ను సృష్టించడానికి ముందు, మీ అనువర్తనాలు మరియు వ్యక్తిగత డేటాను రక్షించడానికి స్క్రీన్ లాక్ను సెటప్ చేయాల్సి ఉంటుంది."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"లాక్ను సెట్ చేయి"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>కు మార్చు"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"అతిథిని జోడించండి"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"అతిథిని తీసివేయండి"</string> + <string name="guest_nickname" msgid="6332276931583337261">"అతిథి"</string> </resources> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 765c5dda24f6..b24f006ddbe6 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -513,16 +513,12 @@ <string name="storage_category" msgid="2287342585424631813">"พื้นที่เก็บข้อมูล"</string> <string name="shared_data_title" msgid="1017034836800864953">"ข้อมูลที่แชร์"</string> <string name="shared_data_summary" msgid="5516326713822885652">"ดูและแก้ไขข้อมูลที่แชร์"</string> - <!-- no translation found for shared_data_no_blobs_text (3108114670341737434) --> - <skip /> - <!-- no translation found for shared_data_query_failure_text (3489828881998773687) --> - <skip /> + <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ไม่มีข้อมูลที่แชร์สำหรับผู้ใช้รายนี้"</string> + <string name="shared_data_query_failure_text" msgid="3489828881998773687">"เกิดข้อผิดพลาดขณะดึงข้อมูลที่แชร์ ลองใหม่"</string> <string name="blob_id_text" msgid="8680078988996308061">"รหัสข้อมูลที่แชร์: <xliff:g id="BLOB_ID">%d</xliff:g>"</string> <string name="blob_expires_text" msgid="7882727111491739331">"จะหมดอายุในวันที่ <xliff:g id="DATE">%s</xliff:g>"</string> - <!-- no translation found for shared_data_delete_failure_text (3842701391009628947) --> - <skip /> - <!-- no translation found for shared_data_no_accessors_dialog_text (8903738462570715315) --> - <skip /> + <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"เกิดข้อผิดพลาดขณะลบข้อมูลที่แชร์"</string> + <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"ไม่มีสัญญาเช่าที่ได้มาสำหรับข้อมูลที่แชร์นี้ คุณต้องการลบข้อมูลนี้ไหม"</string> <string name="accessor_info_title" msgid="8289823651512477787">"แอปที่แชร์ข้อมูล"</string> <string name="accessor_no_description_text" msgid="7510967452505591456">"แอปไม่ได้ให้คำอธิบายไว้"</string> <string name="accessor_expires_text" msgid="4625619273236786252">"เวลาได้รับสิทธิ์จะสิ้นสุดในวันที่ <xliff:g id="DATE">%s</xliff:g>"</string> @@ -547,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"ข้อมูลโปรไฟล์"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ก่อนที่คุณจะสามารถสร้างโปรไฟล์ที่ถูกจำกัดได้ คุณจะต้องตั้งค่าล็อกหน้าจอเพื่อปกป้องแอปและข้อมูลส่วนตัวของคุณ"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"ตั้งค่าล็อก"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"เปลี่ยนเป็น <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้เข้าร่วม"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้เข้าร่วมออก"</string> + <string name="guest_nickname" msgid="6332276931583337261">"ผู้เข้าร่วม"</string> </resources> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 11466198bb74..8d70718c98c3 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Info sa profile"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Bago ka makakalikha ng pinaghihigpitang profile, kakailanganin mong mag-set up ng screen lock upang protektahan ang iyong apps at personal na data."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Itakda ang lock"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Lumipat sa <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string> </resources> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 3853331c3c18..3579957fc00c 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profil bilgisi"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Kısıtlanmış bir profil oluşturabilmeniz için uygulamalarınızı ve kişisel verilerinizi korumak üzere bir ekran kilidi oluşturmanız gerekir."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Kilidi ayarla"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> hesabına geç"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Misafir"</string> </resources> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 2eeda185f4a4..5dae4f0a63c6 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -545,12 +545,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Інформація профілю"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Перш ніж створювати обмежений профіль, потрібно налаштувати блокування екрана, щоб захистити свої програми та особисті дані."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Налаштувати блокування"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Перейти до користувача <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Гість"</string> </resources> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index f802ebc93be3..ce25f2f83af4 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -300,8 +300,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"اگر دستیاب ہو تو ٹیدرنگ ہارڈویئر سرعت کاری کا استعمال کریں"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB ڈیبگ کرنے کی اجازت دیں؟"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB ڈیبگ کرنا صرف ڈیولپمنٹ کے مقاصد کیلئے ہے۔ اپنے کمپیوٹر اور اپنے آلہ کے درمیان ڈیٹا کاپی کرنے کیلئے اسے استعمال کریں، بغیر اطلاع کے اپنے آلہ پر ایپس انسٹال کریں اور لاگ ڈیٹا پڑھیں۔"</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"وائرلیس ڈیبگ کرنے کی اجازت دیں؟"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"وائرلیس ڈیبگ کرنا صرف ڈیولپمنٹ کے مقاصد کے لیے ہے۔ اپنے کمپیوٹر اور اپنے آلہ کے درمیان ڈیٹا کاپی کرنے کے لیے اسے استعمال کریں، بغیر اطلاع کے اپنے آلہ پر ایپس انسٹال کریں اور لاگ ڈیٹا پڑھیں۔"</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"وائرلیس ڈیبگنگ کی اجازت دیں؟"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"وائرلیس ڈیبگنگ صرف ڈیولپمنٹ کے مقاصد کے لیے ہے۔ اپنے کمپیوٹر اور اپنے آلہ کے درمیان ڈیٹا کاپی کرنے کے لیے اسے استعمال کریں، بغیر اطلاع کے اپنے آلہ پر ایپس انسٹال کریں اور لاگ ڈیٹا پڑھیں۔"</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"اپنے ذریعہ پہلے سے اجازت یافتہ سبھی کمپیوٹرز سے USB ڈیبگ کرنے کی رسائی کو کالعدم کریں؟"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"ڈویلپمنٹ ترتیبات کی اجازت دیں؟"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"یہ ترتیبات صرف ڈویلپمنٹ استعمال کے ارادے سے ہیں۔ ان سے آپ کا آلہ اور اس پر موجود ایپلیکیشنز بریک ہو سکتی یا غلط برتاؤ کر سکتی ہیں۔"</string> @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"پروفائل کی معلومات"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ایک محدود پروفائل بنانے سے پہلے، آپ کو اپنی ایپس اور ذاتی ڈیٹا کو محفوظ کرنے کیلئے ایک اسکرین لاک سیٹ اپ کرنا ہوگا۔"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"لاک سیٹ کریں"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> پر سوئچ کریں"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"مہمان کو شامل کریں"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"مہمان کو ہٹائیں"</string> + <string name="guest_nickname" msgid="6332276931583337261">"مہمان"</string> </resources> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 52fe39579a9d..07f3a6e9c5ba 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -520,8 +520,8 @@ <string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Umumiy maʼlumotlarni oʻchirishda xatolik yuz berdi."</string> <string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Bu umumiy maʼlumotlar yuzasidan kelgan soʻrov topilmadi. Oʻchirib tashlansinmi?"</string> <string name="accessor_info_title" msgid="8289823651512477787">"Umumiy maʼlumotlar bor ilovalar"</string> - <string name="accessor_no_description_text" msgid="7510967452505591456">"Ilova hech qanday tavsif bermagan."</string> - <string name="accessor_expires_text" msgid="4625619273236786252">"Ruxsat eskirish sanasi: <xliff:g id="DATE">%s</xliff:g>"</string> + <string name="accessor_no_description_text" msgid="7510967452505591456">"Ilovaga hech qanday tavsif bermagan."</string> + <string name="accessor_expires_text" msgid="4625619273236786252">"Ruxsat tugash sanasi: <xliff:g id="DATE">%s</xliff:g>"</string> <string name="delete_blob_text" msgid="2819192607255625697">"Umumiy maʼlumotlarni oʻchirish"</string> <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Umumiy maʼlumotlarni oʻchirishni xohlaysizmi?"</string> <string name="user_add_user_item_summary" msgid="5748424612724703400">"Foydalanuvchilar o‘zlarining ilovalari va kontenlariga egalar"</string> @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Profil haqida axborot"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Cheklangan profil yaratish uchun, shaxsiy ilovlar va ma‘lumotlarni himoyalash maqsadida avval ekran qulfini yaratish lozim."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Qulf o‘rnatish"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Bunga almashish: <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Mehmon rejimini olib tashlash"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string> </resources> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index eb22f7d726e0..10ac60df77c0 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -206,11 +206,11 @@ <string name="enable_adb" msgid="8072776357237289039">"Gỡ lỗi qua USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Bật chế độ gỡ lỗi khi kết nối USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Thu hồi ủy quyền gỡ lỗi USB"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Gỡ lỗi không dây"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Gỡ lỗi qua Wi-Fi"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Chế độ gỡ lỗi khi có kết nối Wi-Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Lỗi"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Gỡ lỗi không dây"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Để xem và sử dụng các thiết bị có sẵn, hãy bật tính năng gỡ lỗi không dây"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Gỡ lỗi qua Wi-Fi"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Để xem và sử dụng các thiết bị có sẵn, hãy bật tính năng gỡ lỗi qua Wi-Fi"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Ghép nối thiết bị bằng mã QR"</string> <string name="adb_pair_method_qrcode_summary" msgid="3729901496856458634">"Ghép nối các thiết bị mới bằng Trình quét mã QR"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Ghép nối thiết bị bằng mã ghép nối"</string> @@ -300,8 +300,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Sử dụng tính năng tăng tốc phần cứng khi chia sẻ kết nối nếu có"</string> <string name="adb_warning_title" msgid="7708653449506485728">"Cho phép gỡ lỗi qua USB?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"Gỡ lỗi USB chỉ dành cho mục đích phát triển. Hãy sử dụng tính năng này để sao chép dữ liệu giữa máy tính và thiết bị của bạn, cài đặt ứng dụng trên thiết bị của bạn mà không thông báo và đọc dữ liệu nhật ký."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Bật tính năng gỡ lỗi không dây?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Tính năng gỡ lỗi không dây chỉ dành cho mục đích phát triển. Hãy sử dụng tính năng này để sao chép dữ liệu giữa máy tính và thiết bị của bạn, cài đặt ứng dụng trên thiết bị mà không thông báo và đọc dữ liệu nhật ký."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Bật tính năng gỡ lỗi qua Wi-Fi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Tính năng gỡ lỗi qua Wi-Fi chỉ dành cho mục đích phát triển. Hãy sử dụng tính năng này để sao chép dữ liệu giữa máy tính và thiết bị của bạn, cài đặt ứng dụng trên thiết bị mà không thông báo và đọc dữ liệu nhật ký."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"Thu hồi quyền truy cập gỡ lỗi USB từ tất cả máy tính mà bạn đã ủy quyền trước đó?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Cho phép cài đặt phát triển?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Những cài đặt này chỉ dành cho mục đích phát triển. Chúng có thể làm cho thiết bị và ứng dụng trên thiết bị của bạn bị lỗi và hoạt động sai."</string> @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"Thông tin hồ sơ"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"Trước khi bạn có thể tạo tiểu sử bị hạn chế, bạn sẽ cần thiết lập một màn hình khóa để bảo vệ các ứng dụng và dữ liệu cá nhân của bạn."</string> <string name="user_set_lock_button" msgid="1427128184982594856">"Thiết lập khóa"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"Chuyển sang <xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string> + <string name="guest_nickname" msgid="6332276931583337261">"Khách"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index a4727cab98a0..c24f72dbc072 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"个人资料信息"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"您需要先设置锁定屏幕来保护您的应用和个人数据,然后才可以创建受限个人资料。"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"设置屏幕锁定方式"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"切换到<xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"添加访客"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"移除访客"</string> + <string name="guest_nickname" msgid="6332276931583337261">"访客"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index b3f28fac551e..a4c2336d6a02 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"個人檔案資料"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"建立限制存取的個人檔案前,您必須先設定上鎖畫面來保護您的應用程式和個人資料。"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"設定上鎖畫面"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string> + <string name="guest_nickname" msgid="6332276931583337261">"訪客"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 05d4d46a6dc8..5183df3011e5 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -543,12 +543,8 @@ <string name="profile_info_settings_title" msgid="105699672534365099">"設定檔資訊"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"如要建立設有限制的個人資料,你必須先設定螢幕鎖定來保護你的應用程式和個人資料。"</string> <string name="user_set_lock_button" msgid="1427128184982594856">"設定鎖定"</string> - <!-- no translation found for user_switch_to_user (6975428297154968543) --> - <skip /> - <!-- no translation found for guest_new_guest (3482026122932643557) --> - <skip /> - <!-- no translation found for guest_exit_guest (5908239569510734136) --> - <skip /> - <!-- no translation found for guest_nickname (6332276931583337261) --> - <skip /> + <string name="user_switch_to_user" msgid="6975428297154968543">"切換至<xliff:g id="USER_NAME">%s</xliff:g>"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string> + <string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string> + <string name="guest_nickname" msgid="6332276931583337261">"訪客"</string> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index fb8a0b7f63ca..3024b842c2be 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -146,6 +146,7 @@ public class LocalMediaManager implements BluetoothCallback { ((BluetoothMediaDevice) device).getCachedDevice(); if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) { mOnTransferBluetoothDevice = connectDevice; + device.setState(MediaDeviceState.STATE_CONNECTING); cachedDevice.connect(); return; } @@ -220,7 +221,7 @@ public class LocalMediaManager implements BluetoothCallback { */ public MediaDevice getMediaDeviceById(List<MediaDevice> devices, String id) { for (MediaDevice mediaDevice : devices) { - if (mediaDevice.getId().equals(id)) { + if (TextUtils.equals(mediaDevice.getId(), id)) { return mediaDevice; } } @@ -236,7 +237,7 @@ public class LocalMediaManager implements BluetoothCallback { */ public MediaDevice getMediaDeviceById(String id) { for (MediaDevice mediaDevice : mMediaDevices) { - if (mediaDevice.getId().equals(id)) { + if (TextUtils.equals(mediaDevice.getId(), id)) { return mediaDevice; } } @@ -394,6 +395,7 @@ public class LocalMediaManager implements BluetoothCallback { dispatchDeviceListUpdate(); if (mOnTransferBluetoothDevice != null && mOnTransferBluetoothDevice.isConnected()) { connectDevice(mOnTransferBluetoothDevice); + mOnTransferBluetoothDevice.setState(MediaDeviceState.STATE_CONNECTED); mOnTransferBluetoothDevice = null; } } @@ -539,6 +541,14 @@ public class LocalMediaManager implements BluetoothCallback { @Override public void onDeviceAttributesChanged() { + if (mOnTransferBluetoothDevice != null + && !((BluetoothMediaDevice) mOnTransferBluetoothDevice).getCachedDevice() + .isBusy() + && !mOnTransferBluetoothDevice.isConnected()) { + // Failed to connect + mOnTransferBluetoothDevice.setState(MediaDeviceState.STATE_DISCONNECTED); + mOnTransferBluetoothDevice = null; + } dispatchDeviceAttributesChanged(); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 1c690724b1c1..7ddd64c15876 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -218,6 +218,26 @@ public class LocalMediaManagerTest { } @Test + public void getMediaDeviceById_idIsNull_shouldReturnNull() { + final MediaDevice device1 = mock(MediaDevice.class); + final MediaDevice device2 = mock(MediaDevice.class); + mLocalMediaManager.mMediaDevices.add(device1); + mLocalMediaManager.mMediaDevices.add(device2); + + when(device1.getId()).thenReturn(null); + when(device2.getId()).thenReturn(null); + + MediaDevice device = mLocalMediaManager + .getMediaDeviceById(mLocalMediaManager.mMediaDevices, TEST_CURRENT_DEVICE_ID); + + assertThat(device).isNull(); + + device = mLocalMediaManager.getMediaDeviceById(TEST_CURRENT_DEVICE_ID); + + assertThat(device).isNull(); + } + + @Test public void onDeviceAdded_addDevice() { final MediaDevice device = mock(MediaDevice.class); @@ -464,6 +484,26 @@ public class LocalMediaManagerTest { } @Test + public void onDeviceAttributesChanged_failingTransferring_shouldResetState() { + final MediaDevice currentDevice = mock(MediaDevice.class); + final MediaDevice device = mock(BluetoothMediaDevice.class); + final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); + mLocalMediaManager.mMediaDevices.add(device); + mLocalMediaManager.mMediaDevices.add(currentDevice); + when(device.getId()).thenReturn(TEST_DEVICE_ID_1); + when(currentDevice.getId()).thenReturn(TEST_CURRENT_DEVICE_ID); + when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice); + when(cachedDevice.isConnected()).thenReturn(false); + when(cachedDevice.isBusy()).thenReturn(false); + + mLocalMediaManager.registerCallback(mCallback); + mLocalMediaManager.connectDevice(device); + + mLocalMediaManager.mDeviceAttributeChangeCallback.onDeviceAttributesChanged(); + verify(device).setState(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED); + } + + @Test public void onRequestFailed_checkDevicesState() { mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice1); mLocalMediaManager.mMediaDevices.add(mInfoMediaDevice2); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 791b83277571..c6f03271f931 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -255,6 +255,9 @@ <!-- Query all packages on device on R+ --> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> + <!-- Permission to register process observer --> + <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER"/> + <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index 022726e43e98..d956a79cb496 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -98,7 +98,7 @@ <string name="kg_password_pin_failed" msgid="5136259126330604009">"SIM-картанын PIN-кодун ачуу кыйрады!"</string> <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM-картанын PUK-кодун ачуу кыйрады!"</string> <string name="kg_pin_accepted" msgid="1625501841604389716">"Код кабыл алынды!"</string> - <string name="keyguard_carrier_default" msgid="6359808469637388586">"Байланыш жок."</string> + <string name="keyguard_carrier_default" msgid="6359808469637388586">"Интернет жок."</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Киргизүү ыкмасын өзгөртүү"</string> <string name="airplane_mode" msgid="2528005343938497866">"Учак режими"</string> <string name="kg_prompt_reason_prepare_for_update_pin" msgid="8878724145347297575">"Жаңыртууга даярдоо үчүн PIN код талап кылынат"</string> diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index 34633d30086d..5f1df3e109b1 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -54,7 +54,7 @@ <string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"Miejsce na kod PIN karty SIM"</string> <string name="keyguard_accessibility_sim_puk_area" msgid="5537294043180237374">"Miejsce na kod PUK karty SIM"</string> <string name="keyguard_accessibility_next_alarm" msgid="4492876946798984630">"Następny alarm ustawiony na: <xliff:g id="ALARM">%1$s</xliff:g>"</string> - <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Usuwanie"</string> + <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"Usuń"</string> <string name="disable_carrier_button_text" msgid="7153361131709275746">"Wyłącz eSIM"</string> <string name="error_disable_esim_title" msgid="3802652622784813119">"Nie można wyłączyć karty eSIM"</string> <string name="error_disable_esim_msg" msgid="2441188596467999327">"Nie można wyłączyć karty eSIM z powodu błędu."</string> diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index 5119b59424d4..db81e2348cd8 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -40,29 +40,20 @@ <TextView android:id="@+id/status" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" android:textAppearance="@style/TextAppearance.Control.Status" android:paddingTop="@dimen/control_padding_adjustment" android:paddingStart="@dimen/control_status_padding" - android:clickable="false" + android:clickable="true" android:focusable="false" + android:singleLine="true" + android:ellipsize="marquee" + android:marqueeRepeatLimit = "marquee_forever" + app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="@+id/icon" app:layout_constraintStart_toEndOf="@+id/icon" /> - - <TextView - android:id="@+id/status_extra" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.Control.Status" - android:paddingTop="@dimen/control_padding_adjustment" - android:paddingStart="@dimen/control_status_padding" - android:clickable="false" - android:focusable="false" - app:layout_constraintBottom_toBottomOf="@+id/icon" - app:layout_constraintStart_toEndOf="@+id/status" /> - <TextView android:id="@+id/title" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml index 92ae1b95264f..620e2e6b509c 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml @@ -67,9 +67,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:layout_marginRight="@dimen/global_actions_grid_horizontal_padding" - android:layout_marginLeft="@dimen/global_actions_grid_horizontal_padding" /> </LinearLayout> </com.android.systemui.globalactions.MinHeightScrollView> -</LinearLayout>
\ No newline at end of file +</LinearLayout> diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index 63bbe62a6520..da5819c50a7e 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -31,4 +31,7 @@ <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen --> <integer name="navigation_bar_deadzone_orientation">1</integer> + + <!-- Max number of columns for quick controls area --> + <integer name="controls_max_columns">4</integer> </resources> diff --git a/packages/SystemUI/res/values-sw320dp/dimens.xml b/packages/SystemUI/res/values-sw320dp/dimens.xml index 2774554ec642..47a2a093302f 100644 --- a/packages/SystemUI/res/values-sw320dp/dimens.xml +++ b/packages/SystemUI/res/values-sw320dp/dimens.xml @@ -30,5 +30,7 @@ <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen> <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen> + <!-- Home Controls --> + <dimen name="controls_list_side_margin">10dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw360dp/dimens.xml b/packages/SystemUI/res/values-sw360dp/dimens.xml index dfd97435a288..35a653608a90 100644 --- a/packages/SystemUI/res/values-sw360dp/dimens.xml +++ b/packages/SystemUI/res/values-sw360dp/dimens.xml @@ -26,5 +26,7 @@ navigation_extra_key_width --> <dimen name="navigation_side_padding">40dip</dimen> + <!-- Home Controls --> + <dimen name="controls_list_side_margin">12dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw392dp/dimens.xml b/packages/SystemUI/res/values-sw392dp/dimens.xml index be1d9528db1d..308bc69656da 100644 --- a/packages/SystemUI/res/values-sw392dp/dimens.xml +++ b/packages/SystemUI/res/values-sw392dp/dimens.xml @@ -30,5 +30,7 @@ <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen> <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen> + <!-- Home Controls --> + <dimen name="controls_list_side_margin">16dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml index 95716c834483..3343a84e7a9c 100644 --- a/packages/SystemUI/res/values/arrays_tv.xml +++ b/packages/SystemUI/res/values/arrays_tv.xml @@ -35,7 +35,5 @@ </string-array> <string-array name="audio_recording_disclosure_exempt_apps" translatable="false"> - <item>com.google.android.katniss</item> - <item>com.google.android.apps.mediashell</item> </string-array> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 922acff7f6f2..f549a3253319 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -533,4 +533,12 @@ This config value should contain the package name of that preferred application. --> <string translatable="false" name="config_controlsPreferredPackage"></string> + + <!-- Max number of columns for quick controls area --> + <integer name="controls_max_columns">2</integer> + <!-- If the dp width of the available space is <= this value, potentially adjust the number + of columns--> + <integer name="controls_max_columns_adjust_below_width_dp">320</integer> + <!-- If the config font scale is >= this value, potentially adjust the number of columns--> + <item name="controls_max_columns_adjust_above_font_scale" translatable="false" format="float" type="dimen">1.25</item> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d17b81d46090..566d143208fc 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2647,15 +2647,15 @@ <!-- Title for Magnification Controls Window [CHAR LIMIT=NONE] --> <string name="magnification_controls_title">Magnification Window Controls</string> - <!-- Quick Controls strings --> - <!-- Quick Controls empty state, title [CHAR LIMIT=30] --> - <string name="quick_controls_title">Quick controls</string> - <!-- Quick Controls empty state, subtitle [CHAR LIMIT=100] --> + <!-- Device Controls strings --> + <!-- Device Controls empty state, title [CHAR LIMIT=30] --> + <string name="quick_controls_title">Device controls</string> + <!-- Device Controls empty state, subtitle [CHAR LIMIT=100] --> <string name="quick_controls_subtitle">Add controls for your connected devices</string> - <!-- Quick Controls setup, title [CHAR LIMIT=50] --> - <string name="quick_controls_setup_title">Set up quick controls</string> - <!-- Quick Controls setup, subtitle [CHAR LIMIT=100] --> + <!-- Device Controls setup, title [CHAR LIMIT=50] --> + <string name="quick_controls_setup_title">Set up device controls</string> + <!-- Device Controls setup, subtitle [CHAR LIMIT=100] --> <string name="quick_controls_setup_subtitle">Hold the Power button to access your controls</string> <!-- Controls management providers screen title [CHAR LIMIT=60]--> @@ -2679,7 +2679,7 @@ <string name="controls_favorite_other_zone_header">Other</string> <!-- Controls dialog title [CHAR LIMIT=40] --> - <string name="controls_dialog_title">Add to quick controls</string> + <string name="controls_dialog_title">Add to device controls</string> <!-- Controls dialog add to favorites [CHAR LIMIT=40] --> <string name="controls_dialog_ok">Add to favorites</string> <!-- Controls dialog message [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 1598465d6df0..aabee1c952e8 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -249,6 +249,7 @@ <style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/> <style name="TextAppearance.AuthCredential"> + <item name="android:accessibilityLiveRegion">polite</item> <item name="android:gravity">center_horizontal</item> <item name="android:textAlignment">gravity</item> <item name="android:layout_gravity">top</item> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java index b006bc1351a3..8bf259182544 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java @@ -214,9 +214,11 @@ public abstract class AuthCredentialView extends LinearLayout { protected void onAttachedToWindow() { super.onAttachedToWindow(); - setText(mTitleView, getTitle(mBiometricPromptBundle)); + final CharSequence title = getTitle(mBiometricPromptBundle); + setText(mTitleView, title); setTextOrHide(mSubtitleView, getSubtitle(mBiometricPromptBundle)); setTextOrHide(mDescriptionView, getDescription(mBiometricPromptBundle)); + announceForAccessibility(title); final boolean isManagedProfile = Utils.isManagedProfile(mContext, mEffectiveUserId); final Drawable image; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java index ea1abf99a0f3..a0b49384d49f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java @@ -323,6 +323,9 @@ public class ExpandedAnimationController /** Plays a dismiss animation on the dragged out bubble. */ public void dismissDraggedOutBubble(View bubble, Runnable after) { + if (bubble == null) { + return; + } animationForChild(bubble) .withStiffness(SpringForce.STIFFNESS_HIGH) .scaleX(1.1f) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index 7d3a86091869..b1cb04e10eef 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -51,7 +51,6 @@ class ControlViewHolder( ) { val icon: ImageView = layout.requireViewById(R.id.icon) val status: TextView = layout.requireViewById(R.id.status) - val statusExtra: TextView = layout.requireViewById(R.id.status_extra) val title: TextView = layout.requireViewById(R.id.title) val subtitle: TextView = layout.requireViewById(R.id.subtitle) val context: Context = layout.getContext() @@ -65,6 +64,8 @@ class ControlViewHolder( val ld = layout.getBackground() as LayerDrawable ld.mutate() clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable + // needed for marquee to start + status.setSelected(true) } fun bindData(cws: ControlWithState) { @@ -103,8 +104,7 @@ class ControlViewHolder( behavior?.bind(cws) - layout.setContentDescription( - "${title.text} ${subtitle.text} ${status.text} ${statusExtra.text}") + layout.setContentDescription("${title.text} ${subtitle.text} ${status.text}") } fun actionResponse(@ControlAction.ResponseResult response: Int) { @@ -113,15 +113,12 @@ class ControlViewHolder( fun setTransientStatus(tempStatus: String) { val previousText = status.getText() - val previousTextExtra = statusExtra.getText() cancelUpdate = uiExecutor.executeDelayed({ status.setText(previousText) - statusExtra.setText(previousTextExtra) }, UPDATE_DELAY_IN_MILLIS) status.setText(tempStatus) - statusExtra.setText("") } fun action(action: ControlAction) { @@ -154,7 +151,6 @@ class ControlViewHolder( } status.setTextColor(fg) - statusExtra.setTextColor(fg) icon.setImageDrawable(ri.icon) 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 05a0c45c2e15..6e527e29a848 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -21,10 +21,12 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.SharedPreferences +import android.content.res.Configuration import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.service.controls.Control import android.service.controls.actions.ControlAction +import android.util.TypedValue import android.util.Log import android.view.ContextThemeWrapper import android.view.LayoutInflater @@ -345,10 +347,12 @@ class ControlsUiControllerImpl @Inject constructor ( val inflater = LayoutInflater.from(context) inflater.inflate(R.layout.controls_with_favorites, parent, true) + val maxColumns = findMaxColumns() + val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup var lastRow: ViewGroup = createRow(inflater, listView) selectedStructure.controls.forEach { - if (lastRow.getChildCount() == 2) { + if (lastRow.getChildCount() == maxColumns) { lastRow = createRow(inflater, listView) } val baseLayout = inflater.inflate( @@ -365,12 +369,40 @@ class ControlsUiControllerImpl @Inject constructor ( controlViewsById.put(key, cvh) } - // add spacer if necessary to keep control size consistent - if ((selectedStructure.controls.size % 2) == 1) { + // add spacers if necessary to keep control size consistent + var spacersToAdd = selectedStructure.controls.size % maxColumns + while (spacersToAdd > 0) { lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f)) + spacersToAdd-- } } + /** + * For low-dp width screens that also employ an increased font scale, adjust the + * number of columns. This helps prevent text truncation on these devices. + */ + private fun findMaxColumns(): Int { + val res = context.resources + var maxColumns = res.getInteger(R.integer.controls_max_columns) + val maxColumnsAdjustWidth = + res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp) + + val outValue = TypedValue() + res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true) + val maxColumnsAdjustFontScale = outValue.getFloat() + + val config = res.configuration + val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT + if (isPortrait && + config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED && + config.screenWidthDp <= maxColumnsAdjustWidth && + config.fontScale >= maxColumnsAdjustFontScale) { + maxColumns-- + } + + return maxColumns + } + private fun loadPreference(structures: List<StructureInfo>): StructureInfo { if (structures.isEmpty()) return EMPTY_STRUCTURE diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt index f79c8b2393d0..5a956653285c 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt @@ -47,9 +47,10 @@ class ToggleRangeBehavior : Behavior { lateinit var control: Control lateinit var cvh: ControlViewHolder lateinit var rangeTemplate: RangeTemplate - lateinit var statusExtra: TextView lateinit var status: TextView lateinit var context: Context + var currentStatusText: CharSequence = "" + var currentRangeValue: String = "" companion object { private const val DEFAULT_FORMAT = "%.1f" @@ -83,8 +84,8 @@ class ToggleRangeBehavior : Behavior { override fun bind(cws: ControlWithState) { this.control = cws.control!! - statusExtra = cvh.statusExtra - status.setText(control.getStatusText()) + currentStatusText = control.getStatusText() + status.setText(currentStatusText) val ld = cvh.layout.getBackground() as LayerDrawable clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) @@ -96,7 +97,7 @@ class ToggleRangeBehavior : Behavior { val checked = template.isChecked() val currentRatio = rangeTemplate.getCurrentValue() / (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()) - updateRange(currentRatio, checked) + updateRange(currentRatio, checked, /* isDragging */ false) cvh.applyRenderInfo(checked) @@ -147,7 +148,7 @@ class ToggleRangeBehavior : Behavior { AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE) val ratioDiff = (value - rangeTemplate.getCurrentValue()) / (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()) - updateRange(ratioDiff, template.isChecked()) + updateRange(ratioDiff, template.isChecked(), /* isDragging */ false) endUpdateRange() true } @@ -167,26 +168,27 @@ class ToggleRangeBehavior : Behavior { } fun beginUpdateRange() { - status.setVisibility(View.GONE) - statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat()) } - fun updateRange(ratioDiff: Float, checked: Boolean) { + fun updateRange(ratioDiff: Float, checked: Boolean, isDragging: Boolean) { val changeAmount = if (checked) (MAX_LEVEL * ratioDiff).toInt() else MIN_LEVEL val newLevel = Math.max(MIN_LEVEL, Math.min(MAX_LEVEL, clipLayer.getLevel() + changeAmount)) clipLayer.setLevel(newLevel) if (checked) { val newValue = levelToRangeValue(clipLayer.getLevel()) - val formattedNewValue = format(rangeTemplate.getFormatString().toString(), + currentRangeValue = format(rangeTemplate.getFormatString().toString(), DEFAULT_FORMAT, newValue) - - statusExtra.setText(formattedNewValue) - statusExtra.setVisibility(View.VISIBLE) + val text = if (isDragging) { + currentRangeValue + } else { + "$currentStatusText $currentRangeValue" + } + status.setText(text) } else { - statusExtra.setText("") - statusExtra.setVisibility(View.GONE) + status.setText(currentStatusText) } } @@ -210,9 +212,9 @@ class ToggleRangeBehavior : Behavior { } fun endUpdateRange() { - statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + status.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() .getDimensionPixelSize(R.dimen.control_status_normal).toFloat()) - status.setVisibility(View.VISIBLE) + status.setText("$currentStatusText $currentRangeValue") cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(levelToRangeValue(clipLayer.getLevel())))) } @@ -260,7 +262,8 @@ class ToggleRangeBehavior : Behavior { isDragging = true } - this@ToggleRangeBehavior.updateRange(-xDiff / v.getWidth(), true) + this@ToggleRangeBehavior.updateRange(-xDiff / v.getWidth(), + /* checked */ true, /* isDragging */ true) return true } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index dba43430b490..d219a9e65a3c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -319,7 +319,6 @@ public class PipAnimationController { getSurfaceTransactionHelper() .crop(tx, leash, getDestinationBounds()) .round(tx, leash, shouldApplyCornerRadius()); - tx.show(leash); tx.apply(); } }; @@ -360,7 +359,6 @@ public class PipAnimationController { getSurfaceTransactionHelper() .alpha(tx, leash, 1f) .round(tx, leash, shouldApplyCornerRadius()); - tx.show(leash); tx.apply(); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 3879c164a84c..366ef931e1f5 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -21,6 +21,7 @@ import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; +import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -32,10 +33,8 @@ import android.graphics.Region.Op; import android.hardware.display.DisplayManager; import android.os.Bundle; import android.os.Handler; -import android.os.Message; import android.util.AttributeSet; import android.util.Slog; -import android.view.Choreographer; import android.view.Display; import android.view.InsetsState; import android.view.MotionEvent; @@ -57,12 +56,12 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import android.widget.FrameLayout; +import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.internal.policy.DockedDividerUtils; -import com.android.internal.view.SurfaceFlingerVsyncChoreographer; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -111,8 +110,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, private static final Interpolator IME_ADJUST_INTERPOLATOR = new PathInterpolator(0.2f, 0f, 0.1f, 1f); - private static final int MSG_RESIZE_STACK = 0; - private DividerHandleView mHandle; private View mBackground; private MinimizedDockShadow mMinimizedShadow; @@ -149,6 +146,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private SplitDisplayLayout mSplitLayout; private DividerCallbacks mCallback; private final Rect mStableInsets = new Rect(); + private final AnimationHandler mAnimationHandler = new AnimationHandler(); private boolean mGrowRecents; private ValueAnimator mCurrentAnimator; @@ -159,7 +157,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, private boolean mHomeStackResizable; private boolean mAdjustedForIme; private DividerState mState; - private final SurfaceFlingerVsyncChoreographer mSfChoreographer; private SplitScreenTaskOrganizer mTiles; boolean mFirstLayout = true; @@ -173,18 +170,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, // used interact with keyguard. private boolean mSurfaceHidden = false; - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_RESIZE_STACK: - resizeStackSurfaces(msg.arg1, msg.arg2, (SnapTarget) msg.obj); - break; - default: - super.handleMessage(msg); - } - } - }; + private final Handler mHandler = new Handler(); private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() { @Override @@ -277,11 +263,10 @@ public class DividerView extends FrameLayout implements OnTouchListener, public DividerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mSfChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, context.getDisplay(), - Choreographer.getInstance()); final DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); + mAnimationHandler.setProvider(new SfVsyncFrameCallbackProvider()); } @Override @@ -326,7 +311,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, void onDividerRemoved() { mRemoved = true; mCallback = null; - mHandler.removeMessages(MSG_RESIZE_STACK); } @Override @@ -548,7 +532,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) { SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget( mStartPosition, 0 /* velocity */, false /* hardDismiss */); - resizeStackDelayed(calculatePosition(x, y), mStartPosition, snapTarget); + resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget); } break; case MotionEvent.ACTION_UP: @@ -633,7 +617,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, if (DEBUG) Slog.d(TAG, "Getting fling " + position + "->" + snapTarget.position); final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE; ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position); - anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(), + anim.addUpdateListener(animation -> resizeStackSurfaces((int) animation.getAnimatedValue(), taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f ? TASK_POSITION_SAME : snapTarget.taskPosition, @@ -682,7 +666,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, @Override public void onAnimationCancel(Animator animation) { - mHandler.removeMessages(MSG_RESIZE_STACK); mCancelled = true; } @@ -693,8 +676,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, delay = endDelay; } else if (mCancelled) { delay = 0; - } else if (mSfChoreographer.getSurfaceFlingerOffsetMs() > 0) { - delay = mSfChoreographer.getSurfaceFlingerOffsetMs(); } if (delay == 0) { endAction.accept(mCancelled); @@ -705,6 +686,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, } } }); + anim.setAnimationHandler(mAnimationHandler); mCurrentAnimator = anim; return anim; } @@ -1047,13 +1029,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, mDividerSize); } - public void resizeStackDelayed(int position, int taskPosition, SnapTarget taskSnapTarget) { - Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition, - taskSnapTarget); - message.setAsynchronous(true); - mSfChoreographer.scheduleAtSfVsync(mHandler, message); - } - private void resizeStackSurfaces(SnapTarget taskSnapTarget) { resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 94afde786e78..24195156d8cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -322,10 +322,10 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< default void suppressAmbientDisplay(boolean suppress) { } /** - * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int, + * @see IStatusBar#showToast(int, String, IBinder, CharSequence, IBinder, int, * ITransientNotificationCallback) */ - default void showToast(String packageName, IBinder token, CharSequence text, + default void showToast(int uid, String packageName, IBinder token, CharSequence text, IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { } @@ -798,7 +798,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } @Override - public void showToast(String packageName, IBinder token, CharSequence text, + public void showToast(int uid, String packageName, IBinder token, CharSequence text, IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { synchronized (mLock) { SomeArgs args = SomeArgs.obtain(); @@ -807,7 +807,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< args.arg3 = text; args.arg4 = windowToken; args.arg5 = callback; - args.argi1 = duration; + args.argi1 = uid; + args.argi2 = duration; mHandler.obtainMessage(MSG_SHOW_TOAST, args).sendToTarget(); } } @@ -1276,9 +1277,10 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< IBinder windowToken = (IBinder) args.arg4; ITransientNotificationCallback callback = (ITransientNotificationCallback) args.arg5; - int duration = args.argi1; + int uid = args.argi1; + int duration = args.argi2; for (Callbacks callbacks : mCallbacks) { - callbacks.showToast(packageName, token, text, windowToken, duration, + callbacks.showToast(uid, packageName, token, text, windowToken, duration, callback); } break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 6fd3bb2c8222..dc1db50549a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -26,6 +26,7 @@ import static android.view.InsetsState.containsType; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE; import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; @@ -56,6 +57,8 @@ import android.content.IntentFilter; import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.hardware.display.DisplayManager; import android.inputmethodservice.InputMethodService; import android.net.Uri; import android.os.Binder; @@ -71,6 +74,7 @@ import android.telecom.TelecomManager; import android.text.TextUtils; import android.util.Log; import android.view.Display; +import android.view.Gravity; import android.view.InsetsState.InternalInsetsType; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -104,6 +108,7 @@ import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.CommandQueue; @@ -133,7 +138,7 @@ import dagger.Lazy; * on clicks and view states of the nav bar. */ public class NavigationBarFragment extends LifecycleFragment implements Callbacks, - NavigationModeController.ModeChangedListener { + NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener { public static final String TAG = "NavigationBar"; private static final boolean DEBUG = false; @@ -141,6 +146,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private static final String EXTRA_DISABLE2_STATE = "disabled2_state"; private static final String EXTRA_APPEARANCE = "appearance"; private static final String EXTRA_TRANSIENT_STATE = "transient_state"; + private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform"; + /** Allow some time inbetween the long press for back and recents. */ private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; @@ -199,6 +206,23 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private boolean mIsOnDefaultDisplay; public boolean mHomeBlockedThisTouch; + /** + * When user is QuickSwitching between apps of different orientations, we'll draw a fake + * home handle on the orientation they originally touched down to start their swipe + * gesture to indicate to them that they can continue in that orientation without having to + * rotate the phone + * The secondary handle will show when we get + * {@link OverviewProxyListener#onQuickSwitchToNewTask(int)} callback with the + * original handle hidden and we'll flip the visibilities once the + * {@link #mTasksFrozenListener} fires + */ + private NavigationHandle mOrientationHandle; + private WindowManager.LayoutParams mOrientationParams; + private boolean mFrozenTasks; + private int mStartingQuickSwitchRotation; + private int mCurrentRotation; + private boolean mFixedRotationEnabled; + /** Only for default display */ @Nullable private AssistHandleViewController mAssistHandlerViewController; @@ -249,6 +273,12 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } @Override + public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) { + mStartingQuickSwitchRotation = rotation; + orientSecondaryHomeHandle(); + } + + @Override public void startAssistant(Bundle bundle) { mAssistManager.startAssist(bundle); } @@ -271,6 +301,22 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; + private TaskStackChangeListener mTasksFrozenListener = new TaskStackChangeListener() { + @Override + public void onRecentTaskListFrozenChanged(boolean frozen) { + mFrozenTasks = frozen; + orientSecondaryHomeHandle(); + } + }; + + private NavigationBarTransitions.DarkIntensityListener mOrientationHandleIntensityListener = + new NavigationBarTransitions.DarkIntensityListener() { + @Override + public void onDarkIntensity(float darkIntensity) { + mOrientationHandle.setDarkIntensity(darkIntensity); + } + }; + private final ContextButtonListener mRotationButtonListener = (button, visible) -> { if (visible) { // If the button will actually become visible and the navbar is about to hide, @@ -294,6 +340,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; + private final ContentObserver mFixedRotationObserver = new ContentObserver( + new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange, Uri uri) { + updatedFixedRotation(); + } + }; + private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override @@ -351,6 +405,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback Settings.Secure.getUriFor(Settings.Secure.ASSISTANT), false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL); + mContentResolver.registerContentObserver( + Settings.Global.getUriFor(FIXED_ROTATION_TRANSFORM_SETTING_NAME), + false /* notifyForDescendants */, mFixedRotationObserver, UserHandle.USER_ALL); + if (savedInstanceState != null) { mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0); mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0); @@ -376,6 +434,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mNavigationModeController.removeListener(this); mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener); mContentResolver.unregisterContentObserver(mAssistContentObserver); + mContentResolver.unregisterContentObserver(mFixedRotationObserver); DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener); } @@ -406,6 +465,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } mNavigationBarView.setNavigationIconHints(mNavigationIconHints); mNavigationBarView.setWindowVisible(isNavBarWindowVisible()); + updatedFixedRotation(); prepareNavigationBarView(); checkNavBarModes(); @@ -442,6 +502,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback new AssistHandleViewController(mHandler, mNavigationBarView); getBarTransitions().addDarkIntensityListener(mAssistHandlerViewController); } + + initSecondaryHomeHandleForRotation(); + ActivityManagerWrapper.getInstance().registerTaskStackListener(mTasksFrozenListener); } @Override @@ -458,6 +521,13 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } mOverviewProxyService.removeCallback(mOverviewProxyListener); mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); + ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTasksFrozenListener); + if (mOrientationHandle != null) { + resetSecondaryHandle(); + getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this); + getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener); + mWindowManager.removeView(mOrientationHandle); + } } @Override @@ -490,6 +560,88 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback repositionNavigationBar(); } + private void initSecondaryHomeHandleForRotation() { + if (!canShowSecondaryHandle()) { + return; + } + + getContext().getSystemService(DisplayManager.class) + .registerDisplayListener(this, new Handler(Looper.getMainLooper())); + + mOrientationHandle = new VerticalNavigationHandle(getContext()); + + getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener); + mOrientationParams = new WindowManager.LayoutParams(0, 0, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_SLIPPERY, + PixelFormat.TRANSLUCENT); + mWindowManager.addView(mOrientationHandle, mOrientationParams); + mOrientationHandle.setVisibility(View.GONE); + } + + private void orientSecondaryHomeHandle() { + if (!canShowSecondaryHandle()) { + return; + } + + if (!mFrozenTasks) { + resetSecondaryHandle(); + } else { + int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation); + int height = 0; + int width = 0; + Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds(); + switch (deltaRotation) { + case Surface.ROTATION_90: + case Surface.ROTATION_270: + height = dispSize.height(); + width = getResources() + .getDimensionPixelSize(R.dimen.navigation_bar_height); + break; + case Surface.ROTATION_180: + case Surface.ROTATION_0: + // TODO(b/152683657): Need to determine best UX for this + resetSecondaryHandle(); + return; + } + + mOrientationParams.gravity = + deltaRotation == Surface.ROTATION_90 ? Gravity.LEFT : Gravity.RIGHT; + mOrientationParams.height = height; + mOrientationParams.width = width; + mWindowManager.updateViewLayout(mOrientationHandle, mOrientationParams); + mNavigationBarView.setVisibility(View.GONE); + mOrientationHandle.setVisibility(View.VISIBLE); + } + } + + private void resetSecondaryHandle() { + if (mOrientationHandle != null) { + // Case where nav mode is changed w/o ever invoking a quickstep + // mOrientedHandle is initialized lazily + mOrientationHandle.setVisibility(View.GONE); + } + mNavigationBarView.setVisibility(View.VISIBLE); + } + + private int deltaRotation(int oldRotation, int newRotation) { + int delta = newRotation - oldRotation; + if (delta < 0) delta += 4; + return delta; + } + + private void updatedFixedRotation() { + mFixedRotationEnabled = Settings.Global.getInt(mContentResolver, + FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0; + if (!canShowSecondaryHandle()) { + resetSecondaryHandle(); + } + } + @Override public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) { if (mNavigationBarView != null) { @@ -1112,6 +1264,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mNavBarMode = mode; updateScreenPinningGestures(); + if (!canShowSecondaryHandle()) { + resetSecondaryHandle(); + } + // Workaround for b/132825155, for secondary users, we currently don't receive configuration // changes on overlay package change since SystemUI runs for the system user. In this case, // trigger a new configuration change to ensure that the nav bar is updated in the same way. @@ -1156,6 +1312,34 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private final AccessibilityServicesStateChangeListener mAccessibilityListener = this::updateAccessibilityServicesState; + @Override + public void onDisplayAdded(int displayId) { + + } + + @Override + public void onDisplayRemoved(int displayId) { + + } + + @Override + public void onDisplayChanged(int displayId) { + if (!canShowSecondaryHandle()) { + return; + } + + int rotation = getContext().getResources().getConfiguration() + .windowConfiguration.getRotation(); + if (rotation != mCurrentRotation) { + mCurrentRotation = rotation; + orientSecondaryHomeHandle(); + } + } + + private boolean canShowSecondaryHandle() { + return mFixedRotationEnabled && mNavBarMode == NAV_BAR_MODE_GESTURAL; + } + private final Consumer<Integer> mRotationWatcher = rotation -> { if (mNavigationBarView != null && mNavigationBarView.needsReorient(rotation)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java index abceb11b36e9..b87479505d00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java @@ -32,11 +32,11 @@ import com.android.systemui.R; public class NavigationHandle extends View implements ButtonInterface { - private final Paint mPaint = new Paint(); + protected final Paint mPaint = new Paint(); private @ColorInt final int mLightColor; private @ColorInt final int mDarkColor; - private final int mRadius; - private final int mBottom; + protected final int mRadius; + protected final int mBottom; private boolean mRequiresInvalidate; public NavigationHandle(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java new file mode 100644 index 000000000000..a15ca9532a88 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.content.Context; +import android.graphics.Canvas; + +import com.android.systemui.R; + +/** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */ +public class VerticalNavigationHandle extends NavigationHandle { + private final int mWidth; + + public VerticalNavigationHandle(Context context) { + super(context); + mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width); + } + + @Override + protected void onDraw(Canvas canvas) { + int left; + int top; + int bottom; + int right; + + int radiusOffset = mRadius * 2; + right = getWidth() - mBottom; + top = getHeight() / 2 - (mWidth / 2); /* (height of screen / 2) - (height of bar / 2) */ + left = getWidth() - mBottom - radiusOffset; + bottom = getHeight() / 2 + (mWidth / 2); + canvas.drawRoundRect(left, top, right, bottom, mRadius, mRadius, mPaint); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 07985ab5a43c..02ae1f8afcdf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -27,6 +27,7 @@ import android.os.UserHandle; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.SystemUI; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar; import javax.inject.Inject; import javax.inject.Singleton; @@ -66,7 +67,8 @@ public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks { // If the system process isn't there we're doomed anyway. } - new AudioRecordingDisclosureBar(mContext).start(); + // Creating AudioRecordingDisclosureBar and just letting it run + new AudioRecordingDisclosureBar(mContext); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java new file mode 100644 index 000000000000..87b3956060f3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tv.micdisclosure; + +import android.content.Context; + +import java.util.Set; + +/** + * A base class for implementing observers for different kinds of activities related to audio + * recording. These observers are to be initialized by {@link AudioRecordingDisclosureBar} and to + * report back to it. + */ +abstract class AudioActivityObserver { + + interface OnAudioActivityStateChangeListener { + void onAudioActivityStateChange(boolean active, String packageName); + } + + final Context mContext; + + final OnAudioActivityStateChangeListener mListener; + + AudioActivityObserver(Context context, OnAudioActivityStateChangeListener listener) { + mContext = context; + mListener = listener; + } + + abstract Set<String> getActivePackages(); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java index e70e30a5ab57..914868301d72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.tv; +package com.android.systemui.statusbar.tv.micdisclosure; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -25,7 +25,6 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.annotation.IntDef; import android.annotation.UiThread; -import android.app.AppOpsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -40,6 +39,7 @@ import android.view.WindowManager; import android.widget.TextView; import com.android.systemui.R; +import com.android.systemui.statusbar.tv.TvStatusBar; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -54,9 +54,10 @@ import java.util.Set; * * @see TvStatusBar */ -class AudioRecordingDisclosureBar { - private static final String TAG = "AudioRecordingDisclosureBar"; - private static final boolean DEBUG = false; +public class AudioRecordingDisclosureBar implements + AudioActivityObserver.OnAudioActivityStateChangeListener { + private static final String TAG = "AudioRecordingDisclosure"; + static final boolean DEBUG = false; // This title is used to test the microphone disclosure indicator in // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest @@ -98,10 +99,12 @@ class AudioRecordingDisclosureBar { private TextView mTextView; @State private int mState = STATE_NOT_SHOWN; + /** - * Set of the applications that currently are conducting audio recording. + * Array of the observers that monitor different aspects of the system, such as AppOps and + * microphone foreground services */ - private final Set<String> mActiveAudioRecordingPackages = new ArraySet<>(); + private final AudioActivityObserver[] mAudioActivityObservers; /** * Set of applications that we've notified the user about since the indicator came up. Meaning * that if an application is in this list then at some point since the indicator came up, it @@ -119,29 +122,52 @@ class AudioRecordingDisclosureBar { * one of the two aforementioned states. */ private final Queue<String> mPendingNotificationPackages = new LinkedList<>(); + /** + * Set of applications for which we make an exception and do not show the indicator. This gets + * populated once - in {@link #AudioRecordingDisclosureBar(Context)}. + */ + private final Set<String> mExemptPackages; - AudioRecordingDisclosureBar(Context context) { + public AudioRecordingDisclosureBar(Context context) { mContext = context; - } - void start() { - // Register AppOpsManager callback - final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService( - Context.APP_OPS_SERVICE); - appOpsManager.startWatchingActive( - new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, - mContext.getMainExecutor(), - new OnActiveRecordingListener()); + mExemptPackages = new ArraySet<>( + Arrays.asList(mContext.getResources().getStringArray( + R.array.audio_recording_disclosure_exempt_apps))); + + mAudioActivityObservers = new AudioActivityObserver[]{ + new RecordAudioAppOpObserver(mContext, this), + new MicrophoneForegroundServicesObserver(mContext, this), + }; } @UiThread - private void onStartedRecording(String packageName) { - if (!mActiveAudioRecordingPackages.add(packageName)) { - // This app is already known to perform recording + @Override + public void onAudioActivityStateChange(boolean active, String packageName) { + if (DEBUG) { + Log.d(TAG, + "onAudioActivityStateChange, packageName=" + packageName + ", active=" + + active); + } + + if (mExemptPackages.contains(packageName)) { + if (DEBUG) Log.d(TAG, " - exempt package: ignoring"); return; } + + if (active) { + showIndicatorForPackageIfNeeded(packageName); + } else { + hideIndicatorIfNeeded(); + } + } + + @UiThread + private void showIndicatorForPackageIfNeeded(String packageName) { + if (DEBUG) Log.d(TAG, "showIndicatorForPackageIfNeeded, packageName=" + packageName); if (!mSessionNotifiedPackages.add(packageName)) { // We've already notified user about this app, no need to do it again. + if (DEBUG) Log.d(TAG, " - already notified"); return; } @@ -167,23 +193,33 @@ class AudioRecordingDisclosureBar { } @UiThread - private void onDoneRecording(String packageName) { - if (!mActiveAudioRecordingPackages.remove(packageName)) { - // Was not marked as an active recorder, do nothing - return; - } - + private void hideIndicatorIfNeeded() { + if (DEBUG) Log.d(TAG, "hideIndicatorIfNeeded"); // If not MINIMIZED, will check whether the indicator should be hidden when the indicator - // comes to the STATE_MINIMIZED eventually. If is in the STATE_MINIMIZED, but there are - // other active recorders - simply ignore. - if (mState == STATE_MINIMIZED && mActiveAudioRecordingPackages.isEmpty()) { - mSessionNotifiedPackages.clear(); - hide(); + // comes to the STATE_MINIMIZED eventually. + if (mState != STATE_MINIMIZED) return; + + // If is in the STATE_MINIMIZED, but there are other active recorders - simply ignore. + for (int index = mAudioActivityObservers.length - 1; index >= 0; index--) { + for (String activePackage : mAudioActivityObservers[index].getActivePackages()) { + if (mExemptPackages.contains(activePackage)) continue; + if (DEBUG) Log.d(TAG, " - there are still ongoing activities"); + return; + } } + + // Clear the state and hide the indicator. + mSessionNotifiedPackages.clear(); + hide(); } @UiThread private void show(String packageName) { + final String label = getApplicationLabel(packageName); + if (DEBUG) { + Log.d(TAG, "Showing indicator for " + packageName + " (" + label + ")..."); + } + // Inflate the indicator view mIndicatorView = LayoutInflater.from(mContext).inflate( R.layout.tv_audio_recording_indicator, @@ -196,7 +232,6 @@ class AudioRecordingDisclosureBar { mBgRight = mIndicatorView.findViewById(R.id.bg_right); // Set up the notification text - final String label = getApplicationLabel(packageName); mTextView.setText(mContext.getString(R.string.app_accessed_mic, label)); // Initially change the visibility to INVISIBLE, wait until and receives the size and @@ -260,6 +295,9 @@ class AudioRecordingDisclosureBar { @UiThread private void expand(String packageName) { final String label = getApplicationLabel(packageName); + if (DEBUG) { + Log.d(TAG, "Expanding for " + packageName + " (" + label + ")..."); + } mTextView.setText(mContext.getString(R.string.app_accessed_mic, label)); final AnimatorSet set = new AnimatorSet(); @@ -283,6 +321,7 @@ class AudioRecordingDisclosureBar { @UiThread private void minimize() { + if (DEBUG) Log.d(TAG, "Minimizing..."); final int targetOffset = mTextsContainers.getWidth(); final AnimatorSet set = new AnimatorSet(); set.playTogether( @@ -305,6 +344,7 @@ class AudioRecordingDisclosureBar { @UiThread private void hide() { + if (DEBUG) Log.d(TAG, "Hiding..."); final int targetOffset = mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX(); final AnimatorSet set = new AnimatorSet(); @@ -326,6 +366,7 @@ class AudioRecordingDisclosureBar { @UiThread private void onExpanded() { + if (DEBUG) Log.d(TAG, "Expanded"); mState = STATE_SHOWN; mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION); @@ -333,20 +374,21 @@ class AudioRecordingDisclosureBar { @UiThread private void onMinimized() { + if (DEBUG) Log.d(TAG, "Minimized"); mState = STATE_MINIMIZED; if (!mPendingNotificationPackages.isEmpty()) { // There is a new application that started recording, tell the user about it. expand(mPendingNotificationPackages.poll()); - } else if (mActiveAudioRecordingPackages.isEmpty()) { - // Nobody is recording anymore, clear state and remove the indicator. - mSessionNotifiedPackages.clear(); - hide(); + } else { + hideIndicatorIfNeeded(); } } @UiThread private void onHidden() { + if (DEBUG) Log.d(TAG, "Hidden"); + final WindowManager windowManager = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); windowManager.removeView(mIndicatorView); @@ -392,35 +434,4 @@ class AudioRecordingDisclosureBar { } return pm.getApplicationLabel(appInfo).toString(); } - - private class OnActiveRecordingListener implements AppOpsManager.OnOpActiveChangedListener { - private final Set<String> mExemptApps; - - private OnActiveRecordingListener() { - mExemptApps = new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray( - R.array.audio_recording_disclosure_exempt_apps))); - } - - @Override - public void onOpActiveChanged(String op, int uid, String packageName, boolean active) { - if (DEBUG) { - Log.d(TAG, - "OP_RECORD_AUDIO active change, active=" + active + ", app=" - + packageName); - } - - if (mExemptApps.contains(packageName)) { - if (DEBUG) { - Log.d(TAG, "\t- exempt app"); - } - return; - } - - if (active) { - onStartedRecording(packageName); - } else { - onDoneRecording(packageName); - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java new file mode 100644 index 000000000000..1ede88a26020 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tv.micdisclosure; + +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE; + +import static com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar.DEBUG; + +import android.annotation.UiThread; +import android.app.ActivityManager; +import android.app.IActivityManager; +import android.app.IProcessObserver; +import android.content.Context; +import android.os.RemoteException; +import android.util.ArrayMap; +import android.util.Log; +import android.util.SparseArray; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The purpose of these class is to detect packages that are running foreground services of type + * 'microphone' and to report back to {@link AudioRecordingDisclosureBar}. + */ +class MicrophoneForegroundServicesObserver extends AudioActivityObserver { + private static final String TAG = "MicrophoneForegroundServicesObserver"; + private static final boolean ENABLED = true; + + private final IActivityManager mActivityManager; + /** + * A dictionary that maps PIDs to the package names. We only keep track of the PIDs that are + * "active" (those that are running FGS with FOREGROUND_SERVICE_TYPE_MICROPHONE flag). + */ + private final SparseArray<String[]> mPidToPackages = new SparseArray<>(); + /** + * A dictionary that maps "active" packages to the number of the "active" processes associated + * with those packages. We really only need this in case when one application is running in + * multiple processes, so that we don't lose track of the package when one of its "active" + * processes ceases, while others remain "active". + */ + private final Map<String, Integer> mPackageToProcessCount = new ArrayMap<>(); + + MicrophoneForegroundServicesObserver(Context context, + OnAudioActivityStateChangeListener listener) { + super(context, listener); + + mActivityManager = ActivityManager.getService(); + try { + mActivityManager.registerProcessObserver(mProcessObserver); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't register process observer", e); + } + } + + @Override + Set<String> getActivePackages() { + return ENABLED ? mPackageToProcessCount.keySet() : Collections.emptySet(); + } + + @UiThread + private void onProcessForegroundServicesChanged(int pid, boolean hasMicFgs) { + final String[] changedPackages; + if (hasMicFgs) { + if (mPidToPackages.contains(pid)) { + // We are already tracking this pid - ignore. + changedPackages = null; + } else { + changedPackages = getPackageNames(pid); + mPidToPackages.append(pid, changedPackages); + } + } else { + changedPackages = mPidToPackages.removeReturnOld(pid); + } + + if (changedPackages == null) { + return; + } + + for (int index = changedPackages.length - 1; index >= 0; index--) { + final String packageName = changedPackages[index]; + int processCount = mPackageToProcessCount.getOrDefault(packageName, 0); + final boolean shouldNotify; + if (hasMicFgs) { + processCount++; + shouldNotify = processCount == 1; + } else { + processCount--; + shouldNotify = processCount == 0; + } + if (processCount > 0) { + mPackageToProcessCount.put(packageName, processCount); + } else { + mPackageToProcessCount.remove(packageName); + } + if (shouldNotify) notifyPackageStateChanged(packageName, hasMicFgs); + } + } + + @UiThread + private void onProcessDied(int pid) { + final String[] packages = mPidToPackages.removeReturnOld(pid); + if (packages == null) { + // This PID was not active - ignore. + return; + } + + for (int index = packages.length - 1; index >= 0; index--) { + final String packageName = packages[index]; + int processCount = mPackageToProcessCount.getOrDefault(packageName, 0); + if (processCount <= 0) { + Log.e(TAG, "Bookkeeping error, process count for " + packageName + " is " + + processCount); + continue; + } + processCount--; + if (processCount > 0) { + mPackageToProcessCount.put(packageName, processCount); + } else { + mPackageToProcessCount.remove(packageName); + notifyPackageStateChanged(packageName, false); + } + } + } + + @UiThread + private void notifyPackageStateChanged(String packageName, boolean active) { + if (active) { + if (DEBUG) Log.d(TAG, "New microphone fgs detected, package=" + packageName); + } else { + if (DEBUG) Log.d(TAG, "Microphone fgs is gone, package=" + packageName); + } + + if (ENABLED) mListener.onAudioActivityStateChange(active, packageName); + } + + @UiThread + private String[] getPackageNames(int pid) { + final List<ActivityManager.RunningAppProcessInfo> runningApps; + try { + runningApps = mActivityManager.getRunningAppProcesses(); + } catch (RemoteException e) { + Log.d(TAG, "Couldn't get package name for pid=" + pid); + return null; + } + if (runningApps == null) { + Log.wtf(TAG, "No running apps reported"); + } + for (ActivityManager.RunningAppProcessInfo app : runningApps) { + if (app.pid == pid) { + return app.pkgList; + } + } + return null; + } + + private final IProcessObserver mProcessObserver = new IProcessObserver.Stub() { + @Override + public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {} + + @Override + public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) { + mContext.getMainExecutor().execute(() -> onProcessForegroundServicesChanged(pid, + (serviceTypes & FOREGROUND_SERVICE_TYPE_MICROPHONE) != 0)); + } + + @Override + public void onProcessDied(int pid, int uid) { + mContext.getMainExecutor().execute( + () -> MicrophoneForegroundServicesObserver.this.onProcessDied(pid)); + } + }; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java new file mode 100644 index 000000000000..b5b1c2b3018a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.tv.micdisclosure; + +import static com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar.DEBUG; + +import android.annotation.UiThread; +import android.app.AppOpsManager; +import android.content.Context; +import android.util.ArraySet; +import android.util.Log; + +import java.util.Set; + +/** + * The purpose of these class is to detect packages that are conducting audio recording (according + * to {@link AppOpsManager}) and report this to {@link AudioRecordingDisclosureBar}. + */ +class RecordAudioAppOpObserver extends AudioActivityObserver implements + AppOpsManager.OnOpActiveChangedListener { + private static final String TAG = "RecordAudioAppOpObserver"; + + /** + * Set of the applications that currently are conducting audio recording according to {@link + * AppOpsManager}. + */ + private final Set<String> mActiveAudioRecordingPackages = new ArraySet<>(); + + RecordAudioAppOpObserver(Context context, OnAudioActivityStateChangeListener listener) { + super(context, listener); + + // Register AppOpsManager callback + final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService( + Context.APP_OPS_SERVICE); + appOpsManager.startWatchingActive( + new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, + mContext.getMainExecutor(), + this); + } + + @UiThread + @Override + Set<String> getActivePackages() { + return mActiveAudioRecordingPackages; + } + + @UiThread + @Override + public void onOpActiveChanged(String op, int uid, String packageName, boolean active) { + if (DEBUG) { + Log.d(TAG, + "OP_RECORD_AUDIO active change, active=" + active + ", package=" + + packageName); + } + + if (active) { + if (mActiveAudioRecordingPackages.add(packageName)) { + mListener.onAudioActivityStateChange(true, packageName); + } + } else { + if (mActiveAudioRecordingPackages.remove(packageName)) { + mListener.onAudioActivityStateChange(false, packageName); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java index 9ccb9bf5b62b..9b465ae15478 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java @@ -24,10 +24,10 @@ import android.content.Context; import android.content.res.Resources; import android.os.IBinder; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.Log; import android.view.View; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IAccessibilityManager; import android.widget.ToastPresenter; import com.android.internal.R; @@ -48,9 +48,8 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { private static final String TAG = "ToastUI"; private final CommandQueue mCommandQueue; - private final WindowManager mWindowManager; private final INotificationManager mNotificationManager; - private final AccessibilityManager mAccessibilityManager; + private final IAccessibilityManager mAccessibilityManager; private final int mGravity; private final int mY; @Nullable private ToastPresenter mPresenter; @@ -59,18 +58,17 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { @Inject public ToastUI(Context context, CommandQueue commandQueue) { this(context, commandQueue, - (WindowManager) context.getSystemService(Context.WINDOW_SERVICE), INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)), - AccessibilityManager.getInstance(context)); + IAccessibilityManager.Stub.asInterface( + ServiceManager.getService(Context.ACCESSIBILITY_SERVICE))); } @VisibleForTesting - ToastUI(Context context, CommandQueue commandQueue, WindowManager windowManager, - INotificationManager notificationManager, AccessibilityManager accessibilityManager) { + ToastUI(Context context, CommandQueue commandQueue, INotificationManager notificationManager, + @Nullable IAccessibilityManager accessibilityManager) { super(context); mCommandQueue = commandQueue; - mWindowManager = windowManager; mNotificationManager = notificationManager; mAccessibilityManager = accessibilityManager; Resources resources = mContext.getResources(); @@ -85,15 +83,16 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks { @Override @MainThread - public void showToast(String packageName, IBinder token, CharSequence text, + public void showToast(int uid, String packageName, IBinder token, CharSequence text, IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { if (mPresenter != null) { hideCurrentToast(); } - View view = ToastPresenter.getTextToastView(mContext, text); + Context context = mContext.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0); + View view = ToastPresenter.getTextToastView(context, text); mCallback = callback; - mPresenter = new ToastPresenter(mContext, mWindowManager, mAccessibilityManager, - mNotificationManager, packageName); + mPresenter = new ToastPresenter(context, mAccessibilityManager, mNotificationManager, + packageName); mPresenter.show(view, token, windowToken, duration, mGravity, 0, mY, 0, 0, mCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java index 381ccdb50386..1140b9aa3abb 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java +++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java @@ -194,7 +194,9 @@ public class SystemWindows { return; } final Display display = mDisplayController.getDisplay(mDisplayId); - SurfaceControlViewHost viewRoot = new SurfaceControlViewHost(mContext, display, wwm); + SurfaceControlViewHost viewRoot = + new SurfaceControlViewHost(mContext, display, wwm, + true /* useSfChoreographer */); attrs.flags |= FLAG_HARDWARE_ACCELERATED; viewRoot.setView(view, attrs); mViewRoots.put(view, viewRoot); diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java index 56a748497d4e..0d66340a3917 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java @@ -51,6 +51,7 @@ public class PipAnimationControllerTest extends SysuiTestCase { private PipAnimationController mPipAnimationController; + @Mock private SurfaceControl mLeash; @Mock @@ -60,10 +61,6 @@ public class PipAnimationControllerTest extends SysuiTestCase { public void setUp() throws Exception { mPipAnimationController = new PipAnimationController( mContext, new PipSurfaceTransactionHelper(mContext)); - mLeash = new SurfaceControl.Builder() - .setContainerLayer() - .setName("FakeLeash") - .build(); MockitoAnnotations.initMocks(this); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java index 65fbe79b5e9f..0a10ab2fbf02 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java @@ -16,29 +16,43 @@ package com.android.systemui.toast; +import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; +import static android.widget.ToastPresenter.TEXT_TOAST_LAYOUT; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.INotificationManager; import android.app.ITransientNotificationCallback; +import android.content.Context; import android.os.Binder; +import android.os.Parcel; +import android.os.Parcelable; import android.testing.AndroidTestingRunner; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.IAccessibilityManager; import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; +import android.widget.ToastPresenter; import androidx.test.filters.SmallTest; import com.android.internal.R; +import com.android.internal.util.IntPair; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue; @@ -49,32 +63,53 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; @SmallTest @RunWith(AndroidTestingRunner.class) public class ToastUITest extends SysuiTestCase { + private static final int ANDROID_UID = 1000; + private static final int SYSTEMUI_UID = 10140; + + private static final int UID_1 = 10255; private static final String PACKAGE_NAME_1 = "com.example1.test"; private static final Binder TOKEN_1 = new Binder(); private static final Binder WINDOW_TOKEN_1 = new Binder(); + + private static final int UID_2 = 10256; private static final String PACKAGE_NAME_2 = "com.example2.test"; private static final Binder TOKEN_2 = new Binder(); private static final Binder WINDOW_TOKEN_2 = new Binder(); + private static final String TEXT = "Hello World"; private static final int MESSAGE_RES_ID = R.id.message; + private Context mContextSpy; + private ToastUI mToastUI; + @Mock private LayoutInflater mLayoutInflater; @Mock private CommandQueue mCommandQueue; @Mock private WindowManager mWindowManager; @Mock private INotificationManager mNotificationManager; - @Mock private AccessibilityManager mAccessibilityManager; + @Mock private IAccessibilityManager mAccessibilityManager; @Mock private ITransientNotificationCallback mCallback; @Captor private ArgumentCaptor<View> mViewCaptor; @Captor private ArgumentCaptor<ViewGroup.LayoutParams> mParamsCaptor; - private ToastUI mToastUI; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mToastUI = new ToastUI(mContext, mCommandQueue, mWindowManager, mNotificationManager, + + // This is because inflate will result in WindowManager (WM) calls, which will fail since we + // are mocking it, so we mock LayoutInflater with the view obtained before mocking WM. + View view = ToastPresenter.getTextToastView(mContext, TEXT); + when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn(view); + mContext.addMockSystemService(LayoutInflater.class, mLayoutInflater); + + mContext.addMockSystemService(WindowManager.class, mWindowManager); + mContextSpy = spy(mContext); + doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt()); + + mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager, mAccessibilityManager); } @@ -87,7 +122,8 @@ public class ToastUITest extends SysuiTestCase { @Test public void testShowToast_addsCorrectViewToWindowManager() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null); + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + null); verify(mWindowManager).addView(mViewCaptor.capture(), any()); View view = mViewCaptor.getValue(); @@ -96,13 +132,14 @@ public class ToastUITest extends SysuiTestCase { @Test public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null); + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + null); verify(mWindowManager).addView(any(), mParamsCaptor.capture()); ViewGroup.LayoutParams params = mParamsCaptor.getValue(); assertThat(params).isInstanceOf(WindowManager.LayoutParams.class); WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params; - assertThat(windowParams.packageName).isEqualTo(mContext.getPackageName()); + assertThat(windowParams.packageName).isEqualTo(mContextSpy.getPackageName()); assertThat(windowParams.getTitle()).isEqualTo("Toast"); assertThat(windowParams.token).isEqualTo(WINDOW_TOKEN_1); assertThat(windowParams.privateFlags @@ -111,7 +148,8 @@ public class ToastUITest extends SysuiTestCase { @Test public void testShowToast_forAndroidPackage_addsAllUserFlag() throws Exception { - mToastUI.showToast("android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null); + mToastUI.showToast(ANDROID_UID, "android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + null); verify(mWindowManager).addView(any(), mParamsCaptor.capture()); ViewGroup.LayoutParams params = mParamsCaptor.getValue(); @@ -123,8 +161,8 @@ public class ToastUITest extends SysuiTestCase { @Test public void testShowToast_forSystemUiPackage_addsAllUserFlag() throws Exception { - mToastUI.showToast("com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, - null); + mToastUI.showToast(SYSTEMUI_UID, "com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1, + Toast.LENGTH_LONG, null); verify(mWindowManager).addView(any(), mParamsCaptor.capture()); ViewGroup.LayoutParams params = mParamsCaptor.getValue(); @@ -136,7 +174,7 @@ public class ToastUITest extends SysuiTestCase { @Test public void testShowToast_callsCallback() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mCallback); verify(mCallback).onToastShown(); @@ -144,14 +182,24 @@ public class ToastUITest extends SysuiTestCase { @Test public void testShowToast_sendsAccessibilityEvent() throws Exception { - when(mAccessibilityManager.isEnabled()).thenReturn(true); - - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null); + // Enable accessibility + when(mAccessibilityManager.addClient(any(), anyInt())).thenReturn( + IntPair.of(STATE_FLAG_ACCESSIBILITY_ENABLED, AccessibilityEvent.TYPES_ALL_MASK)); + // AccessibilityManager recycles the event that goes over the wire after making the binder + // call to the service. Since we are mocking the service, that call is local, so if we use + // ArgumentCaptor or ArgumentMatcher it will retain a reference to the recycled event, which + // will already have its state reset by the time we verify its contents. So, instead, we + // serialize it at call-time and later on deserialize it to verity its contents. + Parcel eventParcel = Parcel.obtain(); + doAnswer(writeArgumentToParcel(0, eventParcel)).when( + mAccessibilityManager).sendAccessibilityEvent(any(), anyInt()); + + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + null); - ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass( - AccessibilityEvent.class); - verify(mAccessibilityManager).sendAccessibilityEvent(eventCaptor.capture()); - AccessibilityEvent event = eventCaptor.getValue(); + eventParcel.setDataPosition(0); + assertThat(eventParcel.dataSize()).isGreaterThan(0); + AccessibilityEvent event = AccessibilityEvent.CREATOR.createFromParcel(eventParcel); assertThat(event.getEventType()).isEqualTo( AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); assertThat(event.getClassName()).isEqualTo(Toast.class.getName()); @@ -160,7 +208,7 @@ public class ToastUITest extends SysuiTestCase { @Test public void testHideToast_removesView() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mCallback); View view = verifyWmAddViewAndAttachToParent(); @@ -171,7 +219,7 @@ public class ToastUITest extends SysuiTestCase { @Test public void testHideToast_finishesToken() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mCallback); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1); @@ -181,7 +229,7 @@ public class ToastUITest extends SysuiTestCase { @Test public void testHideToast_callsCallback() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mCallback); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1); @@ -191,7 +239,7 @@ public class ToastUITest extends SysuiTestCase { @Test public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mCallback); mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2); @@ -201,7 +249,7 @@ public class ToastUITest extends SysuiTestCase { @Test public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mCallback); mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1); @@ -211,11 +259,12 @@ public class ToastUITest extends SysuiTestCase { @Test public void testShowToast_afterShowToast_hidesCurrentToast() throws Exception { - mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, + mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, mCallback); View view = verifyWmAddViewAndAttachToParent(); - mToastUI.showToast(PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, null); + mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, + null); verify(mWindowManager).removeViewImmediate(view); verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1); @@ -227,8 +276,15 @@ public class ToastUITest extends SysuiTestCase { verify(mWindowManager).addView(viewCaptor.capture(), any()); View view = viewCaptor.getValue(); // Simulate attaching to view hierarchy - ViewGroup parent = new FrameLayout(mContext); + ViewGroup parent = new FrameLayout(mContextSpy); parent.addView(view); return view; } + + private Answer<Void> writeArgumentToParcel(int i, Parcel dest) { + return inv -> { + inv.<Parcelable>getArgument(i).writeToParcel(dest, 0); + return null; + }; + } } diff --git a/packages/VpnDialogs/res/values-ky/strings.xml b/packages/VpnDialogs/res/values-ky/strings.xml index 4e2f698bb1e5..23c9be8819a8 100644 --- a/packages/VpnDialogs/res/values-ky/strings.xml +++ b/packages/VpnDialogs/res/values-ky/strings.xml @@ -26,7 +26,7 @@ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> байт / <xliff:g id="NUMBER_1">%2$s</xliff:g> пакет"</string> <string name="always_on_disconnected_title" msgid="1906740176262776166">"Ар дайым күйүк VPN\'ге туташа албай жатат"</string> <string name="always_on_disconnected_message" msgid="555634519845992917">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. <xliff:g id="VPN_APP_1">%1$s</xliff:g> тармагына кайра туташканга чейин телефонуңуз жалпыга ачык тармакты пайдаланып турат."</string> - <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. VPN тармагына кайра туташмайынча, Интернет байланышыңыз жок болот."</string> + <string name="always_on_disconnected_message_lockdown" msgid="4232225539869452120">"<xliff:g id="VPN_APP">%1$s</xliff:g> тармагына ар дайым туташып турсун деп жөндөлгөн, бирок учурда телефонуңуз ага туташа албай жатат. VPN тармагына кайра туташмайынча, Интернет жок болот."</string> <string name="always_on_disconnected_message_separator" msgid="3310614409322581371">" "</string> <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"VPN жөндөөлөрүн өзгөртүү"</string> <string name="configure" msgid="4905518375574791375">"Конфигурациялоо"</string> diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-ta/strings.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-ta/strings.xml new file mode 100644 index 000000000000..c896ee3aa8d1 --- /dev/null +++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-ta/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="display_cutout_emulation_overlay" msgid="7305489596221077240">"பஞ்ச் ஹோல் கட்அவுட்"</string> +</resources> diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index c8b6d8dfd1b7..132b6927badd 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -43,12 +43,10 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.graphics.GraphicBuffer; import android.graphics.ParcelableColorSpace; -import android.graphics.Point; -import android.graphics.Rect; import android.graphics.Region; import android.hardware.HardwareBuffer; import android.hardware.display.DisplayManager; -import android.hardware.display.DisplayManagerGlobal; +import android.hardware.display.DisplayManagerInternal; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -66,7 +64,6 @@ import android.util.SparseArray; import android.view.Display; import android.view.KeyEvent; import android.view.MagnificationSpec; -import android.view.SurfaceControl; import android.view.SurfaceControl.ScreenshotGraphicBuffer; import android.view.View; import android.view.WindowInfo; @@ -1010,53 +1007,29 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return; } - final Display display = DisplayManagerGlobal.getInstance() - .getRealDisplay(displayId); - if (display == null) { - sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, - callback); + // Private virtual displays are created by the ap and is not allowed to access by other + // aps. We assume the contents on this display should not be captured. + final DisplayManager displayManager = + (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); + final Display display = displayManager.getDisplay(displayId); + if ((display == null) || (display.getType() == Display.TYPE_VIRTUAL + && (display.getFlags() & Display.FLAG_PRIVATE) != 0)) { + sendScreenshotFailure( + AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback); return; } - sendScreenshotSuccess(display, callback); - } - - private ScreenshotGraphicBuffer takeScreenshotBuffer(Display display) { - final Point displaySize = new Point(); - // TODO (b/145893483): calling new API with the display as a parameter - // when surface control supported. - final IBinder token = SurfaceControl.getInternalDisplayToken(); - final Rect crop = new Rect(0, 0, displaySize.x, displaySize.y); - final int rotation = display.getRotation(); - display.getRealSize(displaySize); - - return SurfaceControl.screenshotToBuffer(token, crop, displaySize.x, displaySize.y, - false, rotation); - } - - private void sendScreenshotSuccess(Display display, RemoteCallback callback) { final long identity = Binder.clearCallingIdentity(); try { mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> { - final ScreenshotGraphicBuffer screenshotBuffer = takeScreenshotBuffer(display); - final GraphicBuffer graphicBuffer = screenshotBuffer.getGraphicBuffer(); - try (HardwareBuffer hardwareBuffer = - HardwareBuffer.createFromGraphicBuffer(graphicBuffer)) { - final ParcelableColorSpace colorSpace = - new ParcelableColorSpace(screenshotBuffer.getColorSpace()); - - final Bundle payload = new Bundle(); - payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS, - AccessibilityService.TAKE_SCREENSHOT_SUCCESS); - payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER, - hardwareBuffer); - payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace); - payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP, - SystemClock.uptimeMillis()); - - // Send back the result. - callback.sendResult(payload); - hardwareBuffer.close(); + final ScreenshotGraphicBuffer screenshotBuffer = LocalServices + .getService(DisplayManagerInternal.class) + .screenshotWithoutSecureLayer(displayId); + if (screenshotBuffer != null) { + sendScreenshotSuccess(screenshotBuffer, callback); + } else { + sendScreenshotFailure( + AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback); } }, null).recycleOnUse()); } finally { @@ -1064,6 +1037,29 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } } + private void sendScreenshotSuccess(ScreenshotGraphicBuffer screenshotBuffer, + RemoteCallback callback) { + final GraphicBuffer graphicBuffer = screenshotBuffer.getGraphicBuffer(); + try (HardwareBuffer hardwareBuffer = + HardwareBuffer.createFromGraphicBuffer(graphicBuffer)) { + final ParcelableColorSpace colorSpace = + new ParcelableColorSpace(screenshotBuffer.getColorSpace()); + + final Bundle payload = new Bundle(); + payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS, + AccessibilityService.TAKE_SCREENSHOT_SUCCESS); + payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER, + hardwareBuffer); + payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace); + payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP, + SystemClock.uptimeMillis()); + + // Send back the result. + callback.sendResult(payload); + hardwareBuffer.close(); + } + } + private void sendScreenshotFailure(@AccessibilityService.ScreenshotErrorCode int errorCode, RemoteCallback callback) { mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 1b180e3357d7..2100c1a8be44 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -197,7 +197,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final MainHandler mMainHandler; - private final SystemActionPerformer mSystemActionPerformer; + // Lazily initialized - access through getSystemActionPerfomer() + private SystemActionPerformer mSystemActionPerformer; private MagnificationController mMagnificationController; @@ -295,8 +296,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class); mPackageManager = mContext.getPackageManager(); mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this); - mSystemActionPerformer = - new SystemActionPerformer(mContext, mWindowManagerService, null, this); mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler, mWindowManagerService, this, mSecurityPolicy, this); mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); @@ -667,7 +666,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mSecurityPolicy.enforceCallerIsRecentsOrHasPermission( Manifest.permission.MANAGE_ACCESSIBILITY, FUNCTION_REGISTER_SYSTEM_ACTION); - mSystemActionPerformer.registerSystemAction(actionId, action); + getSystemActionPerformer().registerSystemAction(actionId, action); } /** @@ -680,7 +679,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mSecurityPolicy.enforceCallerIsRecentsOrHasPermission( Manifest.permission.MANAGE_ACCESSIBILITY, FUNCTION_UNREGISTER_SYSTEM_ACTION); - mSystemActionPerformer.unregisterSystemAction(actionId); + getSystemActionPerformer().unregisterSystemAction(actionId); + } + + private SystemActionPerformer getSystemActionPerformer() { + if (mSystemActionPerformer == null) { + mSystemActionPerformer = + new SystemActionPerformer(mContext, mWindowManagerService, null, this); + } + return mSystemActionPerformer; } @Override @@ -792,7 +799,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub synchronized (mLock) { mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient, mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler, - mSecurityPolicy, this, mWindowManagerService, mSystemActionPerformer, + mSecurityPolicy, this, mWindowManagerService, getSystemActionPerformer(), mA11yWindowManager, flags); onUserStateChangedLocked(getCurrentUserStateLocked()); } @@ -1503,7 +1510,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (service == null) { service = new AccessibilityServiceConnection(userState, mContext, componentName, installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, - this, mWindowManagerService, mSystemActionPerformer, + this, mWindowManagerService, getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService); } else if (userState.mBoundServices.contains(service)) { continue; @@ -2741,7 +2748,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub userState, mContext, COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, AccessibilityManagerService.this, mWindowManagerService, - mSystemActionPerformer, mA11yWindowManager, mActivityTaskManagerService) { + getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) { @Override public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { return true; diff --git a/services/core/Android.bp b/services/core/Android.bp index 5faed43dd6e6..a8bc2b4bc6ce 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -91,7 +91,6 @@ java_library_static { ], libs: [ - "android_system_server_stubs_current", "services.net", "android.hardware.light-V2.0-java", "android.hardware.power-java", @@ -101,6 +100,7 @@ java_library_static { "android.net.ipsec.ike.stubs.module_libs_api", "app-compat-annotations", "framework-tethering-stubs-module_libs_api", + "service-permission-stubs", ], required: [ diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java index aedafbbf1662..94f5741fe828 100644 --- a/services/core/java/android/os/UserManagerInternal.java +++ b/services/core/java/android/os/UserManagerInternal.java @@ -23,6 +23,8 @@ import android.content.Context; import android.content.pm.UserInfo; import android.graphics.Bitmap; +import com.android.server.pm.RestrictionsSet; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -57,21 +59,18 @@ public abstract class UserManagerInternal { * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set * restrictions enforced by the user. * - * @param originatingUserId user id of the user where the restriction originated. - * @param restrictions a bundle of user restrictions. - * @param restrictionOwnerType determines which admin {@code userId} corresponds to. - * The admin can be either - * {@link UserManagerInternal#OWNER_TYPE_DEVICE_OWNER}, - * {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER}, - * {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE} - * or {@link UserManagerInternal#OWNER_TYPE_NO_OWNER}. - * If the admin is a DEVICE_OWNER or a PROFILE_OWNER_ORG_OWNED_DEVICE then - * a restriction may be applied globally depending on which restriction it is, - * otherwise it will be applied just on the current user. - * @see OwnerType + * @param originatingUserId user id of the user where the restrictions originated. + * @param global a bundle of global user restrictions. Global restrictions are + * restrictions that apply device-wide: to the managed profile, + * primary profile and secondary users and any profile created in + * any secondary user. + * @param local a restriction set of local user restrictions. The key is the user + * id of the user whom the restrictions are targeting. + * @param isDeviceOwner whether {@code originatingUserId} corresponds to device owner + * user id. */ public abstract void setDevicePolicyUserRestrictions(int originatingUserId, - @Nullable Bundle restrictions, @OwnerType int restrictionOwnerType); + @Nullable Bundle global, @Nullable RestrictionsSet local, boolean isDeviceOwner); /** * Returns the "base" user restrictions. diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2eaa766ad32d..8a1de1f0763e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3153,7 +3153,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - nai.clatd.setNat64Prefix(prefix); + nai.clatd.setNat64PrefixFromDns(prefix); handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } @@ -5865,9 +5865,9 @@ public class ConnectivityService extends IConnectivityManager.Stub @NonNull LinkProperties oldLp) { int netId = networkAgent.network.netId; - // The NetworkAgentInfo does not know whether clatd is running on its network or not, or - // whether there is a NAT64 prefix. Before we do anything else, make sure its LinkProperties - // are accurate. + // The NetworkAgent does not know whether clatd is running on its network or not, or whether + // a NAT64 prefix was discovered by the DNS resolver. Before we do anything else, make sure + // the LinkProperties for the network are accurate. networkAgent.clatd.fixupLinkProperties(oldLp, newLp); updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities, diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 8ccff7605811..a9c3079adcc0 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -2598,8 +2598,6 @@ public class LocationManagerService extends ILocationManager.Stub { @Override @NonNull public List<LocationRequest> getTestProviderCurrentRequests(String provider) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null); - LocationProviderManager manager = getLocationProviderManager(provider); if (manager == null) { throw new IllegalArgumentException("provider doesn't exist: " + provider); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 62d7eb1d0448..e41ba0e1745d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12121,8 +12121,6 @@ public class ActivityManagerService extends IActivityManager.Stub void dumpAllowedAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { - boolean needSep = false; - pw.println("ACTIVITY MANAGER ALLOWED ASSOCIATION STATE (dumpsys activity allowed-associations)"); boolean printed = false; if (mAllowedAssociations != null) { @@ -12130,21 +12128,16 @@ public class ActivityManagerService extends IActivityManager.Stub final String pkg = mAllowedAssociations.keyAt(i); final ArraySet<String> asc = mAllowedAssociations.valueAt(i).getAllowedPackageAssociations(); - boolean printedHeader = false; + if (!printed) { + pw.println(" Allowed associations (by restricted package):"); + printed = true; + } + pw.print(" * "); + pw.print(pkg); + pw.println(":"); for (int j = 0; j < asc.size(); j++) { if (dumpPackage == null || pkg.equals(dumpPackage) || asc.valueAt(j).equals(dumpPackage)) { - if (!printed) { - pw.println(" Allowed associations (by restricted package):"); - printed = true; - needSep = true; - } - if (!printedHeader) { - pw.print(" * "); - pw.print(pkg); - pw.println(":"); - printedHeader = true; - } pw.print(" Allow: "); pw.println(asc.valueAt(j)); } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 8e6ef75078b3..31bcceaba889 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -5853,10 +5853,6 @@ public class AppOpsService extends IAppOpsService.Stub { if (pkg == null) { return false; } - if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.Q) { - return false; - } - String[] requestedPermissions = pkg.requestedPermissions; if (requestedPermissions == null) { return false; diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index 82465f8a093e..3b3c52072bf4 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -81,7 +81,7 @@ public class Nat464Xlat extends BaseNetworkObserver { RUNNING, // start() called, and the stacked iface is known to be up. } - private IpPrefix mNat64Prefix; + private IpPrefix mNat64PrefixFromDns; private String mBaseIface; private String mIface; private Inet6Address mIPv6Address; @@ -100,7 +100,7 @@ public class Nat464Xlat extends BaseNetworkObserver { * currently connected and where the NetworkAgent has not disabled 464xlat. It is the signal to * enable NAT64 prefix discovery. * - * @param network the NetworkAgentInfo corresponding to the network. + * @param nai the NetworkAgentInfo corresponding to the network. * @return true if the network requires clat, false otherwise. */ @VisibleForTesting @@ -180,7 +180,7 @@ public class Nat464Xlat extends BaseNetworkObserver { String addrStr = null; try { - addrStr = mNetd.clatdStart(baseIface, mNat64Prefix.toString()); + addrStr = mNetd.clatdStart(baseIface, getNat64Prefix().toString()); } catch (RemoteException | ServiceSpecificException e) { Slog.e(TAG, "Error starting clatd on " + baseIface + ": " + e); } @@ -318,8 +318,12 @@ public class Nat464Xlat extends BaseNetworkObserver { } } - public void setNat64Prefix(IpPrefix nat64Prefix) { - mNat64Prefix = nat64Prefix; + private IpPrefix getNat64Prefix() { + return mNat64PrefixFromDns; + } + + public void setNat64PrefixFromDns(IpPrefix prefix) { + mNat64PrefixFromDns = prefix; } /** @@ -328,7 +332,7 @@ public class Nat464Xlat extends BaseNetworkObserver { * has no idea that 464xlat is running on top of it. */ public void fixupLinkProperties(@NonNull LinkProperties oldLp, @NonNull LinkProperties lp) { - lp.setNat64Prefix(mNat64Prefix); + lp.setNat64Prefix(getNat64Prefix()); if (!isRunning()) { return; diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 61b18eedfc6e..962f337a8b3f 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -80,6 +80,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -398,78 +399,93 @@ public final class ContentService extends IContentService.Stub { */ @Override public void notifyChange(Uri[] uris, IContentObserver observer, - boolean observerWantsSelfNotifications, int flags, int userHandle, + boolean observerWantsSelfNotifications, int flags, int userId, int targetSdkVersion, String callingPackage) { - final ObserverCollector collector = new ObserverCollector(); - for (Uri uri : uris) { - notifyChange(uri, observer, observerWantsSelfNotifications, flags, userHandle, - targetSdkVersion, callingPackage, collector); - } - final long token = clearCallingIdentity(); - try { - collector.dispatch(); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - public void notifyChange(Uri uri, IContentObserver observer, - boolean observerWantsSelfNotifications, int flags, int userHandle, - int targetSdkVersion, String callingPackage, ObserverCollector collector) { - if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle - + " from observer " + observer + ", flags " + Integer.toHexString(flags)); - - if (uri == null) { - throw new NullPointerException("Uri must not be null"); + if (DEBUG) { + Slog.d(TAG, "Notifying update of " + Arrays.toString(uris) + " for user " + userId + + ", observer " + observer + ", flags " + Integer.toHexString(flags)); } final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); - final int callingUserHandle = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); + + // Set of notification events that we need to dispatch + final ObserverCollector collector = new ObserverCollector(); - userHandle = handleIncomingUser(uri, callingPid, callingUid, - Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle); + // Set of content provider authorities that we've validated the caller + // has access to, mapped to the package name hosting that provider + final ArrayMap<Pair<String, Integer>, String> validatedProviders = new ArrayMap<>(); - final String msg = LocalServices.getService(ActivityManagerInternal.class) - .checkContentProviderAccess(uri.getAuthority(), userHandle); - if (msg != null) { - if (targetSdkVersion >= Build.VERSION_CODES.O) { - throw new SecurityException(msg); - } else { - if (msg.startsWith("Failed to find provider")) { - // Sigh, we need to quietly let apps targeting older API - // levels notify on non-existent providers. - } else { - Log.w(TAG, "Ignoring notify for " + uri + " from " + callingUid + ": " + msg); - return; + for (Uri uri : uris) { + // Validate that calling app has access to this provider + final int resolvedUserId = handleIncomingUser(uri, callingPid, callingUid, + Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userId); + final Pair<String, Integer> provider = Pair.create(uri.getAuthority(), resolvedUserId); + if (!validatedProviders.containsKey(provider)) { + final String msg = LocalServices.getService(ActivityManagerInternal.class) + .checkContentProviderAccess(uri.getAuthority(), resolvedUserId); + if (msg != null) { + if (targetSdkVersion >= Build.VERSION_CODES.O) { + throw new SecurityException(msg); + } else { + if (msg.startsWith("Failed to find provider")) { + // Sigh, we need to quietly let apps targeting older API + // levels notify on non-existent providers. + } else { + Log.w(TAG, "Ignoring notify for " + uri + " from " + + callingUid + ": " + msg); + continue; + } + } } + + // Remember that we've validated this access + final String packageName = getProviderPackageName(uri, resolvedUserId); + validatedProviders.put(provider, packageName); } - } - // This makes it so that future permission checks will be in the context of this - // process rather than the caller's process. We will restore this before returning. - long identityToken = clearCallingIdentity(); - try { + // No concerns raised above, so caller has access; let's collect the + // notifications that should be dispatched synchronized (mRootNode) { - mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications, - flags, userHandle, collector); + final int segmentCount = ObserverNode.countUriSegments(uri); + mRootNode.collectObserversLocked(uri, segmentCount, 0, observer, + observerWantsSelfNotifications, flags, resolvedUserId, collector); } - if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) { - SyncManager syncManager = getSyncManager(); - if (syncManager != null) { - syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, - callingUid, - uri.getAuthority(), getSyncExemptionForCaller(callingUid), - callingUid, callingPid, callingPackage); + } + + final long token = clearCallingIdentity(); + try { + // Actually dispatch all the notifications we collected + collector.dispatch(); + + for (int i = 0; i < validatedProviders.size(); i++) { + final String authority = validatedProviders.keyAt(i).first; + final int resolvedUserId = validatedProviders.keyAt(i).second; + final String packageName = validatedProviders.valueAt(i); + + // Kick off sync adapters for any authorities we touched + if ((flags & ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) { + SyncManager syncManager = getSyncManager(); + if (syncManager != null) { + syncManager.scheduleLocalSync(null /* all accounts */, callingUserId, + callingUid, + authority, getSyncExemptionForCaller(callingUid), + callingUid, callingPid, callingPackage); + } } - } - synchronized (mCache) { - final String providerPackageName = getProviderPackageName(uri, userHandle); - invalidateCacheLocked(userHandle, providerPackageName, uri); + // Invalidate caches for any authorities we touched + synchronized (mCache) { + for (Uri uri : uris) { + if (Objects.equals(uri.getAuthority(), authority)) { + invalidateCacheLocked(resolvedUserId, packageName, uri); + } + } + } } } finally { - restoreCallingIdentity(identityToken); + Binder.restoreCallingIdentity(token); } } @@ -1533,7 +1549,7 @@ public final class ContentService extends IContentService.Stub { } } - private String getUriSegment(Uri uri, int index) { + public static String getUriSegment(Uri uri, int index) { if (uri != null) { if (index == 0) { return uri.getAuthority(); @@ -1545,7 +1561,7 @@ public final class ContentService extends IContentService.Stub { } } - private int countUriSegments(Uri uri) { + public static int countUriSegments(Uri uri) { if (uri == null) { return 0; } @@ -1669,14 +1685,21 @@ public final class ContentService extends IContentService.Stub { } } + @VisibleForTesting + public void collectObserversLocked(Uri uri, int index, + IContentObserver observer, boolean observerWantsSelfNotifications, int flags, + int targetUserHandle, ObserverCollector collector) { + collectObserversLocked(uri, countUriSegments(uri), index, observer, + observerWantsSelfNotifications, flags, targetUserHandle, collector); + } + /** * targetUserHandle is either a hard user handle or is USER_ALL */ - public void collectObserversLocked(Uri uri, int index, IContentObserver observer, - boolean observerWantsSelfNotifications, int flags, - int targetUserHandle, ObserverCollector collector) { + public void collectObserversLocked(Uri uri, int segmentCount, int index, + IContentObserver observer, boolean observerWantsSelfNotifications, int flags, + int targetUserHandle, ObserverCollector collector) { String segment = null; - int segmentCount = countUriSegments(uri); if (index >= segmentCount) { // This is the leaf node, notify all observers if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName); @@ -1696,7 +1719,7 @@ public final class ContentService extends IContentService.Stub { ObserverNode node = mChildren.get(i); if (segment == null || node.mName.equals(segment)) { // We found the child, - node.collectObserversLocked(uri, index + 1, observer, + node.collectObserversLocked(uri, segmentCount, index + 1, observer, observerWantsSelfNotifications, flags, targetUserHandle, collector); if (segment != null) { break; diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 6178e6c1e094..f4d7f9ac5a5e 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -200,7 +200,7 @@ class AutomaticBrightnessController { // Context-sensitive brightness configurations require keeping track of the foreground app's // package name and category, which is done by registering a TaskStackListener to call back to // us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's - // package namd and PackageManager to get its category (so might as well cache them). + // package name and PackageManager to get its category (so might as well cache them). private String mForegroundAppPackageName; private String mPendingForegroundAppPackageName; private @ApplicationInfo.Category int mForegroundAppCategory; @@ -210,6 +210,7 @@ class AutomaticBrightnessController { private PackageManager mPackageManager; private Context mContext; + private DisplayDeviceConfig mDisplayDeviceConfig; private final Injector mInjector; AutomaticBrightnessController(Callbacks callbacks, Looper looper, @@ -218,12 +219,14 @@ class AutomaticBrightnessController { float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, - HysteresisLevels screenBrightnessThresholds, Context context) { + HysteresisLevels screenBrightnessThresholds, Context context, DisplayDeviceConfig + displayDeviceConfig) { this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper, lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig, darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig, - ambientBrightnessThresholds, screenBrightnessThresholds, context); + ambientBrightnessThresholds, screenBrightnessThresholds, context, + displayDeviceConfig); } @VisibleForTesting @@ -233,7 +236,8 @@ class AutomaticBrightnessController { float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds, - HysteresisLevels screenBrightnessThresholds, Context context) { + HysteresisLevels screenBrightnessThresholds, Context context, DisplayDeviceConfig + displayDeviceConfig) { mInjector = injector; mContext = context; mCallbacks = callbacks; @@ -260,7 +264,7 @@ class AutomaticBrightnessController { mScreenBrightnessThresholds = screenBrightnessThresholds; mShortTermModelValid = true; mShortTermModelAnchor = -1; - + mDisplayDeviceConfig = displayDeviceConfig; mHandler = new AutomaticBrightnessHandler(looper); mAmbientLightRingBuffer = new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon); diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java index 696daca79092..3516981c92a6 100644 --- a/services/core/java/com/android/server/display/DisplayDevice.java +++ b/services/core/java/com/android/server/display/DisplayDevice.java @@ -37,6 +37,7 @@ abstract class DisplayDevice { private final DisplayAdapter mDisplayAdapter; private final IBinder mDisplayToken; private final String mUniqueId; + private DisplayDeviceConfig mDisplayDeviceConfig; // The display device does not manage these properties itself, they are set by // the display manager service. The display device shouldn't really be looking at these. @@ -68,6 +69,16 @@ abstract class DisplayDevice { return mDisplayAdapter; } + /* + * Gets the DisplayDeviceConfig for this DisplayDevice. + * Returns null for this device but is overridden in LocalDisplayDevice. + * + * @return The DisplayDeviceConfig. + */ + public DisplayDeviceConfig getDisplayDeviceConfig() { + return mDisplayDeviceConfig; + } + /** * Gets the Surface Flinger display token for this display. * diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 3afbf661f97e..a87fb8b5c301 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -1362,7 +1362,8 @@ public final class DisplayManagerService extends SystemService { return null; } - private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId) { + private SurfaceControl.ScreenshotGraphicBuffer screenshotInternal(int displayId, + boolean captureSecureLayer) { synchronized (mSyncRoot) { final IBinder token = getDisplayToken(displayId); if (token == null) { @@ -1374,9 +1375,15 @@ public final class DisplayManagerService extends SystemService { } final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked(); - return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(), - displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(), - false /* useIdentityTransform */, 0 /* rotation */); + if (captureSecureLayer) { + return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(), + displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(), + false /* useIdentityTransform */, 0 /* rotation */); + } else { + return SurfaceControl.screenshotToBuffer(token, new Rect(), + displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(), + false /* useIdentityTransform */, 0 /* rotation */); + } } } @@ -2469,7 +2476,8 @@ public final class DisplayManagerService extends SystemService { } }; mDisplayPowerController = new DisplayPowerController( - mContext, callbacks, handler, sensorManager, blanker); + mContext, callbacks, handler, sensorManager, blanker, + mDisplayDevices.get(Display.DEFAULT_DISPLAY)); mSensorManager = sensorManager; } @@ -2494,7 +2502,12 @@ public final class DisplayManagerService extends SystemService { @Override public SurfaceControl.ScreenshotGraphicBuffer screenshot(int displayId) { - return screenshotInternal(displayId); + return screenshotInternal(displayId, true); + } + + @Override + public SurfaceControl.ScreenshotGraphicBuffer screenshotWithoutSecureLayer(int displayId) { + return screenshotInternal(displayId, false); } @Override @@ -2503,6 +2516,17 @@ public final class DisplayManagerService extends SystemService { } @Override + public Point getDisplayPosition(int displayId) { + synchronized (mSyncRoot) { + LogicalDisplay display = mLogicalDisplays.get(displayId); + if (display != null) { + return display.getDisplayPosition(); + } + return null; + } + } + + @Override public void registerDisplayTransactionListener(DisplayTransactionListener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 197842ed1c2d..f82ec82ce79b 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -161,6 +161,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // The display blanker. private final DisplayBlanker mBlanker; + // The display device. + private final DisplayDevice mDisplayDevice; + // Tracker for brightness changes. private final BrightnessTracker mBrightnessTracker; @@ -348,11 +351,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Nullable private BrightnessConfiguration mBrightnessConfiguration; - // The last brightness that was set by the user and not temporary. Set to -1 when a brightness - // has yet to be recorded. + // The last brightness that was set by the user and not temporary. Set to + // PowerManager.BRIGHTNESS_INVALID_FLOAT when a brightness has yet to be recorded. private float mLastUserSetScreenBrightness; - // The screen brightenss setting has changed but not taken effect yet. If this is different + // The screen brightness setting has changed but not taken effect yet. If this is different // from the current screen brightness setting then this is coming from something other than us // and should be considered a user interaction. private float mPendingScreenBrightnessSetting; @@ -377,8 +380,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private float mPendingAutoBrightnessAdjustment; // The temporary auto brightness adjustment. Typically set when a user is interacting with the - // adjustment slider but hasn't settled on a choice yet. Set to Float.NaN when there's no - // temporary adjustment set. + // adjustment slider but hasn't settled on a choice yet. Set to + // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set. private float mTemporaryAutoBrightnessAdjustment; // Animators. @@ -386,27 +389,29 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private ObjectAnimator mColorFadeOffAnimator; private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator; - private BrightnessSynchronizer mBrightnessSynchronizer; /** * Creates the display power controller. */ public DisplayPowerController(Context context, DisplayPowerCallbacks callbacks, Handler handler, - SensorManager sensorManager, DisplayBlanker blanker) { + SensorManager sensorManager, DisplayBlanker blanker, DisplayDevice displayDevice) { mHandler = new DisplayControllerHandler(handler.getLooper()); mBrightnessTracker = new BrightnessTracker(context, null); mSettingsObserver = new SettingsObserver(mHandler); mCallbacks = callbacks; - mBrightnessSynchronizer = new BrightnessSynchronizer(context); mBatteryStats = BatteryStatsService.getService(); mSensorManager = sensorManager; mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class); mBlanker = blanker; mContext = context; + mDisplayDevice = displayDevice; PowerManager pm = context.getSystemService(PowerManager.class); + DisplayDeviceConfig displayDeviceConfig = mDisplayDevice.getDisplayDeviceConfig(); + final Resources resources = context.getResources(); + final float screenBrightnessSettingMinimumFloat = clampAbsoluteBrightness( pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM)); @@ -498,7 +503,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate, initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, - screenBrightnessThresholds, context); + screenBrightnessThresholds, context, displayDeviceConfig); } else { mUseSoftwareAutoBrightnessConfig = false; } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 8eb771046e6d..6132467103a9 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -203,6 +203,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { private Spline mNitsToHalBrightness; private boolean mHalBrightnessSupport; + private DisplayDeviceConfig mDisplayDeviceConfig; + LocalDisplayDevice(IBinder displayToken, long physicalDisplayId, SurfaceControl.DisplayInfo info, SurfaceControl.DisplayConfig[] configs, int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs, @@ -224,7 +226,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mAllmSupported = SurfaceControl.getAutoLowLatencyModeSupport(displayToken); mGameContentTypeSupported = SurfaceControl.getGameContentTypeSupport(displayToken); mHalBrightnessSupport = SurfaceControl.getDisplayBrightnessSupport(displayToken); - + mDisplayDeviceConfig = null; // Defer configuration file loading BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage( LocalDisplayDevice::loadDisplayConfigurationBrightnessMapping, this)); @@ -373,17 +375,23 @@ final class LocalDisplayAdapter extends DisplayAdapter { return true; } + @Override + public DisplayDeviceConfig getDisplayDeviceConfig() { + return mDisplayDeviceConfig; + } + private void loadDisplayConfigurationBrightnessMapping() { Spline nitsToHal = null; Spline sysToNits = null; // Load the mapping from nits to HAL brightness range (display-device-config.xml) DisplayDeviceConfig config = DisplayDeviceConfig.create(mPhysicalDisplayId); + mDisplayDeviceConfig = config; if (config == null) { return; } - final float[] halNits = config.getNits(); - final float[] halBrightness = config.getBrightness(); + final float[] halNits = mDisplayDeviceConfig.getNits(); + final float[] halBrightness = mDisplayDeviceConfig.getBrightness(); if (halNits == null || halBrightness == null) { return; } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 3a5aa93d205d..0261f388f7cb 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -16,6 +16,7 @@ package com.android.server.display; +import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManagerInternal; import android.view.Display; @@ -98,6 +99,11 @@ final class LogicalDisplay { private int mDisplayOffsetY; /** + * The position of the display projection sent to SurfaceFlinger + */ + private final Point mDisplayPosition = new Point(); + + /** * {@code true} if display scaling is disabled, or {@code false} if the default scaling mode * is used. * @see #isDisplayScalingDisabled() @@ -335,6 +341,16 @@ final class LogicalDisplay { } /** + * Returns the position of the display's projection. + * + * @return The x, y coordinates of the display. The return object must be treated as immutable. + */ + Point getDisplayPosition() { + // Allocate a new object to avoid a data race. + return new Point(mDisplayPosition); + } + + /** * Applies the layer stack and transformation to the given display device * so that it shows the contents of this logical display. * @@ -445,6 +461,8 @@ final class LogicalDisplay { } else { // Surface.ROTATION_270 mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX); } + + mDisplayPosition.set(mTempDisplayRect.left, mTempDisplayRect.top); device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ed3b9f1fc265..776db63ced73 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2745,15 +2745,15 @@ public class NotificationManagerService extends SystemService { return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId; } - private ToastRecord getToastRecord(int pid, String packageName, IBinder token, + private ToastRecord getToastRecord(int uid, int pid, String packageName, IBinder token, @Nullable CharSequence text, @Nullable ITransientNotification callback, int duration, Binder windowToken, int displayId, @Nullable ITransientNotificationCallback textCallback) { if (callback == null) { - return new TextToastRecord(this, mStatusBar, pid, packageName, token, text, duration, - windowToken, displayId, textCallback); + return new TextToastRecord(this, mStatusBar, uid, pid, packageName, token, text, + duration, windowToken, displayId, textCallback); } else { - return new CustomToastRecord(this, pid, packageName, token, callback, duration, + return new CustomToastRecord(this, uid, pid, packageName, token, callback, duration, windowToken, displayId); } } @@ -2878,8 +2878,8 @@ public class NotificationManagerService extends SystemService { Binder windowToken = new Binder(); mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId); - record = getToastRecord(callingPid, pkg, token, text, callback, duration, - windowToken, displayId, textCallback); + record = getToastRecord(callingUid, callingPid, pkg, token, text, callback, + duration, windowToken, displayId, textCallback); mToastQueue.add(record); index = mToastQueue.size() - 1; keepProcessAliveForToastIfNeededLocked(callingPid); diff --git a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java index aca6f4853597..2b91a00f9da5 100644 --- a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java +++ b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java @@ -23,6 +23,7 @@ import android.app.ITransientNotification; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Slog; import com.android.server.notification.NotificationManagerService; @@ -35,11 +36,10 @@ public class CustomToastRecord extends ToastRecord { public final ITransientNotification callback; - public CustomToastRecord( - NotificationManagerService notificationManager, int pid, String packageName, - IBinder token, ITransientNotification callback, int duration, Binder windowToken, - int displayId) { - super(notificationManager, pid, packageName, token, duration, windowToken, displayId); + public CustomToastRecord(NotificationManagerService notificationManager, int uid, int pid, + String packageName, IBinder token, ITransientNotification callback, int duration, + Binder windowToken, int displayId) { + super(notificationManager, uid, pid, packageName, token, duration, windowToken, displayId); this.callback = checkNotNull(callback); } @@ -74,8 +74,8 @@ public class CustomToastRecord extends ToastRecord { public String toString() { return "CustomToastRecord{" + Integer.toHexString(System.identityHashCode(this)) + + " " + pid + ":" + pkg + "/" + UserHandle.formatUid(uid) + " token=" + token - + " packageName=" + pkg + " callback=" + callback + " duration=" + getDuration() + "}"; diff --git a/services/core/java/com/android/server/notification/toast/TextToastRecord.java b/services/core/java/com/android/server/notification/toast/TextToastRecord.java index 3c231b445f62..544520edc7fc 100644 --- a/services/core/java/com/android/server/notification/toast/TextToastRecord.java +++ b/services/core/java/com/android/server/notification/toast/TextToastRecord.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.app.ITransientNotificationCallback; import android.os.Binder; import android.os.IBinder; +import android.os.UserHandle; import android.util.Slog; import com.android.server.notification.NotificationManagerService; @@ -41,10 +42,10 @@ public class TextToastRecord extends ToastRecord { private final ITransientNotificationCallback mCallback; public TextToastRecord(NotificationManagerService notificationManager, - @Nullable StatusBarManagerInternal statusBarManager, int pid, String packageName, - IBinder token, CharSequence text, int duration, Binder windowToken, int displayId, - @Nullable ITransientNotificationCallback callback) { - super(notificationManager, pid, packageName, token, duration, windowToken, displayId); + @Nullable StatusBarManagerInternal statusBarManager, int uid, int pid, + String packageName, IBinder token, CharSequence text, int duration, Binder windowToken, + int displayId, @Nullable ITransientNotificationCallback callback) { + super(notificationManager, uid, pid, packageName, token, duration, windowToken, displayId); mStatusBar = statusBarManager; mCallback = callback; this.text = checkNotNull(text); @@ -59,7 +60,7 @@ public class TextToastRecord extends ToastRecord { Slog.w(TAG, "StatusBar not available to show text toast for package " + pkg); return false; } - mStatusBar.showToast(pkg, token, text, windowToken, getDuration(), mCallback); + mStatusBar.showToast(uid, pkg, token, text, windowToken, getDuration(), mCallback); return true; } @@ -75,8 +76,8 @@ public class TextToastRecord extends ToastRecord { public String toString() { return "TextToastRecord{" + Integer.toHexString(System.identityHashCode(this)) + + " " + pid + ":" + pkg + "/" + UserHandle.formatUid(uid) + " token=" + token - + " packageName=" + pkg + " text=" + text + " duration=" + getDuration() + "}"; diff --git a/services/core/java/com/android/server/notification/toast/ToastRecord.java b/services/core/java/com/android/server/notification/toast/ToastRecord.java index ef75a6f5dd7b..7915f7013227 100644 --- a/services/core/java/com/android/server/notification/toast/ToastRecord.java +++ b/services/core/java/com/android/server/notification/toast/ToastRecord.java @@ -28,6 +28,7 @@ import java.io.PrintWriter; * Represents a toast, a transient notification. */ public abstract class ToastRecord { + public final int uid; public final int pid; public final String pkg; public final IBinder token; @@ -36,11 +37,10 @@ public abstract class ToastRecord { protected final NotificationManagerService mNotificationManager; private int mDuration; - protected ToastRecord( - NotificationManagerService notificationManager, - int pid, String pkg, IBinder token, int duration, - Binder windowToken, int displayId) { + protected ToastRecord(NotificationManagerService notificationManager, int uid, int pid, + String pkg, IBinder token, int duration, Binder windowToken, int displayId) { this.mNotificationManager = notificationManager; + this.uid = uid; this.pid = pid; this.pkg = pkg; this.token = token; diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java index e8e383404bd6..7df8fc7e34ed 100644 --- a/services/core/java/com/android/server/om/IdmapDaemon.java +++ b/services/core/java/com/android/server/om/IdmapDaemon.java @@ -18,20 +18,19 @@ package com.android.server.om; import static android.content.Context.IDMAP_SERVICE; -import static com.android.server.om.OverlayManagerService.DEBUG; import static com.android.server.om.OverlayManagerService.TAG; import android.os.IBinder; import android.os.IIdmap2; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemProperties; +import android.os.SystemClock; +import android.os.SystemService; import android.util.Slog; import com.android.server.FgThread; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; /** @@ -45,13 +44,14 @@ class IdmapDaemon { // The amount of time in milliseconds to wait when attempting to connect to idmap service. private static final int SERVICE_CONNECT_TIMEOUT_MS = 5000; + private static final int SERVICE_CONNECT_INTERVAL_SLEEP_MS = 200; - private static final Object IDMAP_TOKEN = new Object(); private static final String IDMAP_DAEMON = "idmap2d"; private static IdmapDaemon sInstance; private volatile IIdmap2 mService; private final AtomicInteger mOpenedCount = new AtomicInteger(); + private final Object mIdmapToken = new Object(); /** * An {@link AutoCloseable} connection to the idmap service. When the connection is closed or @@ -62,14 +62,14 @@ class IdmapDaemon { private boolean mOpened = true; private Connection() { - synchronized (IDMAP_TOKEN) { + synchronized (mIdmapToken) { mOpenedCount.incrementAndGet(); } } @Override public void close() { - synchronized (IDMAP_TOKEN) { + synchronized (mIdmapToken) { if (!mOpened) { return; } @@ -82,7 +82,7 @@ class IdmapDaemon { } FgThread.getHandler().postDelayed(() -> { - synchronized (IDMAP_TOKEN) { + synchronized (mIdmapToken) { // Only stop the service if the service does not have an open connection. if (mService == null || mOpenedCount.get() != 0) { return; @@ -91,7 +91,7 @@ class IdmapDaemon { stopIdmapService(); mService = null; } - }, IDMAP_TOKEN, SERVICE_TIMEOUT_MS); + }, mIdmapToken, SERVICE_TIMEOUT_MS); } } } @@ -104,14 +104,14 @@ class IdmapDaemon { } String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce, - int userId) throws Exception { - try (Connection connection = connect()) { + int userId) throws TimeoutException, RemoteException { + try (Connection c = connect()) { return mService.createIdmap(targetPath, overlayPath, policies, enforce, userId); } } - boolean removeIdmap(String overlayPath, int userId) throws Exception { - try (Connection connection = connect()) { + boolean removeIdmap(String overlayPath, int userId) throws TimeoutException, RemoteException { + try (Connection c = connect()) { return mService.removeIdmap(overlayPath, userId); } } @@ -119,76 +119,54 @@ class IdmapDaemon { boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce, int userId) throws Exception { - try (Connection connection = connect()) { + try (Connection c = connect()) { return mService.verifyIdmap(targetPath, overlayPath, policies, enforce, userId); } } - String getIdmapPath(String overlayPath, int userId) throws Exception { - try (Connection connection = connect()) { + String getIdmapPath(String overlayPath, int userId) throws TimeoutException, RemoteException { + try (Connection c = connect()) { return mService.getIdmapPath(overlayPath, userId); } } - private static void startIdmapService() { - SystemProperties.set("ctl.start", IDMAP_DAEMON); + private IBinder getIdmapService() throws TimeoutException, RemoteException { + SystemService.start(IDMAP_DAEMON); + + final long endMillis = SystemClock.elapsedRealtime() + SERVICE_CONNECT_TIMEOUT_MS; + while (SystemClock.elapsedRealtime() <= endMillis) { + final IBinder binder = ServiceManager.getService(IDMAP_SERVICE); + if (binder != null) { + binder.linkToDeath( + () -> Slog.w(TAG, String.format("service '%s' died", IDMAP_SERVICE)), 0); + return binder; + } + + try { + Thread.sleep(SERVICE_CONNECT_INTERVAL_SLEEP_MS); + } catch (InterruptedException ignored) { + } + } + + throw new TimeoutException( + String.format("Failed to connect to '%s' in %d milliseconds", IDMAP_SERVICE, + SERVICE_CONNECT_TIMEOUT_MS)); } private static void stopIdmapService() { - SystemProperties.set("ctl.stop", IDMAP_DAEMON); + SystemService.stop(IDMAP_DAEMON); } - private Connection connect() throws Exception { - synchronized (IDMAP_TOKEN) { - FgThread.getHandler().removeCallbacksAndMessages(IDMAP_TOKEN); + private Connection connect() throws TimeoutException, RemoteException { + synchronized (mIdmapToken) { + FgThread.getHandler().removeCallbacksAndMessages(mIdmapToken); if (mService != null) { // Not enough time has passed to stop the idmap service. Reuse the existing // interface. return new Connection(); } - // Start the idmap service if it is not currently running. - startIdmapService(); - - // Block until the service is found. - FutureTask<IBinder> bindIdmap = new FutureTask<>(() -> { - while (true) { - try { - IBinder binder = ServiceManager.getService(IDMAP_SERVICE); - if (binder != null) { - return binder; - } - } catch (Exception e) { - Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not retrieved; " - + e.getMessage()); - } - Thread.sleep(100); - } - }); - - IBinder binder; - try { - FgThread.getHandler().postAtFrontOfQueue(bindIdmap); - binder = bindIdmap.get(SERVICE_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (Exception rethrow) { - Slog.e(TAG, "service '" + IDMAP_SERVICE + "' not found;"); - throw rethrow; - } - - try { - binder.linkToDeath(() -> { - Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died"); - }, 0); - } catch (RemoteException rethrow) { - Slog.e(TAG, "service '" + IDMAP_SERVICE + "' failed to be bound"); - throw rethrow; - } - - mService = IIdmap2.Stub.asInterface(binder); - if (DEBUG) { - Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected"); - } - + mService = IIdmap2.Stub.asInterface(getIdmapService()); return new Connection(); } } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index e625aeffc0c6..e7d0c41c0fea 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -401,7 +401,8 @@ public class PackageDexOptimizer { return DEX_OPT_FAILED; } String classLoaderContext = null; - if (dexUseInfo.isUnknownClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) { + if (dexUseInfo.isUnsupportedClassLoaderContext() + || dexUseInfo.isVariableClassLoaderContext()) { // If we have an unknown (not yet set), or a variable class loader chain. Just extract // the dex file. compilerFilter = "extract"; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f96ab1d9a042..ab3b2be46988 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17534,31 +17534,26 @@ public class PackageManagerService extends IPackageManager.Stub + " Activities needs verification ..."); int count = 0; - boolean handlesWebUris = false; - final boolean alreadyVerified; + synchronized (mLock) { // If this is a new install and we see that we've already run verification for this // package, we have nothing to do: it means the state was restored from backup. - final IntentFilterVerificationInfo ivi = - mSettings.getIntentFilterVerificationLPr(packageName); - alreadyVerified = (ivi != null); - if (!replacing && alreadyVerified) { - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, "Package " + packageName + " already verified: status=" - + ivi.getStatusString()); + if (!replacing) { + IntentFilterVerificationInfo ivi = + mSettings.getIntentFilterVerificationLPr(packageName); + if (ivi != null) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Package " + packageName+ " already verified: status=" + + ivi.getStatusString()); + } + return; } - return; } - // If any filters need to be verified, then all need to be. In addition, we need to - // know whether an updating app has any web navigation intent filters, to re- - // examine handling policy even if not re-verifying. + // If any filters need to be verified, then all need to be. boolean needToVerify = false; for (ParsedActivity a : activities) { for (ParsedIntentInfo filter : a.getIntents()) { - if (filter.handlesWebUris(true)) { - handlesWebUris = true; - } if (filter.needsVerification() && needsNetworkVerificationLPr(a.getPackageName())) { if (DEBUG_DOMAIN_VERIFICATION) { @@ -17566,17 +17561,11 @@ public class PackageManagerService extends IPackageManager.Stub "Intent filter needs verification, so processing all filters"); } needToVerify = true; - // It's safe to break out here because filter.needsVerification() - // can only be true if filter.handlesWebUris(true) returns true, so - // we've already noted that. break; } } } - // Note whether this app publishes any web navigation handling support at all, - // and whether there are any web-nav filters that fit the profile for running - // a verification pass now. if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; for (ParsedActivity a : activities) { @@ -17595,23 +17584,13 @@ public class PackageManagerService extends IPackageManager.Stub } if (count > 0) { - // count > 0 means that we're running a full verification pass if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count + " IntentFilter verification" + (count > 1 ? "s" : "") + " for userId:" + userId); mIntentFilterVerifier.startVerifications(userId); - } else if (alreadyVerified && handlesWebUris) { - // App used autoVerify in the past, no longer does, but still handles web - // navigation starts. - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy"); - } - synchronized (mLock) { - clearIntentFilterVerificationsLPw(packageName, userId); - } } else { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "No web filters or no prior verify policy for " + packageName); + Slog.d(TAG, "No filters or not all autoVerify for " + packageName); } } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 091535dfc792..e8696f60b59a 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1291,7 +1291,6 @@ public final class Settings { return false; } ps.clearDomainVerificationStatusForUser(userId); - ps.setIntentFilterVerificationInfo(null); return true; } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index d2443fa735e9..323ffcfc2a1c 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1716,27 +1716,6 @@ public class UserManagerService extends IUserManager.Stub { } } - private void setDevicePolicyUserRestrictionsInner(@UserIdInt int originatingUserId, - @Nullable Bundle restrictions, - @UserManagerInternal.OwnerType int restrictionOwnerType) { - final Bundle global = new Bundle(); - final Bundle local = new Bundle(); - - // Sort restrictions into local and global ensuring they don't overlap. - UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, restrictionOwnerType, global, - local); - boolean isDeviceOwner = restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER; - - RestrictionsSet localRestrictionsSet; - if (UserRestrictionsUtils.isEmpty(local)) { - localRestrictionsSet = new RestrictionsSet(); - } else { - localRestrictionsSet = new RestrictionsSet(originatingUserId, local); - } - setDevicePolicyUserRestrictionsInner(originatingUserId, global, localRestrictionsSet, - isDeviceOwner); - } - /** * See {@link UserManagerInternal#setDevicePolicyUserRestrictions} */ @@ -4754,10 +4733,10 @@ public class UserManagerService extends IUserManager.Stub { private class LocalService extends UserManagerInternal { @Override public void setDevicePolicyUserRestrictions(@UserIdInt int originatingUserId, - @Nullable Bundle restrictions, - @OwnerType int restrictionOwnerType) { + @NonNull Bundle global, @NonNull RestrictionsSet local, + boolean isDeviceOwner) { UserManagerService.this.setDevicePolicyUserRestrictionsInner(originatingUserId, - restrictions, restrictionOwnerType); + global, local, isDeviceOwner); } @Override diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index eec6e024fef2..c0502b8a068c 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -233,6 +233,13 @@ public class UserRestrictionsUtils { ); /** + * Special user restrictions that profile owner of an organization-owned managed profile can + * set on the parent profile instance to apply them on the personal profile. + */ + private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS = + Sets.newArraySet(); + + /** * User restrictions that default to {@code true} for managed profile owners. * * NB: {@link UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} is also set by default but it is @@ -416,7 +423,8 @@ public class UserRestrictionsUtils { * @return true if a restriction is settable by profile owner of an organization owned device. */ public static boolean canProfileOwnerOfOrganizationOwnedDeviceChange(String restriction) { - return PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(restriction); + return PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(restriction) + || PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS.contains(restriction); } /** @@ -427,31 +435,9 @@ public class UserRestrictionsUtils { } /** - * Takes restrictions that can be set by device owner, and sort them into what should be applied - * globally and what should be applied only on the current user. - */ - public static void sortToGlobalAndLocal(@Nullable Bundle in, - @UserManagerInternal.OwnerType int restrictionOwnerType, @NonNull Bundle global, - @NonNull Bundle local) { - if (in == null || in.size() == 0) { - return; - } - for (String key : in.keySet()) { - if (!in.getBoolean(key)) { - continue; - } - if (isGlobal(restrictionOwnerType, key)) { - global.putBoolean(key, true); - } else { - local.putBoolean(key, true); - } - } - } - - /** * Whether given user restriction should be enforced globally. */ - private static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType, + public static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType, String key) { return ((restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) && ( PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key))) @@ -463,6 +449,14 @@ public class UserRestrictionsUtils { } /** + * Whether given user restriction should be enforced locally. + */ + public static boolean isLocal(@UserManagerInternal.OwnerType int restrictionOwnerType, + String key) { + return !isGlobal(restrictionOwnerType, key); + } + + /** * @return true if two Bundles contain the same user restriction. * A null bundle and an empty bundle are considered to be equal. */ diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 117cc5e8eb80..e8765ad973f3 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -45,6 +45,7 @@ import dalvik.system.VMRuntime; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -103,19 +104,6 @@ public class DexManager { private static int DEX_SEARCH_FOUND_SPLIT = 2; // dex file is a split apk private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex - /** - * We do not record packages that have no secondary dex files or that are not used by other - * apps. This is an optimization to reduce the amount of data that needs to be written to - * disk (apps will not usually be shared so this trims quite a bit the number we record). - * - * To make this behaviour transparent to the callers which need use information on packages, - * DexManager will return this DEFAULT instance from - * {@link DexManager#getPackageUseInfoOrDefault}. It has no data about secondary dex files and - * is marked as not being used by other apps. This reflects the intended behaviour when we don't - * find the package in the underlying data file. - */ - private final static PackageUseInfo DEFAULT_USE_INFO = new PackageUseInfo(); - public DexManager(Context context, IPackageManager pms, PackageDexOptimizer pdo, Installer installer, Object installLock) { mContext = context; @@ -194,6 +182,8 @@ public class DexManager { // If the dex file is the primary apk (or a split) and not isUsedByOtherApps // do not record it. This case does not bring any new usable information // and can be safely skipped. + // Note this is just an optimization that makes things easier to read in the + // package-dex-use file since we don't need to pollute it with redundant info. continue; } @@ -211,7 +201,7 @@ public class DexManager { // async write to disk to make sure we don't loose the data in case of a reboot. if (mPackageDexUsage.record(searchResult.mOwningPackageName, - dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit, + dexPath, loaderUserId, loaderIsa, primaryOrSplit, loadingAppInfo.packageName, classLoaderContext)) { mPackageDexUsage.maybeWriteAsync(); } @@ -364,7 +354,9 @@ public class DexManager { try { mPackageDexUsage.read(); - mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths); + List<String> packagesToKeepDataAbout = new ArrayList<>(); + mPackageDexUsage.syncData( + packageToUsersMap, packageToCodePaths, packagesToKeepDataAbout); } catch (Exception e) { mPackageDexUsage.clear(); Slog.w(TAG, "Exception while loading package dex usage. " @@ -391,8 +383,17 @@ public class DexManager { * to access the package use. */ public PackageUseInfo getPackageUseInfoOrDefault(String packageName) { + // We do not record packages that have no secondary dex files or that are not used by other + // apps. This is an optimization to reduce the amount of data that needs to be written to + // disk (apps will not usually be shared so this trims quite a bit the number we record). + // + // To make this behaviour transparent to the callers which need use information on packages, + // DexManager will return this DEFAULT instance from + // {@link DexManager#getPackageUseInfoOrDefault}. It has no data about secondary dex files + // and is marked as not being used by other apps. This reflects the intended behaviour when + // we don't find the package in the underlying data file. PackageUseInfo useInfo = mPackageDexUsage.getPackageUseInfo(packageName); - return useInfo == null ? DEFAULT_USE_INFO : useInfo; + return useInfo == null ? new PackageUseInfo(packageName) : useInfo; } /** @@ -542,7 +543,7 @@ public class DexManager { // TODO(calin): questionable API in the presence of class loaders context. Needs amends as the // compilation happening here will use a pessimistic context. public RegisterDexModuleResult registerDexModule(ApplicationInfo info, String dexPath, - boolean isUsedByOtherApps, int userId) { + boolean isSharedModule, int userId) { // Find the owning package record. DexSearchResult searchResult = getDexPackage(info, dexPath, userId); @@ -559,11 +560,14 @@ public class DexManager { // We found the package. Now record the usage for all declared ISAs. boolean update = false; + // If this is a shared module set the loading package to an arbitrary package name + // so that we can mark that module as usedByOthers. + String loadingPackage = isSharedModule ? ".shared.module" : searchResult.mOwningPackageName; for (String isa : getAppDexInstructionSets(info.primaryCpuAbi, info.secondaryCpuAbi)) { boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName, - dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false, + dexPath, userId, isa, /*primaryOrSplit*/ false, searchResult.mOwningPackageName, - PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT); + PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT); update |= newUpdate; } if (update) { diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java index 08763e729c71..10760f52a02b 100644 --- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java +++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java @@ -39,10 +39,12 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -51,25 +53,21 @@ import java.util.Set; * Stat file which store usage information about dex files. */ public class PackageDexUsage extends AbstractStatsBase<Void> { - private final static String TAG = "PackageDexUsage"; + private static final String TAG = "PackageDexUsage"; - // We support previous version to ensure that the usage list remains valid cross OTAs. - private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1 = 1; - // Version 2 added: - // - the list of packages that load the dex files - // - class loader contexts for secondary dex files - // - usage for all code paths (including splits) - private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2 = 2; + // We are currently at version 2. + // Version 1 was introduced in Nougat and Version 2 in Oreo. + // We dropped version 1 support in R since all devices should have updated + // already. + private static final int PACKAGE_DEX_USAGE_VERSION = 2; - private final static int PACKAGE_DEX_USAGE_VERSION = PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2; - - private final static String PACKAGE_DEX_USAGE_VERSION_HEADER = + private static final String PACKAGE_DEX_USAGE_VERSION_HEADER = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__"; - private final static String SPLIT_CHAR = ","; - private final static String CODE_PATH_LINE_CHAR = "+"; - private final static String DEX_LINE_CHAR = "#"; - private final static String LOADING_PACKAGE_CHAR = "@"; + private static final String SPLIT_CHAR = ","; + private static final String CODE_PATH_LINE_CHAR = "+"; + private static final String DEX_LINE_CHAR = "#"; + private static final String LOADING_PACKAGE_CHAR = "@"; // One of the things we record about dex files is the class loader context that was used to // load them. That should be stable but if it changes we don't keep track of variable contexts. @@ -77,10 +75,6 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // skip optimizations on that dex files. /*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT = "=VariableClassLoaderContext="; - // The markers used for unknown class loader contexts. This can happen if the dex file was - // recorded in a previous version and we didn't have a chance to update its usage. - /*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT = - "=UnknownClassLoaderContext="; // The marker used for unsupported class loader contexts (no longer written, may occur in old // files so discarded on read). Note: this matches @@ -126,7 +120,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { * has been seen before. */ /* package */ boolean record(String owningPackageName, String dexPath, int ownerUserId, - String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, + String loaderIsa, boolean primaryOrSplit, String loadingPackageName, String classLoaderContext) { if (!PackageManagerServiceUtils.checkISA(loaderIsa)) { throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported"); @@ -135,20 +129,22 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { throw new IllegalArgumentException("Null classLoaderContext"); } if (classLoaderContext.equals(UNSUPPORTED_CLASS_LOADER_CONTEXT)) { + Slog.e(TAG, "Unsupported context?"); return false; } + boolean isUsedByOtherApps = !owningPackageName.equals(loadingPackageName); + synchronized (mPackageUseInfoMap) { PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName); if (packageUseInfo == null) { // This is the first time we see the package. - packageUseInfo = new PackageUseInfo(); + packageUseInfo = new PackageUseInfo(owningPackageName); if (primaryOrSplit) { // If we have a primary or a split apk, set isUsedByOtherApps. // We do not need to record the loaderIsa or the owner because we compile // primaries for all users and all ISAs. - packageUseInfo.mergeCodePathUsedByOtherApps(dexPath, isUsedByOtherApps, - owningPackageName, loadingPackageName); + packageUseInfo.mergePrimaryCodePaths(dexPath, loadingPackageName); } else { // For secondary dex files record the loaderISA and the owner. We'll need // to know under which user to compile and for what ISA. @@ -164,9 +160,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // We already have data on this package. Amend it. if (primaryOrSplit) { // We have a possible update on the primary apk usage. Merge - // isUsedByOtherApps information and return if there was an update. - return packageUseInfo.mergeCodePathUsedByOtherApps( - dexPath, isUsedByOtherApps, owningPackageName, loadingPackageName); + // dex path information and return if there was an update. + return packageUseInfo.mergePrimaryCodePaths(dexPath, loadingPackageName); } else { DexUseInfo newData = new DexUseInfo( isUsedByOtherApps, ownerUserId, classLoaderContext, loaderIsa); @@ -281,7 +276,7 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // Write the code paths used by other apps. for (Map.Entry<String, Set<String>> codeEntry : - packageUseInfo.mCodePathsUsedByOtherApps.entrySet()) { + packageUseInfo.mPrimaryCodePaths.entrySet()) { String codePath = codeEntry.getKey(); Set<String> loadingPackages = codeEntry.getValue(); fpw.println(CODE_PATH_LINE_CHAR + codePath); @@ -339,7 +334,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { version = Integer.parseInt( versionLine.substring(PACKAGE_DEX_USAGE_VERSION_HEADER.length())); if (!isSupportedVersion(version)) { - throw new IllegalStateException("Unexpected version: " + version); + Slog.w(TAG, "Unexpected package-dex-use version: " + version + + ". Not reading from it"); + return; } } @@ -377,9 +374,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { throw new IllegalStateException("Invalid PackageDexUsage line: " + line); } - // In version 2 we added the loading packages and class loader context. - Set<String> loadingPackages = maybeReadLoadingPackages(in, version); - String classLoaderContext = maybeReadClassLoaderContext(in, version); + Set<String> loadingPackages = readLoadingPackages(in, version); + String classLoaderContext = readClassLoaderContext(in, version); if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(classLoaderContext)) { // We used to record use of unsupported class loaders, but we no longer do. @@ -410,34 +406,16 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } currentPackageData.mDexUseInfoMap.put(dexPath, dexUseInfo); } else if (line.startsWith(CODE_PATH_LINE_CHAR)) { - // This is a code path used by other apps line. - if (version < PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) { - throw new IllegalArgumentException("Unexpected code path line when parsing " + - "PackageDexUseData: " + line); - } - // Expects 2 lines: // +code_paths // @loading_packages String codePath = line.substring(CODE_PATH_LINE_CHAR.length()); - Set<String> loadingPackages = maybeReadLoadingPackages(in, version); - currentPackageData.mCodePathsUsedByOtherApps.put(codePath, loadingPackages); + Set<String> loadingPackages = readLoadingPackages(in, version); + currentPackageData.mPrimaryCodePaths.put(codePath, loadingPackages); } else { // This is a package line. - if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) { - currentPackage = line; - currentPackageData = new PackageUseInfo(); - } else { - // Old version (<2) - // We expect it to be: `packageName,isUsedByOtherApps`. - String[] elems = line.split(SPLIT_CHAR); - if (elems.length != 2) { - throw new IllegalStateException("Invalid PackageDexUsage line: " + line); - } - currentPackage = elems[0]; - currentPackageData = new PackageUseInfo(); - currentPackageData.mUsedByOtherAppsBeforeUpgrade = readBoolean(elems[1]); - } + currentPackage = line; + currentPackageData = new PackageUseInfo(currentPackage); data.put(currentPackage, currentPackageData); } } @@ -449,46 +427,31 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } /** - * Reads the class loader context encoding from the buffer {@code in} if - * {@code version} is at least {PACKAGE_DEX_USAGE_VERSION}. + * Reads the class loader context encoding from the buffer {@code in}. */ - private String maybeReadClassLoaderContext(BufferedReader in, int version) throws IOException { - String context = null; - if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) { - context = in.readLine(); - if (context == null) { - throw new IllegalStateException("Could not find the classLoaderContext line."); - } + private String readClassLoaderContext(BufferedReader in, int version) throws IOException { + String context = in.readLine(); + if (context == null) { + throw new IllegalStateException("Could not find the classLoaderContext line."); } - // The context might be empty if we didn't have the chance to update it after a version - // upgrade. In this case return the special marker so that we recognize this is an unknown - // context. - return context == null ? UNKNOWN_CLASS_LOADER_CONTEXT : context; + return context; } /** - * Reads the list of loading packages from the buffer {@code in} if - * {@code version} is at least {PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2}. + * Reads the list of loading packages from the buffer {@code in}. */ - private Set<String> maybeReadLoadingPackages(BufferedReader in, int version) + private Set<String> readLoadingPackages(BufferedReader in, int version) throws IOException { - if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) { - String line = in.readLine(); - if (line == null) { - throw new IllegalStateException("Could not find the loadingPackages line."); - } - // We expect that most of the times the list of loading packages will be empty. - if (line.length() == LOADING_PACKAGE_CHAR.length()) { - return Collections.emptySet(); - } else { - Set<String> result = new HashSet<>(); - Collections.addAll(result, - line.substring(LOADING_PACKAGE_CHAR.length()).split(SPLIT_CHAR)); - return result; - } - } else { - return Collections.emptySet(); + String line = in.readLine(); + if (line == null) { + throw new IllegalStateException("Could not find the loadingPackages line."); + } + Set<String> result = new HashSet<>(); + if (line.length() != LOADING_PACKAGE_CHAR.length()) { + Collections.addAll(result, + line.substring(LOADING_PACKAGE_CHAR.length()).split(SPLIT_CHAR)); } + return result; } /** @@ -501,21 +464,26 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } private boolean isSupportedVersion(int version) { - return version == PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1 - || version == PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2; + return version == PACKAGE_DEX_USAGE_VERSION; } /** * Syncs the existing data with the set of available packages by removing obsolete entries. */ /*package*/ void syncData(Map<String, Set<Integer>> packageToUsersMap, - Map<String, Set<String>> packageToCodePaths) { + Map<String, Set<String>> packageToCodePaths, + List<String> packagesToKeepDataAbout) { synchronized (mPackageUseInfoMap) { Iterator<Map.Entry<String, PackageUseInfo>> pIt = mPackageUseInfoMap.entrySet().iterator(); while (pIt.hasNext()) { Map.Entry<String, PackageUseInfo> pEntry = pIt.next(); String packageName = pEntry.getKey(); + if (packagesToKeepDataAbout.contains(packageName)) { + // This is a package for which we should keep the data even if it's not + // in the list of user packages. + continue; + } PackageUseInfo packageUseInfo = pEntry.getValue(); Set<Integer> users = packageToUsersMap.get(packageName); if (users == null) { @@ -536,22 +504,31 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { // Sync the code paths. Set<String> codePaths = packageToCodePaths.get(packageName); - Iterator<Map.Entry<String, Set<String>>> codeIt = - packageUseInfo.mCodePathsUsedByOtherApps.entrySet().iterator(); - while (codeIt.hasNext()) { - if (!codePaths.contains(codeIt.next().getKey())) { - codeIt.remove(); + + Iterator<Map.Entry<String, Set<String>>> recordedIt = + packageUseInfo.mPrimaryCodePaths.entrySet().iterator(); + while (recordedIt.hasNext()) { + Map.Entry<String, Set<String>> entry = recordedIt.next(); + String recordedCodePath = entry.getKey(); + if (!codePaths.contains(recordedCodePath)) { + // Clean up a non existing code path. + recordedIt.remove(); + } else { + // Clean up a non existing loading package. + Set<String> recordedLoadingPackages = entry.getValue(); + Iterator<String> recordedLoadingPackagesIt = + recordedLoadingPackages.iterator(); + while (recordedLoadingPackagesIt.hasNext()) { + String recordedLoadingPackage = recordedLoadingPackagesIt.next(); + if (!packagesToKeepDataAbout.contains(recordedLoadingPackage) + && !packageToUsersMap.containsKey(recordedLoadingPackage)) { + recordedLoadingPackagesIt.remove(); + } + } } } - // In case the package was marked as used by other apps in a previous version - // propagate the flag to all the code paths. - // See mUsedByOtherAppsBeforeUpgrade docs on why it is important to do it. - if (packageUseInfo.mUsedByOtherAppsBeforeUpgrade) { - for (String codePath : codePaths) { - packageUseInfo.mergeCodePathUsedByOtherApps(codePath, true, null, null); - } - } else if (!packageUseInfo.isAnyCodePathUsedByOtherApps() + if (!packageUseInfo.isAnyCodePathUsedByOtherApps() && packageUseInfo.mDexUseInfoMap.isEmpty()) { // The package is not used by other apps and we removed all its dex files // records. Remove the entire package record as well. @@ -712,35 +689,26 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { * Stores data on how a package and its dex files are used. */ public static class PackageUseInfo { + // The name of the package this info belongs to. + private final String mPackageName; // The app's code paths that are used by other apps. // The key is the code path and the value is the set of loading packages. - private final Map<String, Set<String>> mCodePathsUsedByOtherApps; + private final Map<String, Set<String>> mPrimaryCodePaths; // Map dex paths to their data (isUsedByOtherApps, owner id, loader isa). private final Map<String, DexUseInfo> mDexUseInfoMap; - // Keeps track of whether or not this package was used by other apps before - // we upgraded to VERSION 4 which records the info for each code path separately. - // This is unwanted complexity but without it we risk to profile guide compile - // something that supposed to be shared. For example: - // 1) we determine that chrome is used by another app - // 2) we take an OTA which upgrades the way we keep track of usage data - // 3) chrome doesn't get used until the background job executes - // 4) as part of the backgound job we now think that chrome is not used by others - // and we speed-profile. - // 5) as a result the next time someone uses chrome it will extract from apk since - // the compiled code will be private. - private boolean mUsedByOtherAppsBeforeUpgrade; - - /*package*/ PackageUseInfo() { - mCodePathsUsedByOtherApps = new HashMap<>(); + /*package*/ PackageUseInfo(String packageName) { + mPrimaryCodePaths = new HashMap<>(); mDexUseInfoMap = new HashMap<>(); + mPackageName = packageName; } // Creates a deep copy of the `other`. private PackageUseInfo(PackageUseInfo other) { - mCodePathsUsedByOtherApps = new HashMap<>(); - for (Map.Entry<String, Set<String>> e : other.mCodePathsUsedByOtherApps.entrySet()) { - mCodePathsUsedByOtherApps.put(e.getKey(), new HashSet<>(e.getValue())); + mPackageName = other.mPackageName; + mPrimaryCodePaths = new HashMap<>(); + for (Map.Entry<String, Set<String>> e : other.mPrimaryCodePaths.entrySet()) { + mPrimaryCodePaths.put(e.getKey(), new HashSet<>(e.getValue())); } mDexUseInfoMap = new HashMap<>(); @@ -749,28 +717,29 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } } - private boolean mergeCodePathUsedByOtherApps(String codePath, boolean isUsedByOtherApps, - String owningPackageName, String loadingPackage) { - if (!isUsedByOtherApps) { - // Nothing to update if the the code path is not used by other apps. - return false; - } - - boolean newCodePath = false; - Set<String> loadingPackages = mCodePathsUsedByOtherApps.get(codePath); + private boolean mergePrimaryCodePaths(String codePath, String loadingPackage) { + Set<String> loadingPackages = mPrimaryCodePaths.get(codePath); if (loadingPackages == null) { loadingPackages = new HashSet<>(); - mCodePathsUsedByOtherApps.put(codePath, loadingPackages); - newCodePath = true; + mPrimaryCodePaths.put(codePath, loadingPackages); } - boolean newLoadingPackage = loadingPackage != null - && !loadingPackage.equals(owningPackageName) - && loadingPackages.add(loadingPackage); - return newCodePath || newLoadingPackage; + return loadingPackages.add(loadingPackage); } public boolean isUsedByOtherApps(String codePath) { - return mCodePathsUsedByOtherApps.containsKey(codePath); + if (mPrimaryCodePaths.containsKey(codePath)) { + Set<String> loadingPackages = mPrimaryCodePaths.get(codePath); + if (loadingPackages.contains(mPackageName)) { + // If the owning package is in the list then this code path + // is used by others if there are other packages in the list. + return loadingPackages.size() > 1; + } else { + // The owning package is not in the loading packages. So if + // the list is non-empty then the code path is used by others. + return !loadingPackages.isEmpty(); + } + } + return false; } public Map<String, DexUseInfo> getDexUseInfoMap() { @@ -778,11 +747,11 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { } public Set<String> getLoadingPackages(String codePath) { - return mCodePathsUsedByOtherApps.getOrDefault(codePath, null); + return mPrimaryCodePaths.getOrDefault(codePath, null); } public boolean isAnyCodePathUsedByOtherApps() { - return !mCodePathsUsedByOtherApps.isEmpty(); + return !mPrimaryCodePaths.isEmpty(); } /** @@ -790,16 +759,16 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { * Returns whether or not there was an update. */ /*package*/ boolean clearCodePathUsedByOtherApps() { - // Update mUsedByOtherAppsBeforeUpgrade as well to be consistent with - // the new data. This is not saved to disk so we don't need to return it. - mUsedByOtherAppsBeforeUpgrade = true; - - if (mCodePathsUsedByOtherApps.isEmpty()) { - return false; - } else { - mCodePathsUsedByOtherApps.clear(); - return true; + boolean updated = false; + List<String> retainOnlyOwningPackage = new ArrayList<>(1); + retainOnlyOwningPackage.add(mPackageName); + for (Map.Entry<String, Set<String>> entry : mPrimaryCodePaths.entrySet()) { + // Remove or loading packages but the owning one. + if (entry.getValue().retainAll(retainOnlyOwningPackage)) { + updated = true; + } } + return updated; } } @@ -847,11 +816,9 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages); String oldClassLoaderContext = mClassLoaderContext; - if (isUnknownOrUnsupportedContext(mClassLoaderContext)) { - // Can happen if we read a previous version. + if (isUnsupportedContext(mClassLoaderContext)) { mClassLoaderContext = dexUseInfo.mClassLoaderContext; - } else if (!isUnknownOrUnsupportedContext(dexUseInfo.mClassLoaderContext) - && !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { + } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) { // We detected a context change. mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT; } @@ -862,11 +829,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { || !Objects.equals(oldClassLoaderContext, mClassLoaderContext); } - private static boolean isUnknownOrUnsupportedContext(String context) { - // TODO: Merge UNKNOWN_CLASS_LOADER_CONTEXT & UNSUPPORTED_CLASS_LOADER_CONTEXT cases - // into UNSUPPORTED_CLASS_LOADER_CONTEXT. - return UNKNOWN_CLASS_LOADER_CONTEXT.equals(context) - || UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context); + private static boolean isUnsupportedContext(String context) { + return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(context); } public boolean isUsedByOtherApps() { @@ -887,10 +851,8 @@ public class PackageDexUsage extends AbstractStatsBase<Void> { public String getClassLoaderContext() { return mClassLoaderContext; } - public boolean isUnknownClassLoaderContext() { - // The class loader context may be unknown if we loaded the data from a previous version - // which didn't save the context. - return isUnknownOrUnsupportedContext(mClassLoaderContext); + public boolean isUnsupportedClassLoaderContext() { + return isUnsupportedContext(mClassLoaderContext); } public boolean isVariableClassLoaderContext() { diff --git a/services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java b/services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java new file mode 100644 index 000000000000..ee3c406fc448 --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdater.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.pm.parsing.library; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +/** + * Updates a package to remove dependency on com.google.android.maps library. + * + * @hide + */ +@VisibleForTesting +public class ComGoogleAndroidMapsUpdater extends PackageSharedLibraryUpdater { + + private static final String LIBRARY_NAME = "com.google.android.maps"; + + @Override + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { + parsedPackage.removeUsesLibrary(LIBRARY_NAME); + parsedPackage.removeUsesOptionalLibrary(LIBRARY_NAME); + } +} diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java index 1d018c485e08..1405a7d613f1 100644 --- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java +++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java @@ -45,6 +45,9 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { static { final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>(); + // Remove com.google.android.maps library. + packageUpdaters.add(new ComGoogleAndroidMapsUpdater()); + // Automatically add the org.apache.http.legacy library to the app classpath if the app // targets < P. packageUpdaters.add(new OrgApacheHttpLegacyUpdater()); diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING index 74958b692eb2..cf1bfc3b555f 100644 --- a/services/core/java/com/android/server/power/TEST_MAPPING +++ b/services/core/java/com/android/server/power/TEST_MAPPING @@ -21,10 +21,7 @@ "options": [ {"include-filter": "com.android.server.power"}, {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, - {"exclude-annotation": "androidx.test.filters.FlakyTest"}, - { - "exclude-filter": "com.android.server.power.PowerManagerServiceTest#testWakefulnessAwake_ShouldWakeUpWhenPluggedIn" - } + {"exclude-annotation": "androidx.test.filters.FlakyTest"} ] } ], diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java index 008933f643dd..da1b7f3113c4 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -114,6 +114,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware DEAD }; + private Boolean mCaptureState; + private final @NonNull ISoundTriggerMiddlewareInternal mDelegate; private final @NonNull Context mContext; private Map<Integer, Set<ModuleService>> mModules; @@ -224,6 +226,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware mDelegate.setCaptureState(active); } catch (Exception e) { throw handleException(e); + } finally { + // It is safe to lock here - local operation. + synchronized (this) { + mCaptureState = active; + } } } @@ -274,8 +281,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware "This implementation is not inteded to be used directly with Binder."); } - @Override public void dump(PrintWriter pw) { + @Override + public void dump(PrintWriter pw) { synchronized (this) { + pw.printf("Capture state is %s\n", mCaptureState == null ? "uninitialized" + : (mCaptureState ? "active" : "inactive")); if (mModules != null) { for (int handle : mModules.keySet()) { pw.println("========================================="); diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 24ab89b027b2..e9da2c4c8472 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -3039,7 +3039,7 @@ public class StatsPullAtomService extends SystemService { e.writeInt(message.getUid()); e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true); e.writeString(message.getPackageName()); - e.writeString(message.getOp()); + e.writeString(""); if (message.getAttributionTag() == null) { e.writeString(""); } else { @@ -3047,6 +3047,7 @@ public class StatsPullAtomService extends SystemService { } e.writeString(message.getMessage()); e.writeInt(message.getSamplingStrategy()); + e.writeInt(AppOpsManager.strOpToOp(message.getOp())); pulledData.add(e.build()); } catch (Throwable t) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index d88dccb9afeb..26497d8b0290 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -131,7 +131,7 @@ public interface StatusBarManagerInternal { * @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence, * IBinder, int, ITransientNotificationCallback) */ - void showToast(String packageName, IBinder token, CharSequence text, + void showToast(int uid, String packageName, IBinder token, CharSequence text, IBinder windowToken, int duration, @Nullable ITransientNotificationCallback textCallback); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 78ef68c09988..d7a0c9871b48 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -502,12 +502,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void showToast(String packageName, IBinder token, CharSequence text, + public void showToast(int uid, String packageName, IBinder token, CharSequence text, IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { if (mBar != null) { try { - mBar.showToast(packageName, token, text, windowToken, duration, callback); + mBar.showToast(uid, packageName, token, text, windowToken, duration, callback); } catch (RemoteException ex) { } } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index ddf166eb0bd5..63952b086c1c 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1904,7 +1904,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub final WallpaperData fallback = new WallpaperData(wallpaper.userId, getWallpaperDir(wallpaper.userId), WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); - ensureSaneWallpaperData(fallback, DEFAULT_DISPLAY); + ensureSaneWallpaperData(fallback); bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply); mWaitingForUnlock = true; } @@ -2425,7 +2425,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (cropHint == null) { cropHint = new Rect(0, 0, 0, 0); } else { - if (cropHint.isEmpty() + if (cropHint.width() < 0 || cropHint.height() < 0 || cropHint.left < 0 || cropHint.top < 0) { throw new IllegalArgumentException("Invalid crop rect supplied: " + cropHint); @@ -3077,7 +3077,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper = new WallpaperData(userId, getWallpaperDir(userId), WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); mLockWallpaperMap.put(userId, wallpaper); - ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY); + ensureSaneWallpaperData(wallpaper); } else { // sanity fallback: we're in bad shape, but establishing a known // valid system+lock WallpaperData will keep us from dying. @@ -3085,7 +3085,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper = new WallpaperData(userId, getWallpaperDir(userId), WALLPAPER, WALLPAPER_CROP); mWallpaperMap.put(userId, wallpaper); - ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY); + ensureSaneWallpaperData(wallpaper); } } } @@ -3196,10 +3196,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } ensureSaneWallpaperDisplaySize(wpdData, DEFAULT_DISPLAY); - ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY); + ensureSaneWallpaperData(wallpaper); WallpaperData lockWallpaper = mLockWallpaperMap.get(userId); if (lockWallpaper != null) { - ensureSaneWallpaperData(lockWallpaper, DEFAULT_DISPLAY); + ensureSaneWallpaperData(lockWallpaper); } } @@ -3215,15 +3215,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private void ensureSaneWallpaperData(WallpaperData wallpaper, int displayId) { - final DisplayData size = getDisplayDataOrCreate(displayId); - - if (displayId == DEFAULT_DISPLAY) { - // crop, if not previously specified - if (wallpaper.cropHint.width() <= 0 - || wallpaper.cropHint.height() <= 0) { - wallpaper.cropHint.set(0, 0, size.mWidth, size.mHeight); - } + private void ensureSaneWallpaperData(WallpaperData wallpaper) { + // Only overwrite cropHint if the rectangle is invalid. + if (wallpaper.cropHint.width() < 0 + || wallpaper.cropHint.height() < 0) { + wallpaper.cropHint.set(0, 0, 0, 0); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c1c844078d6f..5ce63de87ee9 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -196,6 +196,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; import static com.android.server.wm.TaskPersister.DEBUG; import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; @@ -5918,7 +5919,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void prepareSurfaces() { - final boolean show = isVisible() || isAnimating(PARENTS); + final boolean show = isVisible() || isAnimatingExcluding(PARENTS, + ANIMATION_TYPE_SCREEN_ROTATION); if (mSurfaceControl != null) { if (show && !mLastSurfaceShowing) { @@ -7411,7 +7413,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ boolean isResumedActivityOnDisplay() { final DisplayContent display = getDisplay(); - return display != null && this == display.mTaskContainers.getResumedActivity(); + if (display == null) { + return false; + } + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity(); + if (resumedActivity != null) { + return resumedActivity == this; + } + } + return false; } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index a446720c1c39..f5eba96a96d1 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -1119,8 +1119,8 @@ class ActivityStack extends Task { @Override public boolean isAttached() { - final DisplayContent display = getDisplay(); - return display != null && !display.isRemoved(); + final TaskDisplayArea taskDisplayArea = getDisplayArea(); + return taskDisplayArea != null && !taskDisplayArea.isRemoved(); } // TODO: Should each user have there own stacks? diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 8af862473386..02601ff4b6e3 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -385,15 +385,15 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { private final MoveTaskToFullscreenHelper mMoveTaskToFullscreenHelper = new MoveTaskToFullscreenHelper(); private class MoveTaskToFullscreenHelper { - private DisplayContent mToDisplay; + private TaskDisplayArea mToDisplayArea; private boolean mOnTop; private Task mTopTask; private boolean mSchedulePictureInPictureModeChange; - void process(ActivityStack fromStack, DisplayContent toDisplay, boolean onTop, + void process(ActivityStack fromStack, TaskDisplayArea toDisplayArea, boolean onTop, boolean schedulePictureInPictureModeChange) { mSchedulePictureInPictureModeChange = schedulePictureInPictureModeChange; - mToDisplay = toDisplay; + mToDisplayArea = toDisplayArea; mOnTop = onTop; mTopTask = fromStack.getTopMostTask(); @@ -401,7 +401,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { MoveTaskToFullscreenHelper::processLeafTask, this, PooledLambda.__(Task.class)); fromStack.forAllLeafTasks(c, false /* traverseTopToBottom */); c.recycle(); - mToDisplay = null; + mToDisplayArea = null; mTopTask = null; } @@ -411,19 +411,18 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { task.getActivityType())) { final ActivityStack stack = (ActivityStack) task; stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - if (mToDisplay.getDisplayId() != stack.getDisplayId()) { - stack.reparent(mToDisplay.getDefaultTaskDisplayArea(), mOnTop); + if (mToDisplayArea.getDisplayId() != stack.getDisplayId()) { + stack.reparent(mToDisplayArea, mOnTop); } else if (mOnTop) { - mToDisplay.mTaskContainers.positionStackAtTop(stack, - false /* includingParents */); + mToDisplayArea.positionStackAtTop(stack, false /* includingParents */); } else { - mToDisplay.mTaskContainers.positionStackAtBottom(stack); + mToDisplayArea.positionStackAtBottom(stack); } return; } - final ActivityStack toStack = mToDisplay.mTaskContainers.getOrCreateStack( - null, mTmpOptions, task, task.getActivityType(), mOnTop); + final ActivityStack toStack = mToDisplayArea.getOrCreateStack(null, mTmpOptions, task, + task.getActivityType(), mOnTop); if (task == toStack) { // The task was reused as the root task. return; @@ -1418,7 +1417,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mRootWindowContainer.getLaunchStack(null, options, task, ON_TOP); if (stack != currentStack) { - moveHomeStackToFrontIfNeeded(flags, stack.getDisplay(), reason); + moveHomeStackToFrontIfNeeded(flags, stack.getDisplayArea(), reason); task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME, reason); currentStack = stack; @@ -1437,7 +1436,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } if (!reparented) { - moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplay(), reason); + moveHomeStackToFrontIfNeeded(flags, currentStack.getDisplayArea(), reason); } final ActivityRecord r = task.getTopNonFinishingActivity(); @@ -1451,15 +1450,16 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { currentStack, forceNonResizeable); } - private void moveHomeStackToFrontIfNeeded(int flags, DisplayContent display, String reason) { - final ActivityStack focusedStack = display.getFocusedStack(); + private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea, + String reason) { + final ActivityStack focusedStack = taskDisplayArea.getFocusedStack(); - if ((display.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + if ((taskDisplayArea.getWindowingMode() == WINDOWING_MODE_FULLSCREEN && (flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) || (focusedStack != null && focusedStack.isActivityTypeRecents())) { - // We move home stack to front when we are on a fullscreen display and caller has + // We move home stack to front when we are on a fullscreen display area and caller has // requested the home activity to move with it. Or the previous stack is recents. - display.mTaskContainers.moveHomeStackToFront(reason); + taskDisplayArea.moveHomeStackToFront(reason); } } @@ -1511,15 +1511,15 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mService.deferWindowLayout(); try { final int windowingMode = fromStack.getWindowingMode(); - final DisplayContent toDisplay = - mRootWindowContainer.getDisplayContent(toDisplayId); + final TaskDisplayArea toDisplayArea = mRootWindowContainer + .getDisplayContent(toDisplayId).getDefaultTaskDisplayArea(); if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // We are moving all tasks from the docked stack to the fullscreen stack, // which is dismissing the docked stack, so resize all other stacks to // fullscreen here already so we don't end up with resize trashing. - for (int i = toDisplay.getStackCount() - 1; i >= 0; --i) { - final ActivityStack otherStack = toDisplay.getStackAt(i); + for (int i = toDisplayArea.getStackCount() - 1; i >= 0; --i) { + final ActivityStack otherStack = toDisplayArea.getStackAt(i); if (!otherStack.inSplitScreenSecondaryWindowingMode()) { continue; } @@ -1535,7 +1535,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { if (fromStack.hasChild()) { mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); mMoveTaskToFullscreenHelper.process( - fromStack, toDisplay, onTop, schedulePictureInPictureModeChange); + fromStack, toDisplayArea, onTop, schedulePictureInPictureModeChange); } mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); @@ -1546,6 +1546,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } void moveTasksToFullscreenStackLocked(ActivityStack fromStack, boolean onTop) { + // TODO(b/153089193): Support moving within the same task display area mWindowManager.inSurfaceTransaction(() -> moveTasksToFullscreenStackInSurfaceTransaction(fromStack, DEFAULT_DISPLAY, onTop)); } diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 0a0049d1550d..d777f3fee1a2 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -189,9 +189,10 @@ public class ActivityStartController { mSupervisor.beginDeferResume(); final ActivityStack homeStack; try { + // TODO(multi-display-area): Support starting home in a task display area // Make sure home stack exist on display. - homeStack = display.mTaskContainers.getOrCreateStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_HOME, ON_TOP); + homeStack = display.getDefaultTaskDisplayArea().getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); } finally { mSupervisor.endDeferResume(); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 85517a44d656..a93b962c33b4 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2060,20 +2060,53 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * activity type. Null is no compatible stack on the display. */ ActivityStack getStack(int windowingMode, int activityType) { - return mTaskContainers.getStack(windowingMode, activityType); + for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx) + .getStack(windowingMode, activityType); + if (stack != null) { + return stack; + } + } + return null; } - protected int getStackCount() { - return mTaskContainers.mChildren.size(); + protected int getTaskDisplayAreaCount() { + // TODO(multi-display-area): Report actual display area count + return 1; } - protected ActivityStack getStackAt(int index) { - return mTaskContainers.mChildren.get(index); + protected TaskDisplayArea getTaskDisplayAreaAt(int index) { + // TODO(multi-display-area): Report actual display area values + return mTaskContainers; + } + + ActivityStack getStack(int rootTaskId) { + for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final ActivityStack stack = getTaskDisplayAreaAt(tdaNdx).getStack(rootTaskId); + if (stack != null) { + return stack; + } + } + return null; + } + + protected int getStackCount() { + int totalStackCount = 0; + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + totalStackCount += getTaskDisplayAreaAt(i).getStackCount(); + } + return totalStackCount; } @VisibleForTesting ActivityStack getTopStack() { - return mTaskContainers.getTopStack(); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + final ActivityStack stack = getTaskDisplayAreaAt(i).getTopStack(); + if (stack != null) { + return stack; + } + } + return null; } /** @@ -2449,7 +2482,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final PooledConsumer c = PooledLambda.obtainConsumer( DisplayContent::processTaskForTouchExcludeRegion, this, PooledLambda.__(Task.class), focusedTask, delta); - mTaskContainers.forAllTasks(c); + forAllTasks(c); c.recycle(); // If we removed the focused task above, add it back and only leave its @@ -2630,9 +2663,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void prepareFreezingTaskBounds() { - for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mTaskContainers.getChildAt(stackNdx); - stack.prepareFreezingTaskBounds(); + for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + getTaskDisplayAreaAt(tdaNdx).prepareFreezingTaskBounds(); } } @@ -2738,8 +2770,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final ActivityStack focusedStack = getFocusedStack(); if (focusedStack != null) { proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId()); - final ActivityRecord focusedActivity = focusedStack.getDisplay().mTaskContainers - .getResumedActivity(); + final ActivityRecord focusedActivity = focusedStack.getDisplayArea() + .getFocusedActivity(); if (focusedActivity != null) { focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY); } @@ -2797,13 +2829,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (mLastFocus != mCurrentFocus) { pw.print(" mLastFocus="); pw.println(mLastFocus); } - if (mTaskContainers.mPreferredTopFocusableStack != null) { - pw.println(prefix + "mPreferredTopFocusableStack=" - + mTaskContainers.mPreferredTopFocusableStack); - } - if (mTaskContainers.mLastFocusedStack != null) { - pw.println(prefix + "mLastFocusedStack=" + mTaskContainers.mLastFocusedStack); - } if (mLosingFocus.size() > 0) { pw.println(); pw.println(" Windows losing focus:"); @@ -2837,10 +2862,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } pw.println(); - pw.println(prefix + "Application tokens in top down Z order:"); - for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mTaskContainers.getChildAt(stackNdx); - stack.dump(pw, prefix + " ", dumpAll); + pw.println(prefix + "Task display areas in top down Z order:"); + for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + getTaskDisplayAreaAt(tdaNdx).dump(pw, prefix + " ", dumpAll); } pw.println(); @@ -4002,7 +4026,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } // Initialize state of exiting applications. - mTaskContainers.setExitingTokensHasVisible(hasVisible); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + getTaskDisplayAreaAt(i).setExitingTokensHasVisible(hasVisible); + } } void removeExistingTokensIfPossible() { @@ -4014,7 +4040,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } // Time to remove any exiting applications? - mTaskContainers.removeExistingAppTokensIfPossible(); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + getTaskDisplayAreaAt(i).removeExistingAppTokensIfPossible(); + } } @Override @@ -4475,7 +4503,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void assignStackOrdering() { - mTaskContainers.assignStackOrdering(getPendingTransaction()); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + getTaskDisplayAreaAt(i).assignStackOrdering(getPendingTransaction()); + } } /** @@ -5002,13 +5032,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo || windowingMode == WINDOWING_MODE_MULTI_WINDOW); } - ActivityStack createStack(int windowingMode, int activityType, boolean onTop) { - return mTaskContainers.createStack(windowingMode, activityType, onTop, null /* info */, - null /* intent */, false /* createdByOrganizer */); - } - + @Nullable ActivityStack getFocusedStack() { - return mTaskContainers.getFocusedStack(); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + final ActivityStack stack = getTaskDisplayAreaAt(i).getFocusedStack(); + if (stack != null) { + return stack; + } + } + return null; } /** @@ -5016,11 +5048,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED */ void removeStacksInWindowingModes(int... windowingModes) { - mTaskContainers.removeStacksInWindowingModes(windowingModes); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + getTaskDisplayAreaAt(i).removeStacksInWindowingModes(windowingModes); + } } void removeStacksWithActivityTypes(int... activityTypes) { - mTaskContainers.removeStacksWithActivityTypes(activityTypes); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + getTaskDisplayAreaAt(i).removeStacksWithActivityTypes(activityTypes); + } } ActivityRecord topRunningActivity() { @@ -5037,7 +5073,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * @return The top running activity. {@code null} if none is available. */ ActivityRecord topRunningActivity(boolean considerKeyguardState) { - return mTaskContainers.topRunningActivity(considerKeyguardState); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + final ActivityRecord activity = getTaskDisplayAreaAt(i) + .topRunningActivity(considerKeyguardState); + if (activity != null) { + return activity; + } + } + return null; } boolean updateDisplayOverrideConfigurationLocked() { @@ -5149,7 +5192,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // The display may be about to rotate seamlessly, and the animation of closing apps may // still animate in old rotation. So make sure the outdated animation won't show on the // rotated display. - mTaskContainers.forAllActivities(a -> { + forAllActivities(a -> { if (a.nowVisible && a != mFixedRotationLaunchingApp && a.getWindowConfiguration().getRotation() != newRotation) { final WindowContainer<?> w = a.getAnimatingContainer(); @@ -5210,40 +5253,17 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void remove() { mRemoving = true; - final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove(); ActivityStack lastReparentedStack = null; - mTaskContainers.mPreferredTopFocusableStack = null; - - // Stacks could be reparented from the removed display to other display. While - // reparenting the last stack of the removed display, the remove display is ready to be - // released (no more ActivityStack). But, we cannot release it at that moment or the - // related WindowContainer will also be removed. So, we set display as removed after - // reparenting stack finished. - final TaskDisplayArea toTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); + mRootWindowContainer.mStackSupervisor.beginDeferResume(); try { - int numStacks = getStackCount(); - // Keep the order from bottom to top. - for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) { - final ActivityStack stack = getStackAt(stackNdx); - // Always finish non-standard type stacks. - if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) { - stack.finishAllActivitiesImmediately(); - } else { - // If default display is in split-window mode, set windowing mode of the stack - // to split-screen secondary. Otherwise, set the windowing mode to undefined by - // default to let stack inherited the windowing mode from the new display. - final int windowingMode = toTaskDisplayArea.isSplitScreenModeActivated() - ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY - : WINDOWING_MODE_UNDEFINED; - stack.reparent(toTaskDisplayArea, true /* onTop */); - stack.setWindowingMode(windowingMode); - lastReparentedStack = stack; + int numTaskContainers = getTaskDisplayAreaCount(); + for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) { + final ActivityStack lastReparentedStackFromArea = getTaskDisplayAreaAt(tdaNdx) + .remove(); + if (lastReparentedStackFromArea != null) { + lastReparentedStack = lastReparentedStackFromArea; } - // Stacks may be removed from this display. Ensure each stack will be processed and - // the loop will end. - stackNdx -= numStacks - getStackCount(); - numStacks = getStackCount(); } } finally { mRootWindowContainer.mStackSupervisor.endDeferResume(); @@ -5270,12 +5290,27 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return; } - final ActivityStack stack = getStackCount() == 1 ? getStackAt(0) : null; - if (stack != null && stack.isActivityTypeHome() && !stack.hasChild()) { - // Release this display if an empty home stack is the only thing left. - // Since it is the last stack, this display will be released along with the stack - // removal. - stack.removeIfPossible(); + // Check if all task display areas have only the empty home stacks left. + boolean onlyEmptyHomeStacksLeft = true; + for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = getTaskDisplayAreaAt(tdaNdx); + if (taskDisplayArea.getStackCount() != 1) { + onlyEmptyHomeStacksLeft = false; + break; + } + final ActivityStack stack = taskDisplayArea.getStackAt(0); + if (!stack.isActivityTypeHome() || stack.hasChild()) { + onlyEmptyHomeStacksLeft = false; + break; + } + } + if (onlyEmptyHomeStacksLeft) { + // Release this display if only empty home stack(s) are left. This display will be + // released along with the stack(s) removal. + for (int tdaNdx = getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final ActivityStack s = getTaskDisplayAreaAt(tdaNdx).getStackAt(0); + s.removeIfPossible(); + } } else if (getTopStack() == null) { removeIfPossible(); mRootWindowContainer.mStackSupervisor @@ -5334,10 +5369,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void ensureActivitiesVisible(ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients) { - for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = getStackAt(stackNdx); - stack.ensureActivitiesVisible(starting, configChanges, preserveWindows, - notifyClients); + for (int i = getTaskDisplayAreaCount() - 1; i >= 0; --i) { + getTaskDisplayAreaAt(i).ensureActivitiesVisible(starting, configChanges, + preserveWindows, notifyClients); } } @@ -5350,13 +5384,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void setDisplayToSingleTaskInstance() { - final int childCount = getStackCount(); - if (childCount > 1) { + final int taskDisplayAreaCount = getTaskDisplayAreaCount(); + if (taskDisplayAreaCount > 1) { + throw new IllegalArgumentException( + "Display already has multiple task display areas. display=" + this); + } + final int stackCount = getDefaultTaskDisplayArea().getStackCount(); + if (stackCount > 1) { throw new IllegalArgumentException("Display already has multiple stacks. display=" + this); } - if (childCount > 0) { - final ActivityStack stack = getStackAt(0); + if (stackCount > 0) { + final ActivityStack stack = getDefaultTaskDisplayArea().getStackAt(0); if (stack.getChildCount() > 1) { throw new IllegalArgumentException("Display stack already has multiple tasks." + " display=" + this + " stack=" + stack); @@ -5394,6 +5433,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mDisplayPolicy.getSystemUiContext(); } + Point getDisplayPosition() { + return mWmService.mDisplayManagerInternal.getDisplayPosition(getDisplayId()); + } + class RemoteInsetsControlTarget implements InsetsControlTarget { private final IDisplayWindowInsetsController mRemoteInsetsController; diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 264da9fc681b..f088dbcb0174 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -3247,7 +3247,7 @@ public class DisplayPolicy { final int dockedAppearance = updateLightStatusBarAppearanceLw(0 /* vis */, mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState); final boolean inSplitScreen = - mService.mRoot.getDefaultDisplay().mTaskContainers.isSplitScreenModeActivated(); + mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated(); if (inSplitScreen) { mService.getStackBounds(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds); @@ -3879,10 +3879,10 @@ public class DisplayPolicy { WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; - lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; + lp.setFitInsetsTypes(0); lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; if (ActivityManager.isHighEndGfx()) { lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 57a54d0e84ef..f672394251f2 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -529,11 +529,14 @@ class KeyguardController { * occlusion state. */ private ActivityStack getStackForControllingOccluding(DisplayContent display) { - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - if (stack != null && stack.isFocusableAndVisible() - && !stack.inPinnedWindowingMode()) { - return stack; + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (stack != null && stack.isFocusableAndVisible() + && !stack.inPinnedWindowingMode()) { + return stack; + } } } return null; diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 84229f003032..6fda1170a3f5 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -340,7 +340,7 @@ public class RecentsAnimationController implements DeathRecipient { // Make leashes for each of the visible/target tasks and add it to the recents animation to // be started - // TODO(multi-display-area): Support Recents on multiple task display areas + // TODO(b/153090560): Support Recents on multiple task display areas final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea() .getVisibleTasks(); final ActivityStack targetStack = mDisplayContent.getDefaultTaskDisplayArea() diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 2eeda4dcfeed..e1ef76f128cd 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -1643,7 +1643,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> displayId = DEFAULT_DISPLAY; } - final ActivityRecord r = getDisplayContent(displayId).mTaskContainers.getHomeActivity(); + // TODO(multi-display-area): Resume home on the right task container + final ActivityRecord r = getDisplayContent(displayId).getDefaultTaskDisplayArea() + .getHomeActivity(); final String myReason = reason + " resumeHomeActivity"; // Only resume home activity if isn't finishing. @@ -1800,19 +1802,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final ArrayList<IBinder> topActivityTokens = new ArrayList<>(); final ActivityStack topFocusedStack = getTopDisplayFocusedStack(); // Traverse all displays. - for (int i = getChildCount() - 1; i >= 0; i--) { - final DisplayContent display = getChildAt(i); - // Traverse all stacks on a display. - for (int j = display.getStackCount() - 1; j >= 0; --j) { - final ActivityStack stack = display.getStackAt(j); - // Get top activity from a visible stack and add it to the list. - if (stack.shouldBeVisible(null /* starting */)) { - final ActivityRecord top = stack.getTopNonFinishingActivity(); - if (top != null) { - if (stack == topFocusedStack) { - topActivityTokens.add(0, top.appToken); - } else { - topActivityTokens.add(top.appToken); + for (int dNdx = getChildCount() - 1; dNdx >= 0; dNdx--) { + final DisplayContent display = getChildAt(dNdx); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = + display.getTaskDisplayAreaAt(tdaNdx); + // Traverse all stacks on a display area. + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + // Get top activity from a visible stack and add it to the list. + if (stack.shouldBeVisible(null /* starting */)) { + final ActivityRecord top = stack.getTopNonFinishingActivity(); + if (top != null) { + if (stack == topFocusedStack) { + topActivityTokens.add(0, top.appToken); + } else { + topActivityTokens.add(top.appToken); + } } } } @@ -1844,10 +1850,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // focus order. for (int i = getChildCount() - 1; i >= 0; --i) { final DisplayContent display = getChildAt(i); - final ActivityRecord resumedActivityOnDisplay = display.mTaskContainers - .getResumedActivity(); - if (resumedActivityOnDisplay != null) { - return resumedActivityOnDisplay; + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + final ActivityRecord resumedActivityOnTaskContainer = taskDisplayArea + .getFocusedActivity(); + if (resumedActivityOnTaskContainer != null) { + return resumedActivityOnTaskContainer; + } } } return null; @@ -1867,16 +1876,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> WindowProcessController fgApp = null; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - if (isTopDisplayFocusedStack(stack)) { - final ActivityRecord resumedActivity = stack.getResumedActivity(); - if (resumedActivity != null) { - fgApp = resumedActivity.app; - } else if (stack.mPausingActivity != null) { - fgApp = stack.mPausingActivity.app; + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (isTopDisplayFocusedStack(stack)) { + final ActivityRecord resumedActivity = stack.getResumedActivity(); + if (resumedActivity != null) { + fgApp = resumedActivity.app; + } else if (stack.mPausingActivity != null) { + fgApp = stack.mPausingActivity.app; + } + break; } - break; } } } @@ -1992,9 +2004,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mStackSupervisor.mStartingUsers.add(uss); for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - stack.switchUser(userId); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + stack.switchUser(userId); + } } } @@ -2196,13 +2211,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> ActivityStack focusedStack = getTopDisplayFocusedStack(); for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - // It is possible that request to finish activity might also remove its task and stack, - // so we need to be careful with indexes in the loop and check child count every time. - for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - final Task t = stack.finishTopCrashedActivityLocked(app, reason); - if (stack == focusedStack || finishedTask == null) { - finishedTask = t; + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + // It is possible that request to finish activity might also remove its task and + // stack, so we need to be careful with indexes in the loop and check child count + // every time. + for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx); + final Task t = stack.finishTopCrashedActivityLocked(app, reason); + if (stack == focusedStack || finishedTask == null) { + finishedTask = t; + } } } } @@ -2229,26 +2248,29 @@ class RootWindowContainer extends WindowContainer<DisplayContent> for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { boolean resumedOnDisplay = false; final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - final ActivityRecord topRunningActivity = stack.topRunningActivity(); - if (!stack.isFocusableAndVisible() || topRunningActivity == null) { - continue; - } - if (stack == targetStack) { - // Simply update the result for targetStack because the targetStack had - // already resumed in above. We don't want to resume it again, especially in - // some cases, it would cause a second launch failure if app process was dead. - resumedOnDisplay |= result; - continue; - } - if (display.mTaskContainers.isTopStack(stack) - && topRunningActivity.isState(RESUMED)) { - // Kick off any lingering app transitions form the MoveTaskToFront operation, - // but only consider the top task and stack on that display. - stack.executeAppTransition(targetOptions); - } else { - resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final ActivityRecord topRunningActivity = stack.topRunningActivity(); + if (!stack.isFocusableAndVisible() || topRunningActivity == null) { + continue; + } + if (stack == targetStack) { + // Simply update the result for targetStack because the targetStack had + // already resumed in above. We don't want to resume it again, especially in + // some cases, it would cause a second launch failure if app process was + // dead. + resumedOnDisplay |= result; + continue; + } + if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) { + // Kick off any lingering app transitions form the MoveTaskToFront + // operation, but only consider the top task and stack on that display. + stack.executeAppTransition(targetOptions); + } else { + resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target); + } } } if (!resumedOnDisplay) { @@ -2284,32 +2306,37 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } // Set the sleeping state of the stacks on the display. - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - if (displayShouldSleep) { - stack.goToSleepIfPossible(false /* shuttingDown */); - } else { - // When the display which can only contain one task turns on, start a special - // transition. {@link AppTransitionController#handleAppTransitionReady} later - // picks up the transition, and schedules - // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is - // triggered after contents are drawn on the display. - if (display.isSingleTaskInstance()) { - display.mDisplayContent.prepareAppTransition( - TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false); - } - stack.awakeFromSleepingLocked(); - if (display.isSingleTaskInstance()) { - display.executeAppTransition(); - } - if (stack.isFocusedStackOnDisplay() - && !mStackSupervisor.getKeyguardController() - .isKeyguardOrAodShowing(display.mDisplayId)) { - // If the keyguard is unlocked - resume immediately. - // It is possible that the display will not be awake at the time we - // process the keyguard going away, which can happen before the sleep token - // is released. As a result, it is important we resume the activity here. - resumeFocusedStacksTopActivities(); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (displayShouldSleep) { + stack.goToSleepIfPossible(false /* shuttingDown */); + } else { + // When the display which can only contain one task turns on, start a + // special transition. + // {@link AppTransitionController#handleAppTransitionReady} later picks up + // the transition, and schedules + // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is + // triggered after contents are drawn on the display. + if (display.isSingleTaskInstance()) { + display.mDisplayContent.prepareAppTransition( + TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false); + } + stack.awakeFromSleepingLocked(); + if (display.isSingleTaskInstance()) { + display.executeAppTransition(); + } + if (stack.isFocusedStackOnDisplay() + && !mStackSupervisor.getKeyguardController() + .isKeyguardOrAodShowing(display.mDisplayId)) { + // If the keyguard is unlocked - resume immediately. + // It is possible that the display will not be awake at the time we + // process the keyguard going away, which can happen before the sleep + // token is released. As a result, it is important we resume the + // activity here. + resumeFocusedStacksTopActivities(); + } } } } @@ -2318,7 +2345,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> protected ActivityStack getStack(int stackId) { for (int i = getChildCount() - 1; i >= 0; --i) { - final ActivityStack stack = getChildAt(i).mTaskContainers.getStack(stackId); + final ActivityStack stack = getChildAt(i).getStack(stackId); if (stack != null) { return stack; } @@ -2414,9 +2441,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (displayId == INVALID_DISPLAY) { for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - list.add(getStackInfo(stack)); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + list.add(getStackInfo(stack)); + } } } return list; @@ -2425,9 +2455,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (display == null) { return list; } - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - list.add(getStackInfo(stack)); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + list.add(getStackInfo(stack)); + } } return list; } @@ -2646,19 +2679,21 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean allSleep = true; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - // Stacks and activities could be removed while putting activities to sleep if - // the app process was gone. This prevents us getting exception by accessing an - // invalid stack index. - if (stackNdx >= display.getStackCount()) { - continue; - } - - final ActivityStack stack = display.getStackAt(stackNdx); - if (allowDelay) { - allSleep &= stack.goToSleepIfPossible(shuttingDown); - } else { - stack.goToSleep(); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + // Stacks and activities could be removed while putting activities to sleep if + // the app process was gone. This prevents us getting exception by accessing an + // invalid stack index. + if (sNdx >= taskDisplayArea.getStackCount()) { + continue; + } + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (allowDelay) { + allSleep &= stack.goToSleepIfPossible(shuttingDown); + } else { + stack.goToSleep(); + } } } } @@ -2910,14 +2945,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> windowingMode = options != null ? options.getLaunchWindowingMode() : r.getWindowingMode(); } - windowingMode = displayContent.mTaskContainers.validateWindowingMode(windowingMode, r, - candidateTask, r.getActivityType()); // Return the topmost valid stack on the display. - for (int i = displayContent.getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = displayContent.getStackAt(i); - if (isValidLaunchStack(stack, r, windowingMode)) { - return stack; + for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx); + final int validatedWindowingMode = taskDisplayArea + .validateWindowingMode(windowingMode, r, candidateTask, r.getActivityType()); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (isValidLaunchStack(stack, r, validatedWindowingMode)) { + return stack; + } } } @@ -3034,9 +3072,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean hasVisibleActivities = false; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - hasVisibleActivities |= stack.handleAppDied(app); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + hasVisibleActivities |= stack.handleAppDied(app); + } } } return hasVisibleActivities; @@ -3147,10 +3188,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void finishVoiceTask(IVoiceInteractionSession session) { for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - final int numStacks = display.getStackCount(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - stack.finishVoiceTask(session); + int numTaskContainers = display.getTaskDisplayAreaCount(); + for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + final int numStacks = display.getStackCount(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx); + stack.finishVoiceTask(session); + } } } } @@ -3214,14 +3259,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean foundResumed = false; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - final ActivityRecord r = stack.getResumedActivity(); - if (r != null) { - if (!r.nowVisible) { - return false; + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final ActivityRecord r = stack.getResumedActivity(); + if (r != null) { + if (!r.nowVisible) { + return false; + } + foundResumed = true; } - foundResumed = true; } } } @@ -3232,16 +3280,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent> boolean pausing = true; for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - final ActivityRecord r = stack.mPausingActivity; - if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) { - if (DEBUG_STATES) { - Slog.d(TAG_STATES, - "allPausedActivitiesComplete: r=" + r + " state=" + r.getState()); - pausing = false; - } else { - return false; + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + final ActivityRecord r = stack.mPausingActivity; + if (r != null && !r.isState(PAUSED, STOPPED, STOPPING)) { + if (DEBUG_STATES) { + Slog.d(TAG_STATES, "allPausedActivitiesComplete: r=" + r + + " state=" + r.getState()); + pausing = false; + } else { + return false; + } } } } @@ -3297,9 +3348,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void cancelInitializingActivities() { for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - stack.cancelInitializingActivities(); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + taskDisplayArea.getStackAt(sNdx).cancelInitializingActivities(); + } } } } @@ -3402,20 +3455,23 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } if (!sendHint) { // targetActivity != null - // Send power hint when the activity's process is different than the current resumed - // activity on all displays, or if there are no resumed activities in the system. + // Send power hint when the activity's process is different than the current top resumed + // activity on all display areas, or if there are no resumed activities in the system. boolean noResumedActivities = true; boolean allFocusedProcessesDiffer = true; for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) { - final DisplayContent displayContent = getChildAt(displayNdx); - final ActivityRecord resumedActivity = displayContent.mTaskContainers - .getResumedActivity(); - final WindowProcessController resumedActivityProcess = - resumedActivity == null ? null : resumedActivity.app; - - noResumedActivities &= resumedActivityProcess == null; - if (resumedActivityProcess != null) { - allFocusedProcessesDiffer &= !resumedActivityProcess.equals(targetActivity.app); + final DisplayContent dc = getChildAt(displayNdx); + for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); + final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity(); + final WindowProcessController resumedActivityProcess = + resumedActivity == null ? null : resumedActivity.app; + + noResumedActivities &= resumedActivityProcess == null; + if (resumedActivityProcess != null) { + allFocusedProcessesDiffer &= !resumedActivityProcess.equals( + targetActivity.app); + } } } sendHint = noResumedActivities || allFocusedProcessesDiffer; @@ -3462,10 +3518,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> int numDisplays = getChildCount(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { final DisplayContent display = getChildAt(displayNdx); - for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = display.getStackAt(stackNdx); - if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { - activities.addAll(stack.getDumpActivitiesLocked(name)); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) { + activities.addAll(stack.getDumpActivitiesLocked(name)); + } } } } @@ -3505,14 +3564,21 @@ class RootWindowContainer extends WindowContainer<DisplayContent> DisplayContent displayContent = getChildAt(displayNdx); pw.print("Display #"); pw.print(displayContent.mDisplayId); pw.println(" (activities from top to bottom):"); - for (int stackNdx = displayContent.getStackCount() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = displayContent.getStackAt(stackNdx); - pw.println(); - printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep); - needSep = printed; - } - printThisActivity(pw, displayContent.mTaskContainers.getResumedActivity(), dumpPackage, - needSep, " ResumedActivity:"); + for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + pw.println(); + printed = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, needSep); + needSep = printed; + } + } + pw.println(" (resumed activities in task display areas from top to bottom):"); + for (int tdaNdx = displayContent.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = displayContent.getTaskDisplayAreaAt(tdaNdx); + printThisActivity(pw, taskDisplayArea.getFocusedActivity(), dumpPackage, needSep, + " ResumedActivity:"); + } } printed |= dumpHistoryList(fd, pw, mStackSupervisor.mFinishingActivities, " ", diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 6358e4719fde..18e32c0683d6 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -202,6 +202,11 @@ class SurfaceAnimator { return mAnimation != null; } + @AnimationType + int getAnimationType() { + return mAnimationType; + } + /** * @return The current animation spec if we are running an animation, or {@code null} otherwise. */ @@ -453,32 +458,38 @@ class SurfaceAnimator { * Animation for screen rotation. * @hide */ - static final int ANIMATION_TYPE_SCREEN_ROTATION = 2; + static final int ANIMATION_TYPE_SCREEN_ROTATION = 1 << 1; /** * Animation for dimming. * @hide */ - static final int ANIMATION_TYPE_DIMMER = 3; + static final int ANIMATION_TYPE_DIMMER = 1 << 2; /** * Animation for recent apps. * @hide */ - static final int ANIMATION_TYPE_RECENTS = 4; + static final int ANIMATION_TYPE_RECENTS = 1 << 3; /** * Animation for a {@link WindowState} without animating the activity. * @hide */ - static final int ANIMATION_TYPE_WINDOW_ANIMATION = 5; + static final int ANIMATION_TYPE_WINDOW_ANIMATION = 1 << 4; /** * Animation to control insets. This is actually not an animation, but is used to give the * client a leash over the system window causing insets. * @hide */ - static final int ANIMATION_TYPE_INSETS_CONTROL = 6; + static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5; + + /** + * Bitmask to include all animation types. This is NOT an {@link AnimationType} + * @hide + */ + static final int ANIMATION_TYPE_ALL = -1; /** * The type of the animation. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 28998dadd072..cb897db9a2d0 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4132,17 +4132,6 @@ class Task extends WindowContainer<WindowContainer> { // Let the old organizer know it has lost control. sendTaskVanished(); mTaskOrganizer = organizer; - - // If the task is not yet visible when it is added to the task organizer, then we should - // hide it to allow the task organizer to show it when it is properly reparented. We skip - // this for tasks created by the organizer because they can synchronously update the leash - // before new children are added to the task. - if (!mCreatedByOrganizer && organizer != null - && (!getHasBeenVisible() || !hasVisibleChildren())) { - getPendingTransaction().hide(getSurfaceControl()); - commitPendingTransaction(); - } - sendTaskAppeared(); onTaskOrganizerChanged(); return true; diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 13e4d8b038b1..1bc7244996ab 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -63,6 +63,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.protolog.common.ProtoLog; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -134,6 +135,12 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { */ private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>(); + /** + * The task display area is removed from the system and we are just waiting for all activities + * on it to be finished before removing this object. + */ + private boolean mRemoved; + TaskDisplayArea(DisplayContent displayContent, WindowManagerService service) { super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER); mDisplayContent = displayContent; @@ -755,7 +762,11 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { */ ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop, Intent intent, Task candidateTask) { - if (!alwaysCreateStack(windowingMode, activityType)) { + // Need to pass in a determined windowing mode to see if a new stack should be created, + // so use its parent's windowing mode if it is undefined. + if (!alwaysCreateStack( + windowingMode != WINDOWING_MODE_UNDEFINED ? windowingMode : getWindowingMode(), + activityType)) { ActivityStack stack = getStack(windowingMode, activityType); if (stack != null) { return stack; @@ -986,7 +997,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { return candidate; } - ActivityRecord getResumedActivity() { + ActivityRecord getFocusedActivity() { final ActivityStack focusedStack = getFocusedStack(); if (focusedStack == null) { return null; @@ -1572,7 +1583,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } boolean isRemoved() { - return mDisplayContent.isRemoved(); + return mRemoved; } /** @@ -1609,4 +1620,82 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { interface OnStackOrderChangedListener { void onStackOrderChanged(ActivityStack stack); } + + void ensureActivitiesVisible(ActivityRecord starting, int configChanges, + boolean preserveWindows, boolean notifyClients) { + for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = getStackAt(stackNdx); + stack.ensureActivitiesVisible(starting, configChanges, preserveWindows, + notifyClients); + } + } + + void prepareFreezingTaskBounds() { + for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = getChildAt(stackNdx); + stack.prepareFreezingTaskBounds(); + } + } + + /** + * Removes the stacks in the node applying the content removal node from the display. + * @return last reparented stack, or {@code null} if the stacks had to be destroyed. + */ + ActivityStack remove() { + mPreferredTopFocusableStack = null; + // TODO(b/153090332): Allow setting content removal mode per task display area + final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove(); + final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); + ActivityStack lastReparentedStack = null; + + // Stacks could be reparented from the removed display area to other display area. After + // reparenting the last stack of the removed display area, the display area becomes ready to + // be released (no more ActivityStack-s). But, we cannot release it at that moment or the + // related WindowContainer will also be removed. So, we set display area as removed after + // reparenting stack finished. + // Keep the order from bottom to top. + int numStacks = getStackCount(); + for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) { + final ActivityStack stack = getStackAt(stackNdx); + // Always finish non-standard type stacks. + if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) { + stack.finishAllActivitiesImmediately(); + } else { + // If default display is in split-window mode, set windowing mode of the + // stack to split-screen secondary. Otherwise, set the windowing mode to + // undefined by default to let stack inherited the windowing mode from the + // new display. + final int windowingMode = toDisplayArea.isSplitScreenModeActivated() + ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY + : WINDOWING_MODE_UNDEFINED; + stack.reparent(toDisplayArea, true /* onTop */); + stack.setWindowingMode(windowingMode); + lastReparentedStack = stack; + } + // Stacks may be removed from this display. Ensure each stack will be processed + // and the loop will end. + stackNdx -= numStacks - getStackCount(); + numStacks = getStackCount(); + } + mRemoved = true; + + return lastReparentedStack; + } + + + @Override + void dump(PrintWriter pw, String prefix, boolean dumpAll) { + pw.println(prefix + "TaskDisplayArea " + getName()); + if (mPreferredTopFocusableStack != null) { + pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); + } + if (mLastFocusedStack != null) { + pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack); + } + pw.println(prefix + " Application tokens in top down Z order:"); + for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = getChildAt(stackNdx); + stack.dump(pw, prefix + " ", dumpAll); + } + } } diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index e6757e145f2f..da4401a68e7c 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -705,14 +705,19 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { private void adjustBoundsToAvoidConflictInDisplay(@NonNull DisplayContent display, @NonNull Rect inOutBounds) { final List<Rect> taskBoundsToCheck = new ArrayList<>(); - for (int i = 0; i < display.getStackCount(); ++i) { - final ActivityStack stack = display.getStackAt(i); - if (!stack.inFreeformWindowingMode()) { - continue; - } + int numTaskContainers = display.getTaskDisplayAreaCount(); + for (int tdaNdx = 0; tdaNdx < numTaskContainers; tdaNdx++) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + int numStacks = taskDisplayArea.getStackCount(); + for (int sNdx = 0; sNdx < numStacks; ++sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (!stack.inFreeformWindowingMode()) { + continue; + } - for (int j = 0; j < stack.getChildCount(); ++j) { - taskBoundsToCheck.add(stack.getChildAt(j).getBounds()); + for (int j = 0; j < stack.getChildCount(); ++j) { + taskBoundsToCheck.add(stack.getChildAt(j).getBounds()); + } } } adjustBoundsToAvoidConflict(display.getBounds(), taskBoundsToCheck, inOutBounds); diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 30fa0529597c..2bbf8dbb274c 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -25,7 +25,6 @@ import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFI import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS; import android.annotation.Nullable; -import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration; import android.content.Intent; @@ -39,7 +38,6 @@ import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; import android.window.WindowContainerToken; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.io.PrintWriter; @@ -48,7 +46,6 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.WeakHashMap; -import java.util.function.Consumer; /** * Stores the TaskOrganizers associated with a given windowing mode and @@ -84,95 +81,17 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } } } - } - - /** - * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right - * lifecycle order since we may be updating the visibility of task surface controls in a pending - * transaction before they are presented to the task org. - */ - private class TaskOrganizerCallbacks { - final WindowManagerService mService; - final ITaskOrganizer mTaskOrganizer; - final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; - - TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg, - Consumer<Runnable> deferTaskOrgCallbacksConsumer) { - mService = wm; - mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer; - mTaskOrganizer = taskOrg; - } - - IBinder getBinder() { - return mTaskOrganizer.asBinder(); - } - - void onTaskAppeared(Task task) { - final RunningTaskInfo taskInfo = task.getTaskInfo(); - mDeferTaskOrgCallbacksConsumer.accept(() -> { - try { - mTaskOrganizer.onTaskAppeared(taskInfo); - } catch (RemoteException e) { - Slog.e(TAG, "Exception sending onTaskAppeared callback", e); - } - }); - } - - - void onTaskVanished(Task task) { - final RunningTaskInfo taskInfo = task.getTaskInfo(); - mDeferTaskOrgCallbacksConsumer.accept(() -> { - try { - mTaskOrganizer.onTaskVanished(taskInfo); - } catch (RemoteException e) { - Slog.e(TAG, "Exception sending onTaskVanished callback", e); - } - }); - } - - void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) { - mDeferTaskOrgCallbacksConsumer.accept(() -> { - if (!task.isOrganized()) { - // This is safe to ignore if the task is no longer organized - return; - } - try { - mTaskOrganizer.onTaskInfoChanged(taskInfo); - } catch (RemoteException e) { - Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e); - } - }); - } - - void onBackPressedOnTaskRoot(Task task) { - mDeferTaskOrgCallbacksConsumer.accept(() -> { - if (!task.isOrganized()) { - // This is safe to ignore if the task is no longer organized - return; - } - try { - mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo()); - } catch (Exception e) { - Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e); - } - }); - } - } + }; private class TaskOrganizerState { - private final TaskOrganizerCallbacks mOrganizer; + private final ITaskOrganizer mOrganizer; private final DeathRecipient mDeathRecipient; private final ArrayList<Task> mOrganizedTasks = new ArrayList<>(); private final int mUid; private boolean mInterceptBackPressedOnTaskRoot; TaskOrganizerState(ITaskOrganizer organizer, int uid) { - final Consumer<Runnable> deferTaskOrgCallbacksConsumer = - mDeferTaskOrgCallbacksConsumer != null - ? mDeferTaskOrgCallbacksConsumer - : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable; - mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer, - deferTaskOrgCallbacksConsumer); + mOrganizer = organizer; mDeathRecipient = new DeathRecipient(organizer); try { organizer.asBinder().linkToDeath(mDeathRecipient, 0); @@ -188,18 +107,26 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { void addTask(Task t) { mOrganizedTasks.add(t); - mOrganizer.onTaskAppeared(t); + try { + mOrganizer.onTaskAppeared(t.getTaskInfo()); + } catch (Exception e) { + Slog.e(TAG, "Exception sending taskAppeared callback" + e); + } } void removeTask(Task t) { + try { + mOrganizer.onTaskVanished(t.getTaskInfo()); + } catch (Exception e) { + Slog.e(TAG, "Exception sending taskVanished callback" + e); + } mOrganizedTasks.remove(t); - mOrganizer.onTaskVanished(t); } void dispose() { releaseTasks(); for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) { - mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder()); + mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.asBinder()); } } @@ -212,7 +139,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } void unlinkDeath() { - mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0); + mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0); } } @@ -222,10 +149,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>(); private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>(); - private final ActivityTaskManagerService mService; + final ActivityTaskManagerService mService; - private RunningTaskInfo mTmpTaskInfo; - private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer; + RunningTaskInfo mTmpTaskInfo; TaskOrganizerController(ActivityTaskManagerService atm) { mService = atm; @@ -237,15 +163,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { } /** - * Specifies the consumer to run to defer the task org callbacks. Can be overridden while - * testing to allow the callbacks to be sent synchronously. - */ - @VisibleForTesting - public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) { - mDeferTaskOrgCallbacksConsumer = consumer; - } - - /** * Register a TaskOrganizer to manage tasks as they enter the given windowing mode. * If there was already a TaskOrganizer for this windowing mode it will be evicted * but will continue to organize it's existing tasks. @@ -336,7 +253,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { if (state == null) { return null; } - return state.mOrganizer.mTaskOrganizer; + return state.mOrganizer; } void onTaskAppeared(ITaskOrganizer organizer, Task task) { @@ -441,10 +358,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { // change. mTmpTaskInfo = null; - if (task.isOrganized()) { - final TaskOrganizerState state = mTaskOrganizerStates.get( - task.mTaskOrganizer.asBinder()); - state.mOrganizer.onTaskInfoChanged(task, newInfo); + if (task.mTaskOrganizer != null) { + try { + task.mTaskOrganizer.onTaskInfoChanged(newInfo); + } catch (RemoteException e) { + } } } @@ -477,26 +395,27 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final long origId = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { - TaskDisplayArea taskDisplayArea = - mService.mRootWindowContainer.getDisplayContent(displayId).mTaskContainers; - if (taskDisplayArea == null) { + TaskDisplayArea defaultTaskDisplayArea = mService.mRootWindowContainer + .getDisplayContent(displayId).getDefaultTaskDisplayArea(); + if (defaultTaskDisplayArea == null) { return; } Task task = token == null ? null : WindowContainer.fromBinder(token.asBinder()).asTask(); if (task == null) { - taskDisplayArea.mLaunchRootTask = null; + defaultTaskDisplayArea.mLaunchRootTask = null; return; } if (!task.mCreatedByOrganizer) { throw new IllegalArgumentException("Attempt to set task not created by " + "organizer as launch root task=" + task); } - if (task.getDisplayArea() != taskDisplayArea) { + if (task.getDisplayArea() == null + || task.getDisplayArea().getDisplayId() != displayId) { throw new RuntimeException("Can't set launch root for display " + displayId + " to task on display " + task.getDisplayContent().getDisplayId()); } - taskDisplayArea.mLaunchRootTask = task; + task.getDisplayArea().mLaunchRootTask = task; } } finally { Binder.restoreCallingIdentity(origId); @@ -557,13 +476,16 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { throw new IllegalArgumentException("Display " + displayId + " doesn't exist"); } ArrayList<RunningTaskInfo> out = new ArrayList<>(); - for (int i = dc.getStackCount() - 1; i >= 0; --i) { - final Task task = dc.getStackAt(i); - if (activityTypes != null - && !ArrayUtils.contains(activityTypes, task.getActivityType())) { - continue; + for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final Task task = taskDisplayArea.getStackAt(sNdx); + if (activityTypes != null + && !ArrayUtils.contains(activityTypes, task.getActivityType())) { + continue; + } + out.add(task.getTaskInfo()); } - out.add(task.getTaskInfo()); } return out; } @@ -599,7 +521,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { return false; } - state.mOrganizer.onBackPressedOnTaskRoot(task); + try { + state.mOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo()); + } catch (Exception e) { + Slog.e(TAG, "Exception sending interceptBackPressedOnTaskRoot callback" + e); + } return true; } @@ -616,7 +542,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j)); final ArrayList<Task> tasks = state.mOrganizedTasks; pw.print(innerPrefix + " "); - pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":"); + pw.println(state.mOrganizer + " uid=" + state.mUid + ":"); for (int k = 0; k < tasks.size(); k++) { pw.println(innerPrefix + " " + tasks.get(k)); } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 037b9c830a50..569b8f61c4f4 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -36,6 +36,7 @@ import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; @@ -790,7 +791,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * By default this predicate only checks if this container itself is actually running an * animation, but you can extend the check target over its relatives, or relax the condition * so that this can return {@code true} if an animation starts soon by giving a combination - * of {@link #AnimationFlags}. + * of {@link AnimationFlags}. * * Note that you can give a combination of bitmask flags to specify targets and condition for * checking animating status. @@ -800,12 +801,18 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< * * Note that TRANSITION propagates to parents and children as well. * - * {@see AnimationFlags#TRANSITION} - * {@see AnimationFlags#PARENTS} - * {@see AnimationFlags#CHILDREN} + * @param flags The combination of bitmask flags to specify targets and condition for + * checking animating status. + * @param typesToCheck The combination of bitmask {@link AnimationType} to compare when + * determining if animating. + * + * @see AnimationFlags#TRANSITION + * @see AnimationFlags#PARENTS + * @see AnimationFlags#CHILDREN */ - boolean isAnimating(int flags) { - if (mSurfaceAnimator.isAnimating()) { + boolean isAnimating(int flags, int typesToCheck) { + int animationType = mSurfaceAnimator.getAnimationType(); + if (mSurfaceAnimator.isAnimating() && (animationType & typesToCheck) > 0) { return true; } if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) { @@ -813,14 +820,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } if ((flags & PARENTS) != 0) { final WindowContainer parent = getParent(); - if (parent != null && parent.isAnimating(flags & ~CHILDREN)) { + if (parent != null && parent.isAnimating(flags & ~CHILDREN, typesToCheck)) { return true; } } if ((flags & CHILDREN) != 0) { for (int i = 0; i < mChildren.size(); ++i) { final WindowContainer wc = mChildren.get(i); - if (wc.isAnimating(flags & ~PARENTS)) { + if (wc.isAnimating(flags & ~PARENTS, typesToCheck)) { return true; } } @@ -829,6 +836,26 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** + * Similar to {@link #isAnimating(int, int)} except provide a bitmask of + * {@link AnimationType} to exclude, rather than include + * @param flags The combination of bitmask flags to specify targets and condition for + * checking animating status. + * @param typesToExclude The combination of bitmask {@link AnimationType} to exclude when + * checking if animating. + */ + boolean isAnimatingExcluding(int flags, int typesToExclude) { + return isAnimating(flags, ANIMATION_TYPE_ALL & ~typesToExclude); + } + + /** + * @see #isAnimating(int, int) + * TODO (b/152333373): Migrate calls to use isAnimating with specified animation type + */ + boolean isAnimating(int flags) { + return isAnimating(flags, ANIMATION_TYPE_ALL); + } + + /** * @return {@code true} when the container is waiting the app transition start, {@code false} * otherwise. */ @@ -2180,11 +2207,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction) { - if (isOrganized()) { - // Defer to the task organizer to run animations - return null; - } - final DisplayContent displayContent = getDisplayContent(); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); final int width = displayInfo.appWidth; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 687af64e9d4f..a1e0eb730ff7 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -5317,7 +5317,8 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalArgumentException( "Requested window " + client + " does not exist"); } - ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3)); + ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session, + Debug.getCallers(3)); return null; } if (session != null && win.mSession != session) { @@ -5325,7 +5326,8 @@ public class WindowManagerService extends IWindowManager.Stub throw new IllegalArgumentException("Requested window " + client + " is in session " + win.mSession + ", not " + session); } - ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3)); + ProtoLog.w(WM_ERROR, "Failed looking up window session=%s callers=%s", session, + Debug.getCallers(3)); return null; } @@ -6049,11 +6051,21 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mHasPermanentDpad="); pw.println(mHasPermanentDpad); mRoot.dumpTopFocusedDisplayId(pw); mRoot.forAllDisplays(dc -> { + final int displayId = dc.getDisplayId(); final WindowState inputMethodTarget = dc.mInputMethodTarget; if (inputMethodTarget != null) { - pw.print(" mInputMethodTarget in display# "); pw.print(dc.getDisplayId()); + pw.print(" mInputMethodTarget in display# "); pw.print(displayId); pw.print(' '); pw.println(inputMethodTarget); } + if (mAccessibilityController != null) { + final Region magnificationRegion = new Region(); + mAccessibilityController.getMagnificationRegionLocked(displayId, + magnificationRegion); + pw.print(" mMagnificationRegion in display# "); + pw.print(displayId); + pw.print(' '); + pw.println(magnificationRegion); + } }); pw.print(" mInTouchMode="); pw.println(mInTouchMode); pw.print(" mLastDisplayFreezeDuration="); @@ -7318,7 +7330,7 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean isStackVisibleLw(int windowingMode) { - // TODO(multi-display-area): Support multiple task display areas & displays + // TODO(b/153090332): Support multiple task display areas & displays final TaskDisplayArea tc = mRoot.getDefaultTaskDisplayArea(); return tc.isStackVisible(windowingMode); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 8e7585ae4bfa..3ebc0f410fd7 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3439,13 +3439,23 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP getMergedConfiguration(mLastReportedConfiguration); mLastConfigReportedToClient = true; + final boolean reportOrientation = mReportOrientationChanged; + // Always reset these states first, so if {@link IWindow#resized} fails, this + // window won't be added to {@link WindowManagerService#mResizingWindows} and set + // {@link #mOrientationChanging} to true again by {@link #updateResizingWindowIfNeeded} + // that may cause WINDOW_FREEZE_TIMEOUT because resizing the client keeps failing. + mReportOrientationChanged = false; + mDragResizingChangeReported = true; + mWinAnimator.mSurfaceResized = false; + mWindowFrames.resetInsetsChanged(); + final Rect frame = mWindowFrames.mCompatFrame; final Rect contentInsets = mWindowFrames.mLastContentInsets; final Rect visibleInsets = mWindowFrames.mLastVisibleInsets; final Rect stableInsets = mWindowFrames.mLastStableInsets; final MergedConfiguration mergedConfiguration = mLastReportedConfiguration; final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING; - final boolean forceRelayout = mReportOrientationChanged || isDragResizeChanged(); + final boolean forceRelayout = reportOrientation || isDragResizeChanged(); final int displayId = getDisplayId(); final DisplayCutout displayCutout = getWmDisplayCutout().getDisplayCutout(); @@ -3454,25 +3464,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mergedConfiguration, getBackdropFrame(frame), forceRelayout, getDisplayContent().getDisplayPolicy().areSystemBarsForcedShownLw(this), displayId, new DisplayCutout.ParcelableWrapper(displayCutout)); - mDragResizingChangeReported = true; if (mWmService.mAccessibilityController != null) { mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(displayId); } updateLocationInParentDisplayIfNeeded(); - - mWindowFrames.resetInsetsChanged(); - mWinAnimator.mSurfaceResized = false; - mReportOrientationChanged = false; } catch (RemoteException e) { + // Cancel orientation change of this window to avoid blocking unfreeze display. setOrientationChanging(false); mLastFreezeDuration = (int)(SystemClock.elapsedRealtime() - mWmService.mDisplayFreezeTime); - // We are assuming the hosting process is dead or in a zombie state. - Slog.w(TAG, "Failed to report 'resized' to the client of " + this - + ", removing this window."); - mWmService.mPendingRemove.add(this); - mWmService.mWindowPlacerLocked.requestTraversal(); + Slog.w(TAG, "Failed to report 'resized' to " + this + " due to " + e); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } @@ -4982,7 +4984,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override - boolean isAnimating(int flags) { + boolean isAnimating(int flags, int typesToCheck) { // If we are an inset provider, all our animations are driven by the inset client, so we // aren't really animating. @@ -4990,7 +4992,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (mControllableInsetProvider != null) { return false; } - return super.isAnimating(flags); + return super.isAnimating(flags, typesToCheck); } void startAnimation(Animation anim) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index eed39e182a33..d1c47d9feed7 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -87,6 +87,9 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; +import static android.os.UserManagerInternal.OWNER_TYPE_DEVICE_OWNER; +import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER; +import static android.os.UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; import static android.provider.Telephony.Carriers.DPC_URI; @@ -284,6 +287,7 @@ import com.android.server.SystemService; import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; +import com.android.server.pm.RestrictionsSet; import com.android.server.pm.UserRestrictionsUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.storage.DeviceStorageMonitorInternal; @@ -322,6 +326,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; +import java.util.function.Predicate; /** * Implementation of the device policy APIs. @@ -1828,6 +1833,50 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { info = deviceAdminInfo; } + Bundle addSyntheticRestrictions(Bundle restrictions) { + if (disableCamera) { + restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); + } else { + restrictions.remove(UserManager.DISALLOW_CAMERA); + } + return restrictions; + } + + static Bundle removeDeprecatedRestrictions(Bundle restrictions) { + for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) { + restrictions.remove(deprecatedRestriction); + } + return restrictions; + } + + static Bundle filterRestrictions(Bundle restrictions, Predicate<String> filter) { + Bundle result = new Bundle(); + for (String key : restrictions.keySet()) { + if (!restrictions.getBoolean(key)) { + continue; + } + if (filter.test(key)) { + result.putBoolean(key, true); + } + } + return result; + } + + Bundle getEffectiveRestrictions() { + return addSyntheticRestrictions( + removeDeprecatedRestrictions(ensureUserRestrictions())); + } + + Bundle getLocalUserRestrictions(int adminType) { + return filterRestrictions(getEffectiveRestrictions(), + key -> UserRestrictionsUtils.isLocal(adminType, key)); + } + + Bundle getGlobalUserRestrictions(int adminType) { + return filterRestrictions(getEffectiveRestrictions(), + key -> UserRestrictionsUtils.isGlobal(adminType, key)); + } + void dump(IndentingPrintWriter pw) { pw.print("uid="); pw.println(getUid()); pw.print("testOnlyAdmin="); @@ -2772,7 +2821,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId) != 0) { profileOwner.ensureUserRestrictions().putBoolean( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); - saveUserRestrictionsLocked(userId, /* parent = */ false); + saveUserRestrictionsLocked(userId); mInjector.settingsSecurePutIntForUser( Settings.Secure.UNKNOWN_SOURCES_DEFAULT_REVERSED, 0, userId); } @@ -2803,7 +2852,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } admin.defaultEnabledRestrictionsAlreadySet.addAll(restrictionsToSet); Slog.i(LOG_TAG, "Enabled the following restrictions by default: " + restrictionsToSet); - saveUserRestrictionsLocked(userId, /* parent = */ false); + saveUserRestrictionsLocked(userId); } } @@ -8222,9 +8271,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } // Tell the user manager that the restrictions have changed. - final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle; - pushUserRestrictions(affectedUserId); + pushUserRestrictions(userHandle); + final int affectedUserId = parent ? getProfileParentId(userHandle) : userHandle; if (SecurityLog.isLoggingEnabled()) { SecurityLog.writeEvent(SecurityLog.TAG_CAMERA_POLICY_SET, who.getPackageName(), userHandle, affectedUserId, disabled ? 1 : 0); @@ -10806,10 +10855,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { "Cannot use the parent instance in Device Owner mode"); } } else { - if (!(UserRestrictionsUtils.canProfileOwnerChange(key, userHandle) || ( - isProfileOwnerOfOrganizationOwnedDevice(activeAdmin) && parent - && UserRestrictionsUtils.canProfileOwnerOfOrganizationOwnedDeviceChange( - key)))) { + boolean profileOwnerCanChangeOnItself = !parent + && UserRestrictionsUtils.canProfileOwnerChange(key, userHandle); + boolean orgOwnedProfileOwnerCanChangesGlobally = parent + && isProfileOwnerOfOrganizationOwnedDevice(activeAdmin) + && UserRestrictionsUtils + .canProfileOwnerOfOrganizationOwnedDeviceChange(key); + + if (!profileOwnerCanChangeOnItself && !orgOwnedProfileOwnerCanChangesGlobally) { throw new SecurityException("Profile owner cannot set user restriction " + key); } } @@ -10821,7 +10874,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else { restrictions.remove(key); } - saveUserRestrictionsLocked(userHandle, parent); + saveUserRestrictionsLocked(userHandle); } final int eventId = enabledFromThisOwner ? DevicePolicyEnums.ADD_USER_RESTRICTION @@ -10839,91 +10892,65 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void saveUserRestrictionsLocked(int userId, boolean parent) { + private void saveUserRestrictionsLocked(int userId) { saveSettingsLocked(userId); - pushUserRestrictions(parent ? getProfileParentId(userId) : userId); + pushUserRestrictions(userId); sendChangedNotification(userId); } - private void pushUserRestrictions(int userId) { + /** + * Pushes the user restrictions originating from a specific user. + * + * If called by the profile owner of an organization-owned device, the global and local + * user restrictions will be an accumulation of the global user restrictions from the profile + * owner active admin and its parent active admin. The key of the local user restrictions set + * will be the target user id. + */ + private void pushUserRestrictions(int originatingUserId) { + final Bundle global; + final RestrictionsSet local = new RestrictionsSet(); + final boolean isDeviceOwner; synchronized (getLockObject()) { - final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId); - Bundle userRestrictions = null; - final int restrictionOwnerType; - final int originatingUserId; - + isDeviceOwner = mOwners.isDeviceOwnerUserId(originatingUserId); if (isDeviceOwner) { final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); if (deviceOwner == null) { return; // Shouldn't happen. } - userRestrictions = addOrRemoveDisableCameraRestriction( - deviceOwner.userRestrictions, deviceOwner); - restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER; - originatingUserId = deviceOwner.getUserHandle().getIdentifier(); + global = deviceOwner.getGlobalUserRestrictions(OWNER_TYPE_DEVICE_OWNER); + local.updateRestrictions(originatingUserId, deviceOwner.getLocalUserRestrictions( + OWNER_TYPE_DEVICE_OWNER)); } else { - final ActiveAdmin profileOwnerOfOrganizationOwnedDevice = - getProfileOwnerOfOrganizationOwnedDeviceLocked(userId); - - // If profile owner of an organization owned device, the restrictions will be - // pushed to the parent instance. - if (profileOwnerOfOrganizationOwnedDevice != null && !isManagedProfile(userId)) { - restrictionOwnerType = - UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE; - final ActiveAdmin parent = profileOwnerOfOrganizationOwnedDevice - .getParentActiveAdmin(); - userRestrictions = parent.userRestrictions; - userRestrictions = addOrRemoveDisableCameraRestriction(userRestrictions, - parent); - originatingUserId = - profileOwnerOfOrganizationOwnedDevice.getUserHandle().getIdentifier(); - } else { - final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); - - if (profileOwner != null) { - userRestrictions = profileOwner.userRestrictions; - restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER; - originatingUserId = profileOwner.getUserHandle().getIdentifier(); - } else { - restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER; - originatingUserId = userId; - } - userRestrictions = addOrRemoveDisableCameraRestriction( - userRestrictions, userId); + final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(originatingUserId); + if (profileOwner == null) { + return; } - } - // Remove deprecated restrictions. - for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) { - userRestrictions.remove(deprecatedRestriction); - } - mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId, - userRestrictions, restrictionOwnerType); - } - } - - private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) { - if (userRestrictions == null) { - userRestrictions = new Bundle(); - } - if (admin.disableCamera) { - userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); - } else { - userRestrictions.remove(UserManager.DISALLOW_CAMERA); - } - return userRestrictions; - } - - private Bundle addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) { - if (userRestrictions == null) { - userRestrictions = new Bundle(); - } - if (getCameraDisabled(/* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ - false)) { - userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); - } else { - userRestrictions.remove(UserManager.DISALLOW_CAMERA); - } - return userRestrictions; + global = profileOwner.getGlobalUserRestrictions(OWNER_TYPE_PROFILE_OWNER); + local.updateRestrictions(originatingUserId, profileOwner.getLocalUserRestrictions( + OWNER_TYPE_PROFILE_OWNER)); + // Global (device-wide) and local user restrictions set by the profile owner of an + // organization-owned device are stored in the parent ActiveAdmin instance. + if (isProfileOwnerOfOrganizationOwnedDevice( + profileOwner.getUserHandle().getIdentifier())) { + // The global restrictions set on the parent ActiveAdmin instance need to be + // merged with the global restrictions set on the profile owner ActiveAdmin + // instance, since both are to be applied device-wide. + UserRestrictionsUtils.merge(global, + profileOwner.getParentActiveAdmin().getGlobalUserRestrictions( + OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); + // The local restrictions set on the parent ActiveAdmin instance are only to be + // applied to the primary user. They therefore need to be added the local + // restriction set with the primary user id as the key, in this case the + // primary user id is the target user. + local.updateRestrictions( + getProfileParentId(profileOwner.getUserHandle().getIdentifier()), + profileOwner.getParentActiveAdmin().getLocalUserRestrictions( + OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); + } + } + } + mUserManagerInternal.setDevicePolicyUserRestrictions(originatingUserId, global, local, + isDeviceOwner); } @Override diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp index 02bb0bc3e49c..b13d33054e19 100644 --- a/services/incremental/Android.bp +++ b/services/incremental/Android.bp @@ -50,7 +50,6 @@ cc_defaults { "libbinder", "libcrypto", "libcutils", - "libdataloader", "libincfs", "liblog", "libz", diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 0da167303ccd..d36eae89c1ff 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "IncrementalService" #include "IncrementalService.h" -#include "IncrementalServiceValidation.h" #include <android-base/file.h> #include <android-base/logging.h> @@ -582,25 +581,29 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog return -EINVAL; } - ifs->dataLoaderFilesystemParams.readLogsEnabled = enableReadLogs; if (enableReadLogs) { - // We never unregister the callbacks, but given a restricted number of data loaders and even fewer asking for read log access, should be ok. - registerAppOpsCallback(ifs->dataLoaderParams.packageName); + if (auto status = + mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage, + ifs->dataLoaderParams.packageName.c_str()); + !status.isOk()) { + LOG(ERROR) << "checkPermission failed: " << status.toString8(); + return fromBinderStatus(status); + } } - return applyStorageParams(*ifs); -} + if (auto status = applyStorageParams(*ifs, enableReadLogs); !status.isOk()) { + LOG(ERROR) << "applyStorageParams failed: " << status.toString8(); + return fromBinderStatus(status); + } -int IncrementalService::applyStorageParams(IncFsMount& ifs) { - const bool enableReadLogs = ifs.dataLoaderFilesystemParams.readLogsEnabled; if (enableReadLogs) { - if (auto status = CheckPermissionForDataDelivery(kDataUsageStats, kOpUsage); - !status.isOk()) { - LOG(ERROR) << "CheckPermissionForDataDelivery failed: " << status.toString8(); - return fromBinderStatus(status); - } + registerAppOpsCallback(ifs->dataLoaderParams.packageName); } + return 0; +} + +binder::Status IncrementalService::applyStorageParams(IncFsMount& ifs, bool enableReadLogs) { using unique_fd = ::android::base::unique_fd; ::android::os::incremental::IncrementalFileSystemControlParcel control; control.cmd.reset(unique_fd(dup(ifs.control.cmd()))); @@ -611,13 +614,7 @@ int IncrementalService::applyStorageParams(IncFsMount& ifs) { } std::lock_guard l(mMountOperationLock); - const auto status = mVold->setIncFsMountOptions(control, enableReadLogs); - if (!status.isOk()) { - LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8(); - return fromBinderStatus(status); - } - - return 0; + return mVold->setIncFsMountOptions(control, enableReadLogs); } void IncrementalService::deleteStorage(StorageId storageId) { @@ -1280,39 +1277,54 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ } void IncrementalService::registerAppOpsCallback(const std::string& packageName) { - if (packageName.empty()) { - return; - } - + sp<IAppOpsCallback> listener; { std::unique_lock lock{mCallbacksLock}; - if (!mCallbackRegistered.insert(packageName).second) { + auto& cb = mCallbackRegistered[packageName]; + if (cb) { return; } + cb = new AppOpsListener(*this, packageName); + listener = cb; } - /* TODO(b/152633648): restore callback after it's not crashing Binder anymore. - sp<AppOpsListener> listener = new AppOpsListener(*this, packageName); mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener); - */ } -void IncrementalService::onAppOppChanged(const std::string& packageName) { +bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) { + sp<IAppOpsCallback> listener; + { + std::unique_lock lock{mCallbacksLock}; + auto found = mCallbackRegistered.find(packageName); + if (found == mCallbackRegistered.end()) { + return false; + } + listener = found->second; + mCallbackRegistered.erase(found); + } + + mAppOpsManager->stopWatchingMode(listener); + return true; +} + +void IncrementalService::onAppOpChanged(const std::string& packageName) { + if (!unregisterAppOpsCallback(packageName)) { + return; + } + std::vector<IfsMountPtr> affected; { std::lock_guard l(mLock); affected.reserve(mMounts.size()); for (auto&& [id, ifs] : mMounts) { - if (ifs->dataLoaderFilesystemParams.readLogsEnabled && ifs->dataLoaderParams.packageName == packageName) { + if (ifs->mountId == id && ifs->dataLoaderParams.packageName == packageName) { affected.push_back(ifs); } } } - /* TODO(b/152633648): restore callback after it's not crashing Kernel anymore. for (auto&& ifs : affected) { - applyStorageParams(*ifs); + applyStorageParams(*ifs, false); } - */ } binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, @@ -1378,8 +1390,8 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange return binder::Status::ok(); } -void IncrementalService::AppOpsListener::opChanged(int32_t op, const String16&) { - incrementalService.onAppOppChanged(packageName); +void IncrementalService::AppOpsListener::opChanged(int32_t, const String16&) { + incrementalService.onAppOpChanged(packageName); } } // namespace android::incremental diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index ff69633e185b..58002974e180 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -40,7 +40,6 @@ #include "ServiceWrappers.h" #include "android/content/pm/BnDataLoaderStatusListener.h" #include "incfs.h" -#include "dataloader_ndk.h" #include "path.h" using namespace android::os::incremental; @@ -182,7 +181,6 @@ private: StorageMap storages; BindMap bindPoints; DataLoaderParamsParcel dataLoaderParams; - DataLoaderFilesystemParams dataLoaderFilesystemParams; std::atomic<int> nextStorageDirNo{0}; std::atomic<int> dataLoaderStatus = -1; bool dataLoaderStartRequested = false; @@ -193,9 +191,7 @@ private: : root(std::move(root)), control(std::move(control)), mountId(mountId), - incrementalService(incrementalService) { - dataLoaderFilesystemParams.readLogsEnabled = false; - } + incrementalService(incrementalService) {} IncFsMount(IncFsMount&&) = delete; IncFsMount& operator=(IncFsMount&&) = delete; ~IncFsMount(); @@ -234,10 +230,11 @@ private: std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage, std::string_view path); - int applyStorageParams(IncFsMount& ifs); + binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs); void registerAppOpsCallback(const std::string& packageName); - void onAppOppChanged(const std::string& packageName); + bool unregisterAppOpsCallback(const std::string& packageName); + void onAppOpChanged(const std::string& packageName); // Member variables std::unique_ptr<VoldServiceWrapper> const mVold; @@ -252,7 +249,7 @@ private: BindPathMap mBindsByPath; std::mutex mCallbacksLock; - std::set<std::string> mCallbackRegistered; + std::map<std::string, sp<AppOpsListener>> mCallbackRegistered; std::atomic_bool mSystemReady = false; StorageId mNextId = 0; diff --git a/services/incremental/IncrementalServiceValidation.h b/services/incremental/IncrementalServiceValidation.h index 24f9f7f94dfd..48894c6926c8 100644 --- a/services/incremental/IncrementalServiceValidation.h +++ b/services/incremental/IncrementalServiceValidation.h @@ -41,7 +41,8 @@ inline int fromBinderStatus(const binder::Status& status) { : -EIO; } -inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation) { +inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation, + const char* package) { using android::base::StringPrintf; int32_t pid; @@ -52,23 +53,23 @@ inline binder::Status CheckPermissionForDataDelivery(const char* permission, con StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission)); } + String16 packageName{package}; + // Caller must also have op granted. PermissionController pc; - // Package is a required parameter. Need to obtain one. - Vector<String16> packages; - pc.getPackagesForUid(uid, packages); - if (packages.empty()) { + if (auto packageUid = pc.getPackageUid(packageName, 0); packageUid != uid) { return Exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d / PID %d has no packages", uid, pid)); + StringPrintf("UID %d / PID %d does not own package %s", uid, pid, + package)); } - switch (auto result = pc.noteOp(String16(operation), uid, packages[0]); result) { + switch (auto result = pc.noteOp(String16(operation), uid, packageName); result) { case PermissionController::MODE_ALLOWED: case PermissionController::MODE_DEFAULT: return binder::Status::ok(); default: return Exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d / PID %d lacks app-op %s, error %d", uid, pid, - operation, result)); + StringPrintf("UID %d / PID %d / package %s lacks app-op %s, error %d", + uid, pid, package, operation, result)); } } diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index 449b457045c6..84bf1ffaf45c 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -16,6 +16,8 @@ #pragma once +#include "IncrementalServiceValidation.h" + #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <android/content/pm/DataLoaderParamsParcel.h> @@ -85,7 +87,10 @@ public: class AppOpsManagerWrapper { public: virtual ~AppOpsManagerWrapper() = default; + virtual binder::Status checkPermission(const char* permission, const char* operation, + const char* package) const = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0; + virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; }; class ServiceManagerWrapper { @@ -105,17 +110,19 @@ public: ~RealVoldService() = default; binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir, int32_t flags, - IncrementalFileSystemControlParcel* _aidl_return) const override { + IncrementalFileSystemControlParcel* _aidl_return) const final { return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return); } - binder::Status unmountIncFs(const std::string& dir) const override { + binder::Status unmountIncFs(const std::string& dir) const final { return mInterface->unmountIncFs(dir); } binder::Status bindMount(const std::string& sourceDir, - const std::string& targetDir) const override { + const std::string& targetDir) const final { return mInterface->bindMount(sourceDir, targetDir); } - binder::Status setIncFsMountOptions(const ::android::os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs) const override { + binder::Status setIncFsMountOptions( + const ::android::os::incremental::IncrementalFileSystemControlParcel& control, + bool enableReadLogs) const final { return mInterface->setIncFsMountOptions(control, enableReadLogs); } @@ -131,13 +138,13 @@ public: binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, const sp<IDataLoaderStatusListener>& listener, - bool* _aidl_return) const override { + bool* _aidl_return) const final { return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return); } - binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const override { + binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final { return mInterface->getDataLoader(mountId, _aidl_return); } - binder::Status destroyDataLoader(MountId mountId) const override { + binder::Status destroyDataLoader(MountId mountId) const final { return mInterface->destroyDataLoader(mountId); } @@ -148,9 +155,18 @@ private: class RealAppOpsManager : public AppOpsManagerWrapper { public: ~RealAppOpsManager() = default; - void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) override { + binder::Status checkPermission(const char* permission, const char* operation, + const char* package) const final { + return android::incremental::CheckPermissionForDataDelivery(permission, operation, package); + } + void startWatchingMode(int32_t op, const String16& packageName, + const sp<IAppOpsCallback>& callback) final { mAppOpsManager.startWatchingMode(op, packageName, callback); } + void stopWatchingMode(const sp<IAppOpsCallback>& callback) final { + mAppOpsManager.stopWatchingMode(callback); + } + private: android::AppOpsManager mAppOpsManager; }; @@ -174,36 +190,35 @@ class RealIncFs : public IncFsWrapper { public: RealIncFs() = default; ~RealIncFs() = default; - Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const override { + Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final { return incfs::createControl(cmd, pendingReads, logs); } ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id, - NewFileParams params) const override { + NewFileParams params) const final { return incfs::makeFile(control, path, mode, id, params); } - ErrorCode makeDir(const Control& control, std::string_view path, int mode) const override { + ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final { return incfs::makeDir(control, path, mode); } - RawMetadata getMetadata(const Control& control, FileId fileid) const override { + RawMetadata getMetadata(const Control& control, FileId fileid) const final { return incfs::getMetadata(control, fileid); } - RawMetadata getMetadata(const Control& control, std::string_view path) const override { + RawMetadata getMetadata(const Control& control, std::string_view path) const final { return incfs::getMetadata(control, path); } - FileId getFileId(const Control& control, std::string_view path) const override { + FileId getFileId(const Control& control, std::string_view path) const final { return incfs::getFileId(control, path); } - ErrorCode link(const Control& control, std::string_view from, - std::string_view to) const override { + ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final { return incfs::link(control, from, to); } - ErrorCode unlink(const Control& control, std::string_view path) const override { + ErrorCode unlink(const Control& control, std::string_view path) const final { return incfs::unlink(control, path); } - base::unique_fd openForSpecialOps(const Control& control, FileId id) const override { + base::unique_fd openForSpecialOps(const Control& control, FileId id) const final { return base::unique_fd{incfs::openForSpecialOps(control, id).release()}; } - ErrorCode writeBlocks(Span<const DataBlock> blocks) const override { + ErrorCode writeBlocks(Span<const DataBlock> blocks) const final { return incfs::writeBlocks(blocks); } }; diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 5553f688060a..0635ae169281 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -221,7 +221,28 @@ public: }; class MockAppOpsManager : public AppOpsManagerWrapper { +public: + MOCK_CONST_METHOD3(checkPermission, binder::Status(const char*, const char*, const char*)); MOCK_METHOD3(startWatchingMode, void(int32_t, const String16&, const sp<IAppOpsCallback>&)); + MOCK_METHOD1(stopWatchingMode, void(const sp<IAppOpsCallback>&)); + + void checkPermissionSuccess() { + ON_CALL(*this, checkPermission(_, _, _)).WillByDefault(Return(android::incremental::Ok())); + } + void checkPermissionFails() { + ON_CALL(*this, checkPermission(_, _, _)) + .WillByDefault( + Return(android::incremental::Exception(binder::Status::EX_SECURITY, {}))); + } + void initializeStartWatchingMode() { + ON_CALL(*this, startWatchingMode(_, _, _)) + .WillByDefault(Invoke(this, &MockAppOpsManager::storeCallback)); + } + void storeCallback(int32_t, const String16&, const sp<IAppOpsCallback>& cb) { + mStoredCallback = cb; + } + + sp<IAppOpsCallback> mStoredCallback; }; class MockServiceManager : public ServiceManagerWrapper { @@ -418,9 +439,15 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { mVold->setIncFsMountOptionsSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); + mAppOpsManager->checkPermissionSuccess(); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); - EXPECT_CALL(*mVold, setIncFsMountOptions(_, _)); + // We are calling setIncFsMountOptions(true). + EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1); + // After setIncFsMountOptions succeeded expecting to start watching. + EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1); + // Not expecting callback removal. + EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0); TemporaryDir tempDir; int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, @@ -429,6 +456,56 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { ASSERT_GE(mIncrementalService->setStorageParams(storageId, true), 0); } +TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) { + mVold->mountIncFsSuccess(); + mIncFs->makeFileSuccess(); + mVold->bindMountSuccess(); + mVold->setIncFsMountOptionsSuccess(); + mDataLoaderManager->initializeDataLoaderSuccess(); + mDataLoaderManager->getDataLoaderSuccess(); + mAppOpsManager->checkPermissionSuccess(); + mAppOpsManager->initializeStartWatchingMode(); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); + // We are calling setIncFsMountOptions(true). + EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1); + // setIncFsMountOptions(false) is called on the callback. + EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1); + // After setIncFsMountOptions succeeded expecting to start watching. + EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1); + // After callback is called, disable read logs and remove callback. + EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(1); + TemporaryDir tempDir; + int storageId = + mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, + IncrementalService::CreateOptions::CreateNew); + ASSERT_GE(storageId, 0); + ASSERT_GE(mIncrementalService->setStorageParams(storageId, true), 0); + ASSERT_NE(nullptr, mAppOpsManager->mStoredCallback.get()); + mAppOpsManager->mStoredCallback->opChanged(0, {}); +} + +TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) { + mVold->mountIncFsSuccess(); + mIncFs->makeFileSuccess(); + mVold->bindMountSuccess(); + mDataLoaderManager->initializeDataLoaderSuccess(); + mDataLoaderManager->getDataLoaderSuccess(); + mAppOpsManager->checkPermissionFails(); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); + // checkPermission fails, no calls to set opitions, start or stop WatchingMode. + EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(0); + EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0); + EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0); + TemporaryDir tempDir; + int storageId = + mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, + IncrementalService::CreateOptions::CreateNew); + ASSERT_GE(storageId, 0); + ASSERT_LT(mIncrementalService->setStorageParams(storageId, true), 0); +} + TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) { mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); @@ -436,9 +513,14 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) { mVold->setIncFsMountOptionsFails(); mDataLoaderManager->initializeDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); + mAppOpsManager->checkPermissionSuccess(); EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); - EXPECT_CALL(*mVold, setIncFsMountOptions(_, _)); + // We are calling setIncFsMountOptions. + EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1); + // setIncFsMountOptions fails, no calls to start or stop WatchingMode. + EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0); + EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0); TemporaryDir tempDir; int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java index 7bf1d98d9a3f..0445bff8fd0d 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -16,7 +16,10 @@ package com.android.server.accessibility; +import static android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY; +import static android.accessibilityservice.AccessibilityService.ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS; import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_HOME; +import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_STATUS; import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION; import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES; import static android.accessibilityservice.AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; @@ -69,6 +72,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.graphics.Region; +import android.hardware.display.DisplayManager; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -93,6 +97,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -162,6 +167,7 @@ public class AbstractAccessibilityServiceConnectionTest { @Mock private IAccessibilityInteractionConnectionCallback mMockCallback; @Mock private FingerprintGestureDispatcher mMockFingerprintGestureDispatcher; @Mock private MagnificationController mMockMagnificationController; + @Mock private RemoteCallback.OnResultListener mMockListener; @Before public void setup() { @@ -705,6 +711,38 @@ public class AbstractAccessibilityServiceConnectionTest { })); } + @Test + public void takeScreenshot_NoA11yAccess_returnErrorCode() throws InterruptedException { + // no checkAccessibilityAccess, should return error code. + when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(true); + when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); + + mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY, + new RemoteCallback(mMockListener)); + mHandler.sendLastMessage(); + + verify(mMockListener).onResult(Mockito.argThat( + bundle -> ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS + == bundle.getInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS))); + } + + @Test + public void takeScreenshot_invalidDisplay_returnErrorCode() throws InterruptedException { + when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(true); + when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(true); + + final DisplayManager displayManager = new DisplayManager(mMockContext); + when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(displayManager); + + mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY + 1, + new RemoteCallback(mMockListener)); + mHandler.sendLastMessage(); + + verify(mMockListener).onResult(Mockito.argThat( + bundle -> ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY + == bundle.getInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS))); + } + private void updateServiceInfo(AccessibilityServiceInfo serviceInfo, int eventType, int feedbackType, int flags, String[] packageNames, int notificationTimeout) { serviceInfo.eventTypes = eventType; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index fe47cea6b693..d780370b9849 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -83,7 +83,6 @@ import android.os.Bundle; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; -import android.os.UserManagerInternal; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.security.KeyChain; @@ -1170,7 +1169,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { () -> dpm.clearDeviceOwnerApp(admin1.getPackageName())); when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true); - reset(getServices().userManagerInternal); dpm.clearDeviceOwnerApp(admin1.getPackageName()); // Now DO shouldn't be set. @@ -1181,9 +1179,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( - eq(UserHandle.USER_SYSTEM), - MockUtils.checkUserRestrictions(), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true)); verify(getServices().usageStatsManagerInternal).setActiveAdminApps( null, UserHandle.USER_SYSTEM); @@ -1745,15 +1742,16 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true)); reset(getServices().userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS, - UserManager.DISALLOW_ADD_USER), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER), + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM, + UserManager.DISALLOW_OUTGOING_CALLS), + eq(true)); reset(getServices().userManagerInternal); DpmTestUtils.assertRestrictions( @@ -1770,8 +1768,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM, + UserManager.DISALLOW_OUTGOING_CALLS), + eq(true)); reset(getServices().userManagerInternal); DpmTestUtils.assertRestrictions( @@ -1787,7 +1787,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true)); reset(getServices().userManagerInternal); assertNoDeviceOwnerRestrictions(); @@ -1801,7 +1801,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME, UserManager.DISALLOW_UNMUTE_MICROPHONE), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true)); reset(getServices().userManagerInternal); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME); @@ -1813,7 +1813,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true)); reset(getServices().userManagerInternal); dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN); @@ -1821,7 +1821,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN, UserManager.DISALLOW_ADD_USER), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true)); reset(getServices().userManagerInternal); dpm.setCameraDisabled(admin1, true); @@ -1830,7 +1830,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { // DISALLOW_CAMERA will be applied globally. MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN, UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_CAMERA), - eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)); + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true)); reset(getServices().userManagerInternal); } @@ -1887,17 +1887,19 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER)); - reset(getServices().userManagerInternal); + MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE, + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES), + eq(false)); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE, + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserManager.DISALLOW_OUTGOING_CALLS), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER)); - reset(getServices().userManagerInternal); + eq(false)); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( @@ -1918,9 +1920,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER)); - reset(getServices().userManagerInternal); + MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE, + UserManager.DISALLOW_OUTGOING_CALLS), + eq(false)); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions( @@ -1940,8 +1943,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER)); - reset(getServices().userManagerInternal); + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE), eq(false)); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), @@ -1956,21 +1958,25 @@ public class DevicePolicyManagerTest extends DpmTestBase { // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE can be set by PO too, even // though when DO sets them they'll be applied globally. dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME); - reset(getServices().userManagerInternal); + dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME, + MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE, + UserManager.DISALLOW_ADJUST_VOLUME, UserManager.DISALLOW_UNMUTE_MICROPHONE), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER)); - reset(getServices().userManagerInternal); + eq(false)); dpm.setCameraDisabled(admin1, true); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME, - UserManager.DISALLOW_UNMUTE_MICROPHONE, UserManager.DISALLOW_CAMERA), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER)); + MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE, + UserManager.DISALLOW_ADJUST_VOLUME, + UserManager.DISALLOW_UNMUTE_MICROPHONE, + UserManager.DISALLOW_CAMERA), + eq(false)); reset(getServices().userManagerInternal); // TODO Make sure restrictions are written to the file. @@ -2004,15 +2010,14 @@ public class DevicePolicyManagerTest extends DpmTestBase { ); public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception { - final int MANAGED_PROFILE_USER_ID = DpmMockContext.CALLER_USER_HANDLE; final int MANAGED_PROFILE_ADMIN_UID = - UserHandle.getUid(MANAGED_PROFILE_USER_ID, DpmMockContext.SYSTEM_UID); + UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE); - when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID)) + when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE)) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); for (String restriction : PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS) { @@ -2021,16 +2026,20 @@ public class DevicePolicyManagerTest extends DpmTestBase { parentDpm.setCameraDisabled(admin1, true); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( - eq(MANAGED_PROFILE_USER_ID), + eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); - reset(getServices().userManagerInternal); + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE), + eq(false)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(UserManager.DISALLOW_CAMERA), + parentDpm.getUserRestrictions(admin1) + ); parentDpm.setCameraDisabled(admin1, false); - verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( - eq(MANAGED_PROFILE_USER_ID), - MockUtils.checkUserRestrictions(), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + parentDpm.getUserRestrictions(admin1) + ); reset(getServices().userManagerInternal); } @@ -2039,13 +2048,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(DpmMockContext.CALLER_USER_HANDLE), MockUtils.checkUserRestrictions(restriction), - eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)); + MockUtils.checkUserRestrictions(DpmMockContext.CALLER_USER_HANDLE), + eq(false)); parentDpm.clearUserRestriction(admin1, restriction); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(), parentDpm.getUserRestrictions(admin1) ); - reset(getServices().userManagerInternal); } public void testNoDefaultEnabledUserRestrictions() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java index 09a681913e45..15f3ed1be552 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java @@ -15,10 +15,6 @@ */ package com.android.server.devicepolicy; -import com.google.common.base.Objects; - -import com.android.server.pm.UserRestrictionsUtils; - import android.content.ComponentName; import android.content.Intent; import android.os.BaseBundle; @@ -26,6 +22,11 @@ import android.os.Bundle; import android.os.UserHandle; import android.util.ArraySet; +import com.android.server.pm.RestrictionsSet; +import com.android.server.pm.UserRestrictionsUtils; + +import com.google.common.base.Objects; + import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; @@ -106,11 +107,14 @@ public class MockUtils { } public static Bundle checkUserRestrictions(String... keys) { - final Bundle expected = DpmTestUtils.newRestrictions(java.util.Objects.requireNonNull(keys)); + final Bundle expected = DpmTestUtils.newRestrictions( + java.util.Objects.requireNonNull(keys)); final Matcher<Bundle> m = new BaseMatcher<Bundle>() { @Override public boolean matches(Object item) { - if (item == null) return false; + if (item == null) { + return false; + } return UserRestrictionsUtils.areEqual((Bundle) item, expected); } @@ -122,6 +126,26 @@ public class MockUtils { return MockitoHamcrest.argThat(m); } + public static RestrictionsSet checkUserRestrictions(int userId, String... keys) { + final RestrictionsSet expected = DpmTestUtils.newRestrictions(userId, + java.util.Objects.requireNonNull(keys)); + final Matcher<RestrictionsSet> m = new BaseMatcher<RestrictionsSet>() { + @Override + public boolean matches(Object item) { + if (item == null) return false; + RestrictionsSet actual = (RestrictionsSet) item; + return UserRestrictionsUtils.areEqual(expected.getRestrictions(userId), + actual.getRestrictions(userId)); + } + + @Override + public void describeTo(Description description) { + description.appendText("User restrictions=" + getRestrictionsAsString(expected)); + } + }; + return MockitoHamcrest.argThat(m); + } + public static Set<String> checkApps(String... adminApps) { final Matcher<Set<String>> m = new BaseMatcher<Set<String>>() { @Override @@ -146,6 +170,23 @@ public class MockUtils { return MockitoHamcrest.argThat(m); } + private static String getRestrictionsAsString(RestrictionsSet r) { + final StringBuilder sb = new StringBuilder(); + sb.append("{"); + + if (r != null) { + String sep = ""; + for (int i = 0; i < r.size(); i++) { + sb.append(sep); + sep = ","; + sb.append( + String.format("%s= %s", r.keyAt(i), getRestrictionsAsString(r.valueAt(i)))); + } + } + sb.append("}"); + return sb.toString(); + } + private static String getRestrictionsAsString(Bundle b) { final StringBuilder sb = new StringBuilder(); sb.append("["); diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java index 234c987bd3d6..7b3417a67857 100644 --- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -60,6 +60,7 @@ public class AutomaticBrightnessControllerTest { @Mock HysteresisLevels mAmbientBrightnessThresholds; @Mock HysteresisLevels mScreenBrightnessThresholds; @Mock Handler mNoopHandler; + @Mock DisplayDeviceConfig mDisplayDeviceConfig; private static final int LIGHT_SENSOR_WARMUP_TIME = 0; @Before @@ -82,7 +83,8 @@ public class AutomaticBrightnessControllerTest { BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE, INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG, DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, - mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mContext); + mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mContext, + mDisplayDeviceConfig); controller.setLoggingEnabled(true); // Configure the brightness controller and grab an instance of the sensor listener, diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java new file mode 100644 index 000000000000..301a9fe64d5e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.graphics.Point; +import android.view.DisplayInfo; +import android.view.Surface; +import android.view.SurfaceControl; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; + +public class LogicalDisplayTest { + private static final int DISPLAY_ID = 0; + private static final int LAYER_STACK = 0; + private static final int DISPLAY_WIDTH = 100; + private static final int DISPLAY_HEIGHT = 200; + + private LogicalDisplay mLogicalDisplay; + private DisplayDevice mDisplayDevice; + + @Before + public void setUp() { + // Share classloader to allow package private access. + System.setProperty("dexmaker.share_classloader", "true"); + mDisplayDevice = mock(DisplayDevice.class); + DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo(); + displayDeviceInfo.width = DISPLAY_WIDTH; + displayDeviceInfo.height = DISPLAY_HEIGHT; + displayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; + mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice); + when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(displayDeviceInfo); + + ArrayList<DisplayDevice> displayDevices = new ArrayList<>(); + displayDevices.add(mDisplayDevice); + mLogicalDisplay.updateLocked(displayDevices); + } + + @Test + public void testGetDisplayPosition() { + Point expectedPosition = new Point(); + + SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); + + expectedPosition.set(20, 40); + mLogicalDisplay.setDisplayOffsetsLocked(20, 40); + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); + + expectedPosition.set(40, -20); + DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.logicalWidth = DISPLAY_HEIGHT; + displayInfo.logicalHeight = DISPLAY_WIDTH; + displayInfo.rotation = Surface.ROTATION_90; + mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo); + mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false); + assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 5109de501157..b60e99363706 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -17,7 +17,9 @@ package com.android.server.pm; -import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -48,7 +50,6 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.pm.parsing.pkg.PackageImpl; import com.android.server.pm.parsing.pkg.ParsedPackage; -import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,7 +59,7 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.security.cert.CertificateException; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -650,32 +651,32 @@ public class AppsFilterTest { final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1; final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2; PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId); - PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("some.system.pkg"), + PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"), seesNothingAppId); PackageSetting hasProvider = simulateAddPackage(appsFilter, - pkgWithProvider("com.some.package", "com.some.authority"), hasProviderAppId); + pkgWithProvider("com.some.other.package", "com.some.authority"), hasProviderAppId); PackageSetting queriesProvider = simulateAddPackage(appsFilter, - pkgQueriesProvider("com.some.other.package", "com.some.authority"), + pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"), queriesProviderAppId); final int[] systemFilter = appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0); - assertThat(Arrays.asList(systemFilter), arrayContaining(systemAppId)); + assertThat(toList(systemFilter), empty()); final int[] seesNothingFilter = appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0); - assertThat(Arrays.asList(seesNothingFilter), - arrayContaining(systemAppId, seesNothingAppId)); + assertThat(toList(seesNothingFilter), + contains(seesNothingAppId)); final int[] hasProviderFilter = appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0); - assertThat(Arrays.asList(hasProviderFilter), - arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId)); + assertThat(toList(hasProviderFilter), + contains(hasProviderAppId, queriesProviderAppId)); int[] queriesProviderFilter = appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); - assertThat(Arrays.asList(queriesProviderFilter), - arrayContaining(systemAppId, queriesProviderAppId)); + assertThat(toList(queriesProviderFilter), + contains(queriesProviderAppId)); // provider read appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId); @@ -683,11 +684,16 @@ public class AppsFilterTest { // ensure implicit access is included in the filter queriesProviderFilter = appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); - assertThat(Arrays.asList(queriesProviderFilter), - arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId)); + assertThat(toList(queriesProviderFilter), + contains(hasProviderAppId, queriesProviderAppId)); } - private void assertThat(List<int[]> asList, Matcher<Integer[]> arrayContainingInAnyOrder) { + private List<Integer> toList(int[] array) { + ArrayList<Integer> ret = new ArrayList<>(array.length); + for (int i = 0; i < array.length; i++) { + ret.add(i, array[i]); + } + return ret; } private interface WithSettingBuilder { diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java index 1c2313e3e32f..dc181a959d83 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java @@ -22,7 +22,6 @@ import static com.android.server.devicepolicy.DpmTestUtils.newRestrictions; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; -import android.os.UserManagerInternal; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import android.util.SparseArray; @@ -118,135 +117,6 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase { UserManager.DISALLOW_ADJUST_VOLUME, user)); } - public void testSortToGlobalAndLocal() { - final Bundle local = new Bundle(); - final Bundle global = new Bundle(); - - UserRestrictionsUtils.sortToGlobalAndLocal(null, - UserManagerInternal.OWNER_TYPE_PROFILE_OWNER, - global, local); - assertEquals(0, global.size()); - assertEquals(0, local.size()); - - UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, - UserManagerInternal.OWNER_TYPE_PROFILE_OWNER, - global, local); - assertEquals(0, global.size()); - assertEquals(0, local.size()); - - // Restrictions set by DO. - UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions( - UserManager.DISALLOW_ADJUST_VOLUME, - UserManager.DISALLOW_UNMUTE_MICROPHONE, - UserManager.DISALLOW_USB_FILE_TRANSFER, - UserManager.DISALLOW_CONFIG_TETHERING, - UserManager.DISALLOW_OUTGOING_BEAM, - UserManager.DISALLOW_APPS_CONTROL, - UserManager.ENSURE_VERIFY_APPS, - UserManager.DISALLOW_CAMERA - ), UserManagerInternal.OWNER_TYPE_DEVICE_OWNER, - global, local); - - - assertRestrictions(newRestrictions( - // This one is global no matter who sets it. - UserManager.ENSURE_VERIFY_APPS, - - // These can be set by PO too, but when DO sets them, they're global. - UserManager.DISALLOW_ADJUST_VOLUME, - UserManager.DISALLOW_UNMUTE_MICROPHONE, - - // These can only be set by DO. - UserManager.DISALLOW_USB_FILE_TRANSFER, - UserManager.DISALLOW_CONFIG_TETHERING, - - // This can be set by DO or PO of organisation owned device - UserManager.DISALLOW_CAMERA - ), global); - - assertRestrictions(newRestrictions( - // They can be set by both DO/PO. - UserManager.DISALLOW_OUTGOING_BEAM, - UserManager.DISALLOW_APPS_CONTROL - ), local); - - local.clear(); - global.clear(); - - // Restrictions set by PO. - UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions( - UserManager.DISALLOW_ADJUST_VOLUME, - UserManager.DISALLOW_UNMUTE_MICROPHONE, - UserManager.DISALLOW_USB_FILE_TRANSFER, - UserManager.DISALLOW_CONFIG_TETHERING, - UserManager.DISALLOW_OUTGOING_BEAM, - UserManager.DISALLOW_APPS_CONTROL, - UserManager.ENSURE_VERIFY_APPS, - UserManager.DISALLOW_CAMERA - ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER, - global, local); - - assertRestrictions(newRestrictions( - // This one is global no matter who sets it. - UserManager.ENSURE_VERIFY_APPS - ), global); - - assertRestrictions(newRestrictions( - // These can be set by PO too, but when PO sets them, they're local. - UserManager.DISALLOW_ADJUST_VOLUME, - UserManager.DISALLOW_UNMUTE_MICROPHONE, - - // They can be set by both DO/PO. - UserManager.DISALLOW_OUTGOING_BEAM, - UserManager.DISALLOW_APPS_CONTROL, - - // These can only be set by DO. - UserManager.DISALLOW_USB_FILE_TRANSFER, - UserManager.DISALLOW_CONFIG_TETHERING, - - // This can be set by DO or PO of organisation owned device - UserManager.DISALLOW_CAMERA - ), local); - - local.clear(); - global.clear(); - - // Restrictions set by PO of organisation owned device - UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions( - UserManager.DISALLOW_CONFIG_DATE_TIME - ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE, - global, local); - - assertRestrictions(newRestrictions( - // This user restriction is global when set by PO of org owned device - UserManager.DISALLOW_CONFIG_DATE_TIME - ), global); - assertEquals(0, local.size()); - } - - public void testSortToLocalAndGlobalWithCameraDisabled() { - final Bundle local = new Bundle(); - final Bundle global = new Bundle(); - - UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA), - UserManagerInternal.OWNER_TYPE_DEVICE_OWNER, global, local); - assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global); - assertEquals(0, local.size()); - global.clear(); - - UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA), - UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE, global, - local); - assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global); - assertEquals(0, local.size()); - global.clear(); - - UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA), - UserManagerInternal.OWNER_TYPE_PROFILE_OWNER, global, local); - assertEquals(0, global.size()); - assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local); - } - public void testMoveRestriction() { SparseArray<RestrictionsSet> localRestrictions = new SparseArray<>(); RestrictionsSet globalRestrictions = new RestrictionsSet(); diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java index 5df4509af885..adf4551e79a8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java @@ -77,25 +77,25 @@ public class PackageDexUsageTests { String fooDataDir = "/data/user/0/com.google.foo/"; mFooBaseUser0 = new TestData(fooPackageName, - fooCodeDir + "base.apk", 0, ISA, false, true, fooPackageName); + fooCodeDir + "base.apk", 0, ISA, true, fooPackageName); mFooSplit1User0 = new TestData(fooPackageName, - fooCodeDir + "split-1.apk", 0, ISA, false, true, fooPackageName); + fooCodeDir + "split-1.apk", 0, ISA, true, fooPackageName); mFooSplit2UsedByOtherApps0 = new TestData(fooPackageName, - fooCodeDir + "split-2.apk", 0, ISA, true, true, "used.by.other.com"); + fooCodeDir + "split-2.apk", 0, ISA, true, "used.by.other.com"); mFooSecondary1User0 = new TestData(fooPackageName, - fooDataDir + "sec-1.dex", 0, ISA, false, false, fooPackageName); + fooDataDir + "sec-1.dex", 0, ISA, false, fooPackageName); mFooSecondary1User1 = new TestData(fooPackageName, - fooDataDir + "sec-1.dex", 1, ISA, false, false, fooPackageName); + fooDataDir + "sec-1.dex", 1, ISA, false, fooPackageName); mFooSecondary2UsedByOtherApps0 = new TestData(fooPackageName, - fooDataDir + "sec-2.dex", 0, ISA, true, false, "used.by.other.com"); + fooDataDir + "sec-2.dex", 0, ISA, false, "used.by.other.com"); mInvalidIsa = new TestData(fooPackageName, - fooCodeDir + "base.apk", 0, "INVALID_ISA", false, true, "INALID_USER"); + fooCodeDir + "base.apk", 0, "INVALID_ISA", true, "INALID_USER"); String barPackageName = "com.google.bar"; String barCodeDir = "/data/app/com.google.bar/"; @@ -103,11 +103,11 @@ public class PackageDexUsageTests { String barDataDir1 = "/data/user/1/com.google.bar/"; mBarBaseUser0 = new TestData(barPackageName, - barCodeDir + "base.apk", 0, ISA, false, true, barPackageName); + barCodeDir + "base.apk", 0, ISA, true, barPackageName); mBarSecondary1User0 = new TestData(barPackageName, - barDataDir + "sec-1.dex", 0, ISA, false, false, barPackageName); + barDataDir + "sec-1.dex", 0, ISA, false, barPackageName); mBarSecondary2User1 = new TestData(barPackageName, - barDataDir1 + "sec-2.dex", 1, ISA, false, false, barPackageName); + barDataDir1 + "sec-2.dex", 1, ISA, false, barPackageName); } @Test @@ -134,7 +134,9 @@ public class PackageDexUsageTests { public void testRecordSplitPrimarySequence() { // Assert new information. assertTrue(record(mFooBaseUser0)); - // Assert no new information. + assertTrue(record(mFooSplit1User0)); + // Assert no new information if we add again + assertFalse(record(mFooBaseUser0)); assertFalse(record(mFooSplit1User0)); assertPackageDexUsage(mFooBaseUser0); @@ -192,7 +194,7 @@ public class PackageDexUsageTests { for (int i = 1; i <= tooManyFiles; i++) { String fooPackageName = "com.google.foo"; TestData testData = new TestData(fooPackageName, - "/data/user/0/" + fooPackageName + "/sec-" + i + "1.dex", 0, ISA, false, false, + "/data/user/0/" + fooPackageName + "/sec-" + i + "1.dex", 0, ISA, false, fooPackageName); if (i < tooManyFiles) { assertTrue("Adding " + testData.mDexFile, record(testData)); @@ -200,7 +202,11 @@ public class PackageDexUsageTests { } else { assertFalse("Adding " + testData.mDexFile, record(testData)); } - assertPackageDexUsage(mPackageDexUsage, null, null, expectedSecondaries); + assertPackageDexUsage( + mPackageDexUsage, + /* usdeBy=*/ (Set<String>) null, + /* primaryDex= */ null, + expectedSecondaries); } } @@ -276,7 +282,7 @@ public class PackageDexUsageTests { Map<String, Set<String>> packageToCodePaths = new HashMap<>(); packageToCodePaths.put(mBarBaseUser0.mPackageName, new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile))); - mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths); + mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths, new ArrayList<String>()); // Assert that only user 1 files are there. assertPackageDexUsage(mBarBaseUser0, mBarSecondary2User1); @@ -284,6 +290,41 @@ public class PackageDexUsageTests { } @Test + public void testSyncDataKeepPackages() { + PackageDexUsage packageDexUsage = new PackageDexUsage(); + // Write the record we want to keep and which won't be keep by default. + Set<String> fooUsers = new HashSet<>(Arrays.asList( + new String[] {mFooBaseUser0.mPackageName})); + assertTrue(record(packageDexUsage, mFooBaseUser0, fooUsers)); + // Write a record that would be kept by default. + Set<String> barUsers = new HashSet<>(Arrays.asList( + new String[] {"another.package", mFooBaseUser0.mPackageName})); + assertTrue(record(packageDexUsage, mBarBaseUser0, barUsers)); + + // Construct the user packages and their code paths (things that will be + // kept by default during sync). + Map<String, Set<Integer>> packageToUsersMap = new HashMap<>(); + packageToUsersMap.put(mBarBaseUser0.mPackageName, + new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId))); + Map<String, Set<String>> packageToCodePaths = new HashMap<>(); + packageToCodePaths.put(mBarBaseUser0.mPackageName, + new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile))); + + // Sync data. + List<String> keepData = new ArrayList<String>(); + keepData.add(mFooBaseUser0.mPackageName); + packageDexUsage.syncData(packageToUsersMap, packageToCodePaths, keepData); + + // Assert that both packages are kept + assertPackageDexUsage(packageDexUsage, fooUsers, mFooBaseUser0); + // "another.package" should not be in the loading packages after sync. + Set<String> expectedBarUsers = new HashSet<>(Arrays.asList( + new String[] {mFooBaseUser0.mPackageName})); + assertPackageDexUsage(packageDexUsage, expectedBarUsers, + mBarBaseUser0.updateUsedBy(mFooBaseUser0.mPackageName)); + } + + @Test public void testRemovePackage() { // Record Bar secondaries for two different users. assertTrue(record(mBarSecondary1User0)); @@ -345,9 +386,8 @@ public class PackageDexUsageTests { mFooSplit2UsedByOtherApps0.mDexFile, mFooSplit2UsedByOtherApps0.mOwnerUserId, mFooSplit2UsedByOtherApps0.mLoaderIsa, - /*mIsUsedByOtherApps*/false, mFooSplit2UsedByOtherApps0.mPrimaryOrSplit, - mFooSplit2UsedByOtherApps0.mUsedBy); + /*usedBy=*/ null); assertPackageDexUsage(noLongerUsedByOtherApps); } @@ -371,19 +411,19 @@ public class PackageDexUsageTests { assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, users)); assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, usersExtra)); - assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, users)); - assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, usersExtra)); + assertTrue(record(packageDexUsageRecordUsers, mFooSecondary2UsedByOtherApps0, users)); + assertTrue(record(packageDexUsageRecordUsers, mFooSecondary2UsedByOtherApps0, usersExtra)); packageDexUsageRecordUsers = writeAndReadBack(packageDexUsageRecordUsers); // Verify that the users were recorded. Set<String> userAll = new HashSet<>(users); userAll.addAll(usersExtra); assertPackageDexUsage(packageDexUsageRecordUsers, userAll, mFooSplit2UsedByOtherApps0, - mFooSecondary1User0); + mFooSecondary2UsedByOtherApps0); } @Test - public void testRecordDexFileUsersNotTheOwningPackage() { + public void testRecordDexFileUsersAndTheOwningPackage() { PackageDexUsage packageDexUsageRecordUsers = new PackageDexUsage(); Set<String> users = new HashSet<>(Arrays.asList( new String[] {mFooSplit2UsedByOtherApps0.mPackageName})); @@ -393,13 +433,13 @@ public class PackageDexUsageTests { assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, users)); assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, usersExtra)); - assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, users)); - assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, usersExtra)); - packageDexUsageRecordUsers = writeAndReadBack(packageDexUsageRecordUsers); - // Verify that only the non owning packages were recorded. - assertPackageDexUsage(packageDexUsageRecordUsers, usersExtra, mFooSplit2UsedByOtherApps0, - mFooSecondary1User0); + + Set<String> expectedUsers = new HashSet<>(users); + expectedUsers.addAll(usersExtra); + // Verify that all loading packages were recorded. + assertPackageDexUsage( + packageDexUsageRecordUsers, expectedUsers, mFooSplit2UsedByOtherApps0); } @Test @@ -421,44 +461,97 @@ public class PackageDexUsageTests { } @Test - public void testRecordClassLoaderContextTransitionFromUnknown() { - // Record a secondary dex file. - TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext( - PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT); - assertTrue(record(unknownContext)); - - assertPackageDexUsage(null, unknownContext); - writeAndReadBack(); - assertPackageDexUsage(null, unknownContext); - - // Now update the secondary dex record with a class loader context. This simulates the - // version 2 to version 3 upgrade. - - assertTrue(record(mFooSecondary1User0)); - - assertPackageDexUsage(null, mFooSecondary1User0); - writeAndReadBack(); - assertPackageDexUsage(null, mFooSecondary1User0); - } - - @Test public void testDexUsageClassLoaderContext() { final boolean isUsedByOtherApps = false; final int userId = 0; PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId, "valid_context", "arm"); - assertFalse(validContext.isUnknownClassLoaderContext()); + assertFalse(validContext.isUnsupportedClassLoaderContext()); assertFalse(validContext.isVariableClassLoaderContext()); PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId, PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm"); - assertFalse(variableContext.isUnknownClassLoaderContext()); + assertFalse(variableContext.isUnsupportedClassLoaderContext()); assertTrue(variableContext.isVariableClassLoaderContext()); + } - PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId, - PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm"); - assertTrue(unknownContext.isUnknownClassLoaderContext()); - assertFalse(unknownContext.isVariableClassLoaderContext()); + @Test + public void testRead() { + String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); + // Equivalent to + // record(mFooSplit2UsedByOtherApps0); + // record(mFooSecondary1User0); + // record(mFooSecondary2UsedByOtherApps0); + // record(mBarBaseUser0); + // record(mBarSecondary1User0); + String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n" + + "com.google.foo\n" + + "+/data/app/com.google.foo/split-2.apk\n" + + "@used.by.other.com\n" + + "#/data/user/0/com.google.foo/sec-2.dex\n" + + "0,1," + ISA + "\n" + + "@used.by.other.com\n" + + "PCL[/data/user/0/com.google.foo/sec-2.dex]\n" + + "#/data/user/0/com.google.foo/sec-1.dex\n" + + "0,0," + ISA + "\n" + + "@\n" + + "PCL[/data/user/0/com.google.foo/sec-1.dex]\n" + + "com.google.bar\n" + + "+/data/app/com.google.bar/base.apk\n" + + "@com.google.bar\n" + + "#/data/user/0/com.google.bar/sec-1.dex\n" + + "0,0," + ISA + "\n" + + "@\n" + + "PCL[/data/user/0/com.google.bar/sec-1.dex]"; + + PackageDexUsage packageDexUsage = new PackageDexUsage(); + try { + packageDexUsage.read(new StringReader(content)); + } catch (IOException e) { + fail(); + } + + // After the read we must sync the data to fill the missing information on the code paths. + Map<String, Set<Integer>> packageToUsersMap = new HashMap<>(); + Map<String, Set<String>> packageToCodePaths = new HashMap<>(); + + // Handle foo package. + packageToUsersMap.put( + mFooSplit2UsedByOtherApps0.mPackageName, + new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId))); + packageToCodePaths.put( + mFooSplit2UsedByOtherApps0.mPackageName, + new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mDexFile, + mFooSplit1User0.mDexFile, mFooBaseUser0.mDexFile))); + // Handle bar package. + packageToUsersMap.put( + mBarBaseUser0.mPackageName, + new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId))); + packageToCodePaths.put( + mBarBaseUser0.mPackageName, + new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile))); + // Handle the loading package. + packageToUsersMap.put( + mFooSplit2UsedByOtherApps0.mUsedBy, + new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId))); + + // Sync the data. + packageDexUsage.syncData(packageToUsersMap, packageToCodePaths, new ArrayList<>()); + + // Assert foo code paths. + assertPackageDexUsage( + packageDexUsage, + /*nonDefaultUsers=*/ null, + mFooSplit2UsedByOtherApps0, + mFooSecondary2UsedByOtherApps0, + mFooSecondary1User0); + + // Assert bar code paths. + assertPackageDexUsage( + packageDexUsage, + /*nonDefaultUsers=*/ null, + mBarBaseUser0, + mBarSecondary1User0); } @Test @@ -483,77 +576,19 @@ public class PackageDexUsageTests { } @Test - public void testReadVersion1() { + public void testEnsureLoadingPackagesCanBeExtended() { String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); - // Equivalent to - // record(mFooSplit2UsedByOtherApps0); - // record(mFooSecondary1User0); - // record(mFooSecondary2UsedByOtherApps0); - // record(mBarBaseUser0); - // record(mBarSecondary1User0); - String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__1\n" - + "com.google.foo,1\n" - + "#/data/user/0/com.google.foo/sec-1.dex\n" - + "0,0," + isa + "\n" - + "#/data/user/0/com.google.foo/sec-2.dex\n" - + "0,1," + isa + "\n" - + "com.google.bar,0\n" - + "#/data/user/0/com.google.bar/sec-1.dex\n" - + "0,0," + isa + "\n"; - + String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n" + + "com.google.foo\n" + + "+/data/app/com.google.foo/split-2.apk\n" + + "@\n"; PackageDexUsage packageDexUsage = new PackageDexUsage(); try { packageDexUsage.read(new StringReader(content)); } catch (IOException e) { fail(); } - - // After the read we must sync the data to fill the missing information on the code paths. - Map<String, Set<Integer>> packageToUsersMap = new HashMap<>(); - Map<String, Set<String>> packageToCodePaths = new HashMap<>(); - - // Handle foo package. - packageToUsersMap.put(mFooSplit2UsedByOtherApps0.mPackageName, - new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId))); - packageToCodePaths.put(mFooSplit2UsedByOtherApps0.mPackageName, - new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mDexFile, - mFooSplit1User0.mDexFile, mFooBaseUser0.mDexFile))); - // Handle bar package. - packageToUsersMap.put(mBarBaseUser0.mPackageName, - new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId))); - packageToCodePaths.put(mBarBaseUser0.mPackageName, - new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile))); - - // Sync the data. - packageDexUsage.syncData(packageToUsersMap, packageToCodePaths); - - // Update the class loaders to unknown before asserting if needed. Before version 2 we - // didn't have any. - String unknown = PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT; - TestData fooBaseUser0 = mFooBaseUser0.updateClassLoaderContext(unknown); - TestData fooSplit1User0 = mFooSplit1User0.updateClassLoaderContext(unknown); - TestData fooSplit2UsedByOtherApps0 = - mFooSplit2UsedByOtherApps0.updateClassLoaderContext(unknown); - TestData fooSecondary1User0 = mFooSecondary1User0.updateClassLoaderContext(unknown); - TestData fooSecondary2UsedByOtherApps0 = - mFooSecondary2UsedByOtherApps0.updateClassLoaderContext(unknown); - TestData barBaseUser0 = mBarBaseUser0.updateClassLoaderContext(unknown); - TestData barSecondary1User0 = mBarSecondary1User0.updateClassLoaderContext(unknown); - - // Assert foo code paths. Note that we ignore the users during upgrade. - final Set<String> ignoredUsers = null; - assertPackageDexUsage(packageDexUsage, ignoredUsers, - fooSplit2UsedByOtherApps0, fooSecondary1User0, fooSecondary2UsedByOtherApps0); - // Because fooSplit2UsedByOtherApps0 is used by others, all the other code paths must - // share the same data. - assertPackageDexUsage(packageDexUsage, ignoredUsers, - fooSplit1User0.updateUseByOthers(true), - fooSecondary1User0, fooSecondary2UsedByOtherApps0); - assertPackageDexUsage(packageDexUsage, ignoredUsers, fooBaseUser0.updateUseByOthers(true), - fooSecondary1User0, fooSecondary2UsedByOtherApps0); - - // Assert bar code paths. Note that we ignore the users during upgrade. - assertPackageDexUsage(packageDexUsage, ignoredUsers, barBaseUser0, barSecondary1User0); + record(packageDexUsage, mFooSplit2UsedByOtherApps0, mFooSplit2UsedByOtherApps0.getUsedBy()); } private void assertPackageDexUsage(TestData primary, TestData... secondaries) { @@ -570,16 +605,18 @@ public class PackageDexUsageTests { String packageName = primary == null ? secondaries.get(0).mPackageName : primary.mPackageName; - boolean primaryUsedByOtherApps = primary != null && primary.mUsedByOtherApps; + boolean primaryUsedByOtherApps = primary != null && primary.isUsedByOtherApps(); PackageUseInfo pInfo = packageDexUsage.getPackageUseInfo(packageName); // Check package use info assertNotNull(pInfo); if (primary != null) { - assertEquals(primaryUsedByOtherApps, pInfo.isUsedByOtherApps(primary.mDexFile)); if (users != null) { assertEquals(pInfo.getLoadingPackages(primary.mDexFile), users); + } else if (pInfo.getLoadingPackages(primary.mDexFile) != null) { + assertEquals(pInfo.getLoadingPackages(primary.mDexFile), primary.getUsedBy()); } + assertEquals(primaryUsedByOtherApps, pInfo.isUsedByOtherApps(primary.mDexFile)); } Map<String, DexUseInfo> dexUseInfoMap = pInfo.getDexUseInfoMap(); @@ -589,13 +626,15 @@ public class PackageDexUsageTests { for (TestData testData : secondaries) { DexUseInfo dInfo = dexUseInfoMap.get(testData.mDexFile); assertNotNull(dInfo); - assertEquals(testData.mUsedByOtherApps, dInfo.isUsedByOtherApps()); + if (users != null) { + assertEquals(testData.mDexFile, dInfo.getLoadingPackages(), users); + } else { + assertEquals(testData.mDexFile, dInfo.getLoadingPackages(), testData.getUsedBy()); + } + assertEquals(testData.isUsedByOtherApps(), dInfo.isUsedByOtherApps()); assertEquals(testData.mOwnerUserId, dInfo.getOwnerUserId()); assertEquals(1, dInfo.getLoaderIsas().size()); assertTrue(dInfo.getLoaderIsas().contains(testData.mLoaderIsa)); - if (users != null) { - assertEquals(dInfo.getLoadingPackages(), users); - } assertEquals(testData.mClassLoaderContext, dInfo.getClassLoaderContext()); } @@ -603,7 +642,7 @@ public class PackageDexUsageTests { private boolean record(TestData testData) { return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile, - testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps, + testData.mOwnerUserId, testData.mLoaderIsa, testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext); } @@ -611,7 +650,7 @@ public class PackageDexUsageTests { boolean result = true; for (String user : users) { result = result && packageDexUsage.record(testData.mPackageName, testData.mDexFile, - testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps, + testData.mOwnerUserId, testData.mLoaderIsa, testData.mPrimaryOrSplit, user, testData.mClassLoaderContext); } return result; @@ -640,37 +679,49 @@ public class PackageDexUsageTests { private final String mDexFile; private final int mOwnerUserId; private final String mLoaderIsa; - private final boolean mUsedByOtherApps; private final boolean mPrimaryOrSplit; private final String mUsedBy; private final String mClassLoaderContext; private TestData(String packageName, String dexFile, int ownerUserId, - String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, String usedBy) { - this(packageName, dexFile, ownerUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit, - usedBy, "DefaultClassLoaderContextFor_" + dexFile); + String loaderIsa, boolean primaryOrSplit, String usedBy) { + this(packageName, dexFile, ownerUserId, loaderIsa, primaryOrSplit, + usedBy, "PCL[" + dexFile + "]"); } private TestData(String packageName, String dexFile, int ownerUserId, - String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, String usedBy, + String loaderIsa, boolean primaryOrSplit, String usedBy, String classLoaderContext) { mPackageName = packageName; mDexFile = dexFile; mOwnerUserId = ownerUserId; mLoaderIsa = loaderIsa; - mUsedByOtherApps = isUsedByOtherApps; mPrimaryOrSplit = primaryOrSplit; mUsedBy = usedBy; mClassLoaderContext = classLoaderContext; } private TestData updateClassLoaderContext(String newContext) { - return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, mUsedByOtherApps, + return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, mPrimaryOrSplit, mUsedBy, newContext); } - private TestData updateUseByOthers(boolean newUsedByOthers) { - return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, newUsedByOthers, - mPrimaryOrSplit, mUsedBy, mClassLoaderContext); + private TestData updateUsedBy(String newUsedBy) { + return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, + mPrimaryOrSplit, newUsedBy, mClassLoaderContext); + } + + private boolean isUsedByOtherApps() { + return mUsedBy != null && !mPackageName.equals(mUsedBy); + } + + private Set<String> getUsedBy() { + Set<String> users = new HashSet<>(); + if ((mUsedBy != null) && (mPrimaryOrSplit || isUsedByOtherApps())) { + // We do not store the loading package for secondary dex files + // which are not used by others. + users.add(mUsedBy); + } + return users; } } } diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java new file mode 100644 index 000000000000..404f29c118d0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.parsing.library; + +import android.os.Build; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link ComGoogleAndroidMapsUpdater} + */ +@Presubmit +@SmallTest +@RunWith(JUnit4.class) +public class ComGoogleAndroidMapsUpdaterTest extends PackageSharedLibraryUpdaterTest { + + @Test + public void otherUsesLibraries() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary("other") + .addUsesOptionalLibrary("optional") + .addUsesLibrary("com.google.android.maps") + .hideAsParsed()); + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary("other") + .addUsesOptionalLibrary("optional") + .hideAsParsed()) + .hideAsFinal(); + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary("com.google.android.maps") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed()) + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary("com.google.android.maps") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed()) + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, ComGoogleAndroidMapsUpdater::new); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java index ca3886092cf1..09c8142105cc 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java @@ -148,6 +148,23 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal()); } + /** + * Ensures that the {@link PackageBackwardCompatibility} uses a + * {@link ComGoogleAndroidMapsUpdater}. + */ + @Test + public void com_google_android_maps_in_usesLibraries() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary("com.google.android.maps") + .hideAsParsed()); + + ParsingPackage after = PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT); + + checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal()); + } + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance); } diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index eef9012b005b..10981ab49513 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java @@ -16,6 +16,8 @@ package com.android.server.systemconfig; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import android.platform.test.annotations.Presubmit; @@ -164,7 +166,7 @@ public class SystemConfigTest { mSysConfig.readPermissions(folder, /* No permission needed anyway */ 0); - final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>(); + final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>(); packageOneExpected.put("com.android.package1.Full", true); packageOneExpected.put("com.android.package1.Relative", false); @@ -181,7 +183,47 @@ public class SystemConfigTest { } /** + * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS} + * permission flag for the tag: whitelisted-staged-installer. + */ + @Test + public void readPermissions_allowAppConfigs_parsesStagedInstallerWhitelist() + throws IOException { + final String contents = + "<config>\n" + + " <whitelisted-staged-installer package=\"com.android.package1\" />\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "staged-installer-whitelist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + + assertThat(mSysConfig.getWhitelistedStagedInstallers()) + .containsExactly("com.android.package1"); + } + + /** + * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_APP_CONFIGS} + * permission flag for the tag: whitelisted-staged-installer. + */ + @Test + public void readPermissions_notAllowAppConfigs_wontParseStagedInstallerWhitelist() + throws IOException { + final String contents = + "<config>\n" + + " <whitelisted-staged-installer package=\"com.android.package1\" />\n" + + "</config>"; + final File folder = createTempSubfolder("folder"); + createTempFile(folder, "staged-installer-whitelist.xml", contents); + + mSysConfig.readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); + + assertThat(mSysConfig.getWhitelistedStagedInstallers()).isEmpty(); + } + + /** * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. + * * @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed * @return the folder */ @@ -194,7 +236,8 @@ public class SystemConfigTest { /** * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. - * @param folder pre-existing subdirectory of mTemporaryFolder to put the file + * + * @param folder pre-existing subdirectory of mTemporaryFolder to put the file * @param fileName name of the file (e.g. filename.xml) to create * @param contents contents to write to the file * @return the folder containing the newly created file (not the file itself!) 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 f9596b53407f..15220e1ff54a 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -4791,7 +4791,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // enqueue toast -> no toasts enqueued ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), "Text", 2000, 0, null); - verify(mStatusBar).showToast(any(), any(), any(), any(), anyInt(), any()); + verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 1cca207d5336..bdba4b6c8ac8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -495,9 +495,12 @@ public class ActivityStarterTests extends ActivityTestsBase { } private void assertNoTasks(DisplayContent display) { - for (int i = display.getStackCount() - 1; i >= 0; --i) { - final ActivityStack stack = display.getStackAt(i); - assertFalse(stack.hasChild()); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + assertFalse(stack.hasChild()); + } } } @@ -1042,10 +1045,14 @@ public class ActivityStarterTests extends ActivityTestsBase { // move everything to secondary because test expects this but usually sysui // does it. DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId); - for (int i = dc.getStackCount() - 1; i >= 0; --i) { - if (!WindowConfiguration.isSplitScreenWindowingMode( - dc.getStackAt(i).getWindowingMode())) { - dc.getStackAt(i).reparent(mSecondary, POSITION_BOTTOM); + for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final ActivityStack stack = taskDisplayArea.getStackAt(sNdx); + if (!WindowConfiguration.isSplitScreenWindowingMode( + stack.getWindowingMode())) { + stack.reparent(mSecondary, POSITION_BOTTOM); + } } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index d9c3ace4589d..add4e9cf3948 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -686,8 +686,8 @@ public class RecentTasksTest extends ActivityTestsBase { mRecentTasks.setOnlyTestVisibleRange(); mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */); - final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); - final Task alwaysOnTopTask = display.createStack(WINDOWING_MODE_MULTI_WINDOW, + final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); + final Task alwaysOnTopTask = taskDisplayArea.createStack(WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, true /* onTop */); alwaysOnTopTask.setAlwaysOnTop(true); @@ -862,8 +862,8 @@ public class RecentTasksTest extends ActivityTestsBase { final ActivityStack homeStack = mTaskContainer.getRootHomeTask(); final DisplayContent otherDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP); - final ActivityStack otherDisplayStack = otherDisplay.createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final ActivityStack otherDisplayStack = otherDisplay.getDefaultTaskDisplayArea() + .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not // removed diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 48d4e705ff4b..b648346eeb28 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -349,8 +349,8 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Create Recents on secondary display. final TestDisplayContent secondDisplay = addNewDisplayContentAt( DisplayContent.POSITION_TOP); - final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_RECENTS, true /* onTop */); + final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea() + .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */); final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); new ActivityBuilder(mService).setTask(task).build(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 19824bf73c1c..9625ffdac052 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -16,8 +16,18 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 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; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -27,6 +37,9 @@ 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.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import android.platform.test.annotations.Presubmit; @@ -134,4 +147,48 @@ public class TaskDisplayAreaTests extends WindowTestsBase { assertEquals("The testing DisplayContent should be moved to top with task", mWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack); } + + @Test + public void testReuseTaskAsStack() { + final Task candidateTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, mDisplayContent); + final Task newStack = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD, mDisplayContent); + doReturn(newStack).when(mDisplayContent.mTaskContainers).createStack(anyInt(), + anyInt(), anyBoolean(), any(), any(), anyBoolean()); + + final int type = ACTIVITY_TYPE_STANDARD; + assertGetOrCreateStack(WINDOWING_MODE_FULLSCREEN, type, candidateTask, + true /* reuseCandidate */); + assertGetOrCreateStack(WINDOWING_MODE_UNDEFINED, type, candidateTask, + true /* reuseCandidate */); + assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, type, candidateTask, + true /* reuseCandidate */); + assertGetOrCreateStack(WINDOWING_MODE_FREEFORM, type, candidateTask, + true /* reuseCandidate */); + assertGetOrCreateStack(WINDOWING_MODE_MULTI_WINDOW, type, candidateTask, + true /* reuseCandidate */); + assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, type, candidateTask, + false /* reuseCandidate */); + assertGetOrCreateStack(WINDOWING_MODE_PINNED, type, candidateTask, + false /* reuseCandidate */); + + final int windowingMode = WINDOWING_MODE_FULLSCREEN; + assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_HOME, candidateTask, + false /* reuseCandidate */); + assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_RECENTS, candidateTask, + false /* reuseCandidate */); + assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_ASSISTANT, candidateTask, + false /* reuseCandidate */); + assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_DREAM, candidateTask, + false /* reuseCandidate */); + } + + private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask, + boolean reuseCandidate) { + final TaskDisplayArea taskDisplayArea = (TaskDisplayArea) candidateTask.getParent(); + final ActivityStack stack = taskDisplayArea.getOrCreateStack(windowingMode, activityType, + false /* onTop */, null /* intent */, candidateTask /* candidateTask */); + assertEquals(reuseCandidate, stack == candidateTask); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java index 2dbfd06b3019..2ce9c2b9ced0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java @@ -69,8 +69,6 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -119,13 +117,6 @@ public class TaskOrganizerTests extends WindowTestsBase { return createTaskStackOnDisplay(mDisplayContent); } - @Before - public void setUp() { - // We defer callbacks since we need to adjust task surface visibility, but for these tests, - // just run the callbacks synchronously - mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run()); - } - @Test public void testAppearVanish() throws RemoteException { final ActivityStack stack = createStack(); @@ -627,9 +618,12 @@ public class TaskOrganizerTests extends WindowTestsBase { private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) { ArrayList<Task> out = new ArrayList<>(); - for (int i = dc.getStackCount() - 1; i >= 0; --i) { - final Task t = dc.getStackAt(i); - if (t.mCreatedByOrganizer) out.add(t); + for (int tdaNdx = dc.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = dc.getTaskDisplayAreaAt(tdaNdx); + for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) { + final Task t = taskDisplayArea.getStackAt(sNdx); + if (t.mCreatedByOrganizer) out.add(t); + } } return out; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index 50584c61cf92..519ac780bd6b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -354,7 +354,7 @@ public class TaskRecordTests extends ActivityTestsBase { spyOn(parentWindowContainer); parentWindowContainer.setBounds(fullScreenBounds); doReturn(parentWindowContainer).when(task).getParent(); - doReturn(display.mTaskContainers).when(task).getDisplayArea(); + doReturn(display.getDefaultTaskDisplayArea()).when(task).getDisplayArea(); doReturn(stack).when(task).getStack(); doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant(); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index d48e82723295..413ae134fe18 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -33,6 +33,8 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import android.app.WindowConfiguration; @@ -144,7 +146,7 @@ public class TaskStackTests extends WindowTestsBase { // Stack removal is deferred if one of its child is animating. doReturn(true).when(stack).hasWindowsAlive(); - doReturn(true).when(task).isAnimating(TRANSITION | CHILDREN); + doReturn(true).when(task).isAnimating(eq(TRANSITION | CHILDREN), anyInt()); stack.removeIfPossible(); // For the case of deferred removal the task controller will still be connected to the its diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 118c2e4db208..353c781c15ef 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_TASK_OPEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; @@ -35,6 +36,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -423,6 +425,35 @@ public class WindowContainerTests extends WindowTestsBase { } @Test + public void testIsAnimating_typesToCheck() { + final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); + final TestWindowContainer window = builder.setIsAnimating(true).setLayer(0).build(); + + assertTrue(window.isAnimating()); + assertFalse(window.isAnimating(0, ANIMATION_TYPE_SCREEN_ROTATION)); + assertTrue(window.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION)); + assertFalse(window.isAnimatingExcluding(0, ANIMATION_TYPE_APP_TRANSITION)); + + final TestWindowContainer child = window.addChildWindow(); + assertFalse(child.isAnimating()); + assertTrue(child.isAnimating(PARENTS)); + assertTrue(child.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION)); + assertFalse(child.isAnimating(PARENTS, ANIMATION_TYPE_SCREEN_ROTATION)); + + final WindowState windowState = createWindow(null /* parent */, TYPE_BASE_APPLICATION, + mDisplayContent, "TestWindowState"); + WindowContainer parent = windowState.getParent(); + spyOn(windowState.mSurfaceAnimator); + doReturn(true).when(windowState.mSurfaceAnimator).isAnimating(); + doReturn(ANIMATION_TYPE_APP_TRANSITION).when( + windowState.mSurfaceAnimator).getAnimationType(); + assertTrue(parent.isAnimating(CHILDREN)); + + windowState.setControllableInsetProvider(mock(InsetsSourceProvider.class)); + assertFalse(parent.isAnimating(CHILDREN)); + } + + @Test public void testIsVisible() { final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); @@ -895,6 +926,7 @@ public class WindowContainerTests extends WindowTestsBase { mWaitForTransitStart = waitTransitStart; spyOn(mSurfaceAnimator); doReturn(mIsAnimating).when(mSurfaceAnimator).isAnimating(); + doReturn(ANIMATION_TYPE_APP_TRANSITION).when(mSurfaceAnimator).getAnimationType(); } TestWindowContainer getParentWindow() { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 820d3816a6f6..71b35b62366e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -40,6 +40,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; @@ -47,6 +48,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.google.common.truth.Truth.assertThat; + import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; @@ -55,6 +58,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; @@ -65,6 +69,7 @@ import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.util.Size; import android.view.DisplayCutout; @@ -568,6 +573,36 @@ public class WindowStateTests extends WindowTestsBase { } @Test + public void testReportResizedWithRemoteException() { + final WindowState win = mChildAppWindowAbove; + makeWindowVisible(win, win.getParentWindow()); + win.mLayoutSeq = win.getDisplayContent().mLayoutSeq; + win.updateResizingWindowIfNeeded(); + + assertThat(mWm.mResizingWindows).contains(win); + assertTrue(win.getOrientationChanging()); + + mWm.mResizingWindows.remove(win); + spyOn(win.mClient); + try { + doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frame */, + any() /* contentInsets */, any() /* visibleInsets */, any() /* stableInsets */, + anyBoolean() /* reportDraw */, any() /* mergedConfig */, + any() /* backDropFrame */, anyBoolean() /* forceLayout */, + anyBoolean() /* alwaysConsumeSystemBars */, anyInt() /* displayId */, + any() /* displayCutout */); + } catch (RemoteException ignored) { + } + win.reportResized(); + win.updateResizingWindowIfNeeded(); + + // Even "resized" throws remote exception, it is still considered as reported. So the window + // shouldn't be resized again (which may block unfreeze in real case). + assertThat(mWm.mResizingWindows).doesNotContain(win); + assertFalse(win.getOrientationChanging()); + } + + @Test public void testGetTransformationMatrix() { final int PARENT_WINDOW_OFFSET = 1; final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2; diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 6c0f2b0cd278..edbdd4e94ac8 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -40,6 +40,9 @@ import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent; import android.hardware.soundtrigger.SoundTriggerModule; import android.os.Binder; import android.os.DeadObjectException; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.RemoteException; @@ -113,6 +116,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { private PowerSaveModeListener mPowerSaveModeListener; + // Handler to process call state changes will delay to allow time for the audio + // and sound trigger HALs to process the end of call notifications + // before we re enable pending recognition requests. + private final Handler mHandler; + private static final int MSG_CALL_STATE_CHANGED = 0; + private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000; + SoundTriggerHelper(Context context) { ArrayList <ModuleProperties> modules = new ArrayList<>(); int status = SoundTrigger.listModules(modules); @@ -130,6 +140,31 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { // TODO: Figure out how to determine which module corresponds to the DSP hardware. mModuleProperties = modules.get(0); } + + Looper looper = Looper.myLooper(); + if (looper == null) { + looper = Looper.getMainLooper(); + } + if (looper != null) { + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CALL_STATE_CHANGED: + synchronized (mLock) { + onCallStateChangedLocked( + TelephonyManager.CALL_STATE_OFFHOOK == msg.arg1); + } + break; + default: + Slog.e(TAG, "unknown message in handler:" + msg.what); + break; + } + } + }; + } else { + mHandler = null; + } } /** @@ -227,6 +262,37 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return status; } + private int prepareForRecognition(ModelData modelData) { + if (mModule == null) { + mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null); + if (mModule == null) { + Slog.w(TAG, "prepareForRecognition: cannot attach to sound trigger module"); + return STATUS_ERROR; + } + } + // Load the model if it is not loaded. + if (!modelData.isModelLoaded()) { + // Before we try and load this model, we should first make sure that any other + // models that don't have an active recognition/dead callback are unloaded. Since + // there is a finite limit on the number of models that the hardware may be able to + // have loaded, we want to make sure there's room for our model. + stopAndUnloadDeadModelsLocked(); + int[] handle = new int[] { 0 }; + int status = mModule.loadSoundModel(modelData.getSoundModel(), handle); + if (status != SoundTrigger.STATUS_OK) { + Slog.w(TAG, "prepareForRecognition: loadSoundModel failed with status: " + status); + return status; + } + modelData.setHandle(handle[0]); + modelData.setLoaded(); + if (DBG) { + Slog.d(TAG, "prepareForRecognition: Sound model loaded with handle:" + handle[0]); + } + } + return STATUS_OK; + } + + /** * Starts recognition for the given sound model. A single routine for both keyphrase and * generic sound models. @@ -248,12 +314,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { Slog.w(TAG, "Attempting startRecognition without the capability"); return STATUS_ERROR; } - if (mModule == null) { - mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null); - if (mModule == null) { - Slog.w(TAG, "startRecognition cannot attach to sound trigger module"); - return STATUS_ERROR; + + IRecognitionStatusCallback oldCallback = modelData.getCallback(); + if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) { + Slog.w(TAG, "Canceling previous recognition for model id: " + + modelData.getModelId()); + try { + oldCallback.onError(STATUS_ERROR); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException in onDetectionStopped", e); } + modelData.clearCallback(); } // If the existing SoundModel is different (for the same UUID for Generic and same @@ -287,48 +358,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } - IRecognitionStatusCallback oldCallback = modelData.getCallback(); - if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) { - Slog.w(TAG, "Canceling previous recognition for model id: " + - modelData.getModelId()); - try { - oldCallback.onError(STATUS_ERROR); - } catch (RemoteException e) { - Slog.w(TAG, "RemoteException in onDetectionStopped", e); - } - modelData.clearCallback(); - } - - // Load the model if it is not loaded. - if (!modelData.isModelLoaded()) { - // Before we try and load this model, we should first make sure that any other - // models that don't have an active recognition/dead callback are unloaded. Since - // there is a finite limit on the number of models that the hardware may be able to - // have loaded, we want to make sure there's room for our model. - stopAndUnloadDeadModelsLocked(); - int[] handle = new int[] { INVALID_VALUE }; - int status = mModule.loadSoundModel(soundModel, handle); - if (status != SoundTrigger.STATUS_OK) { - Slog.w(TAG, "loadSoundModel call failed with " + status); - return status; - } - if (handle[0] == INVALID_VALUE) { - Slog.w(TAG, "loadSoundModel call returned invalid sound model handle"); - return STATUS_ERROR; - } - modelData.setHandle(handle[0]); - modelData.setLoaded(); - Slog.d(TAG, "Sound model loaded with handle:" + handle[0]); - } modelData.setCallback(callback); modelData.setRequested(true); modelData.setRecognitionConfig(recognitionConfig); modelData.setSoundModel(soundModel); - int status = startRecognitionLocked(modelData, + if (!isRecognitionAllowed()) { + initializeTelephonyAndPowerStateListeners(); + return STATUS_OK; + } + + int status = prepareForRecognition(modelData); + if (status != STATUS_OK) { + Slog.w(TAG, "startRecognition failed to prepare model for recognition"); + return status; + } + status = startRecognitionLocked(modelData, false /* Don't notify for synchronous calls */); - // Initialize power save, call active state monitoring logic. + // Initialize power save, call active state monitoring logic. if (status == STATUS_OK) { initializeTelephonyAndPowerStateListeners(); } @@ -398,7 +446,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (DBG) { Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" + callback.asBinder()); - Slog.d(TAG, "current callback=" + (modelData == null ? "null" : + Slog.d(TAG, "current callback=" + + ((modelData == null || modelData.getCallback() == null) ? "null" : modelData.getCallback().asBinder())); } int status = stopRecognition(modelData, callback); @@ -507,8 +556,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { synchronized (mLock) { MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1); ModelData modelData = getKeyphraseModelDataLocked(keyphraseId); - if (mModule == null || modelData == null || modelData.getHandle() == INVALID_VALUE || - !modelData.isKeyphraseModel()) { + if (mModule == null || modelData == null || !modelData.isModelLoaded() + || !modelData.isKeyphraseModel()) { return STATUS_ERROR; } @@ -943,6 +992,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return STATUS_OK; } if (start) { + int status = prepareForRecognition(model); + if (status != STATUS_OK) { + return status; + } return startRecognitionLocked(model, notify); } else { return stopRecognitionLocked(model, notify); @@ -992,8 +1045,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { @Override public void onCallStateChanged(int state, String arg1) { if (DBG) Slog.d(TAG, "onCallStateChanged: " + state); - synchronized (mLock) { - onCallStateChangedLocked(TelephonyManager.CALL_STATE_OFFHOOK == state); + + if (mHandler != null) { + synchronized (mLock) { + mHandler.removeMessages(MSG_CALL_STATE_CHANGED); + Message msg = mHandler.obtainMessage(MSG_CALL_STATE_CHANGED, state, 0); + mHandler.sendMessageDelayed( + msg, (TelephonyManager.CALL_STATE_OFFHOOK == state) ? 0 + : CALL_INACTIVE_MSG_DELAY_MS); + } } } } @@ -1216,9 +1276,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { // models. private int startRecognitionLocked(ModelData modelData, boolean notify) { IRecognitionStatusCallback callback = modelData.getCallback(); - int handle = modelData.getHandle(); RecognitionConfig config = modelData.getRecognitionConfig(); - if (callback == null || handle == INVALID_VALUE || config == null) { + if (callback == null || !modelData.isModelLoaded() || config == null) { // Nothing to do here. Slog.w(TAG, "startRecognition: Bad data passed in."); MetricsLogger.count(mContext, "sth_start_recognition_error", 1); @@ -1235,7 +1294,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (mModule == null) { return STATUS_ERROR; } - int status = mModule.startRecognition(handle, config); + int status = mModule.startRecognition(modelData.getHandle(), config); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "startRecognition failed with " + status); MetricsLogger.count(mContext, "sth_start_recognition_error", 1); @@ -1376,7 +1435,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { // Model handle is an integer used by the HAL as an identifier for sound // models. - private int mModelHandle = INVALID_VALUE; + private int mModelHandle; // The SoundModel instance, one of KeyphraseSoundModel or GenericSoundModel. private SoundModel mSoundModel = null; @@ -1436,7 +1495,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { synchronized void clearState() { mModelState = MODEL_NOTLOADED; - mModelHandle = INVALID_VALUE; mRecognitionConfig = null; mRequested = false; mCallback = null; diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java index 548af0c54b03..498cb7c1c710 100644 --- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java @@ -18,7 +18,6 @@ package com.google.android.test.windowinsetstests; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; - import static java.lang.Math.max; import static java.lang.Math.min; @@ -31,6 +30,7 @@ import android.content.Context; import android.graphics.Insets; import android.os.Bundle; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -44,11 +44,11 @@ import android.view.WindowInsetsController.OnControllableInsetsChangedListener; import android.view.animation.LinearInterpolator; import android.widget.LinearLayout; -import androidx.appcompat.app.AppCompatActivity; - import java.util.ArrayList; import java.util.List; +import androidx.appcompat.app.AppCompatActivity; + public class WindowInsetsActivity extends AppCompatActivity { private View mRoot; @@ -191,6 +191,40 @@ public class WindowInsetsActivity extends AppCompatActivity { mTransitions.forEach(it -> it.onFinish(animation)); } }); + + findViewById(R.id.floating_action_button).setOnClickListener( + v -> v.getWindowInsetsController().controlWindowInsetsAnimation(ime(), -1, + new LinearInterpolator(), null /* cancellationSignal */, + new WindowInsetsAnimationControlListener() { + @Override + public void onReady( + WindowInsetsAnimationController controller, + int types) { + ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); + anim.setDuration(1500); + anim.addUpdateListener(animation + -> controller.setInsetsAndAlpha( + controller.getShownStateInsets(), + (float) animation.getAnimatedValue(), + anim.getAnimatedFraction())); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + controller.finish(true); + } + }); + anim.start(); + } + + @Override + public void onCancelled(WindowInsetsAnimationController controller) { + } + + @Override + public void onFinished(WindowInsetsAnimationController controller) { + } + })); } @Override @@ -200,57 +234,6 @@ public class WindowInsetsActivity extends AppCompatActivity { getWindow().getDecorView().post(() -> getWindow().setDecorFitsSystemWindows(false)); } - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - getWindow().getInsetsController().addOnControllableInsetsChangedListener( - new OnControllableInsetsChangedListener() { - - boolean hasControl = false; - @Override - public void onControllableInsetsChanged(WindowInsetsController controller, - int types) { - if ((types & ime()) != 0 && !hasControl) { - hasControl = true; - controller.controlWindowInsetsAnimation(ime(), -1, - new LinearInterpolator(), null /* cancellationSignal */, - new WindowInsetsAnimationControlListener() { - @Override - public void onReady( - WindowInsetsAnimationController controller, - int types) { - ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); - anim.setDuration(1500); - anim.addUpdateListener(animation - -> controller.setInsetsAndAlpha( - controller.getShownStateInsets(), - (float) animation.getAnimatedValue(), - anim.getAnimatedFraction())); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - controller.finish(true); - } - }); - anim.start(); - } - - @Override - public void onFinished( - WindowInsetsAnimationController controller) { - } - - @Override - public void onCancelled( - WindowInsetsAnimationController controller) { - } - }); - } - } - }); - } - static class Transition { private int mEndBottom; private int mStartBottom; diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt new file mode 100644 index 000000000000..ef15b668e24c --- /dev/null +++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net + +import android.net.wifi.aware.DiscoverySession +import android.net.wifi.aware.PeerHandle +import android.net.wifi.aware.WifiAwareNetworkSpecifier +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 + +import com.android.testutils.assertParcelSane + +import java.lang.IllegalStateException + +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito + +@RunWith(AndroidJUnit4::class) +@SmallTest +class MatchAllNetworkSpecifierTest { + @Test + fun testParcel() { + assertParcelSane(MatchAllNetworkSpecifier(), 0) + } + + @Test(expected = IllegalStateException::class) + fun testSatisfiedBy() { + val specifier = MatchAllNetworkSpecifier() + val discoverySession = Mockito.mock(DiscoverySession::class.java) + val peerHandle = Mockito.mock(PeerHandle::class.java) + val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession, + peerHandle).build() + specifier.satisfiedBy(wifiAwareNetworkSpecifier) + } +} diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index 316a83adf45e..6e9dc8eaf2dc 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -55,6 +55,10 @@ import android.util.ArraySet; import androidx.core.os.BuildCompat; import androidx.test.runner.AndroidJUnit4; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; + +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -67,6 +71,9 @@ public class NetworkCapabilitiesTest { private static final String TEST_SSID = "TEST_SSID"; private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID"; + @Rule + public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule(); + private boolean isAtLeastR() { // BuildCompat.isAtLeastR() is used to check the Android version before releasing Android R. // Build.VERSION.SDK_INT > Build.VERSION_CODES.Q is used to check the Android version after @@ -441,7 +448,7 @@ public class NetworkCapabilitiesTest { return range; } - @Test + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testSetAdministratorUids() { NetworkCapabilities nc = new NetworkCapabilities().setAdministratorUids(new int[] {2, 1, 3}); @@ -449,7 +456,7 @@ public class NetworkCapabilitiesTest { assertArrayEquals(new int[] {1, 2, 3}, nc.getAdministratorUids()); } - @Test + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testSetAdministratorUidsWithDuplicates() { try { new NetworkCapabilities().setAdministratorUids(new int[] {1, 1}); @@ -510,6 +517,12 @@ public class NetworkCapabilitiesTest { assertFalse(nc2.appliesToUid(12)); assertTrue(nc1.appliesToUid(22)); assertTrue(nc2.appliesToUid(22)); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + public void testCombineCapabilities_AdministratorUids() { + final NetworkCapabilities nc1 = new NetworkCapabilities(); + final NetworkCapabilities nc2 = new NetworkCapabilities(); final int[] adminUids = {3, 6, 12}; nc1.setAdministratorUids(adminUids); @@ -518,7 +531,7 @@ public class NetworkCapabilitiesTest { assertArrayEquals(nc2.getAdministratorUids(), adminUids); final int[] adminUidsOtherOrder = {3, 12, 6}; - nc1.setAdministratorUids(adminUids); + nc1.setAdministratorUids(adminUidsOtherOrder); assertTrue(nc2.equalsAdministratorUids(nc1)); final int[] adminUids2 = {11, 1, 12, 3, 6}; diff --git a/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt new file mode 100644 index 000000000000..9119d62fb023 --- /dev/null +++ b/tests/net/common/java/android/net/netstats/NetworkStatsApiTest.kt @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats + +import android.net.NetworkStats +import android.net.NetworkStats.DEFAULT_NETWORK_NO +import android.net.NetworkStats.DEFAULT_NETWORK_YES +import android.net.NetworkStats.Entry +import android.net.NetworkStats.IFACE_VT +import android.net.NetworkStats.METERED_NO +import android.net.NetworkStats.METERED_YES +import android.net.NetworkStats.ROAMING_NO +import android.net.NetworkStats.ROAMING_YES +import android.net.NetworkStats.SET_DEFAULT +import android.net.NetworkStats.SET_FOREGROUND +import android.net.NetworkStats.TAG_NONE +import android.os.Build +import androidx.test.filters.SmallTest +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.assertFieldCountEquals +import com.android.testutils.assertNetworkStatsEquals +import com.android.testutils.assertParcelingIsLossless +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals + +@RunWith(JUnit4::class) +@SmallTest +class NetworkStatsApiTest { + @Rule + @JvmField + val ignoreRule = DevSdkIgnoreRule() + + private val testStatsEmpty = NetworkStats(0L, 0) + + // stats1 and stats2 will have some entries with common keys, which are expected to + // be merged if performing add on these 2 stats. + private val testStats1 = NetworkStats(0L, 0) + // Entries which only appear in set1. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4)) + // Entries which are common for set1 and set2. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0)) + .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8)) + .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0)) + + private val testStats2 = NetworkStats(0L, 0) + // Entries which are common for set1 and set2. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45)) + .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7)) + .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0)) + // Entry which only appears in set2. + .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0)) + + // This is a result of adding stats1 and stats2, while the merging of common key items is + // subject to test later, this should not be initialized with for a loop to add stats1 + // and stats2 above. + private val testStats3 = NetworkStats(0L, 9) + // Entries which are unique either in stats1 or stats2. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2)) + .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0)) + // Entries which are common for stats1 and stats2 are being merged. + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1)) + .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49)) + .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15)) + .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0)) + + companion object { + private const val TEST_IFACE = "test0" + private const val TEST_UID1 = 1001 + private const val TEST_UID2 = 1002 + } + + @Before + fun setUp() { + assertEquals(8, testStats1.size()) + assertEquals(5, testStats2.size()) + assertEquals(9, testStats3.size()) + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testAddEntry() { + val expectedEntriesInStats2 = arrayOf( + Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1), + Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45), + Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7), + Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0), + Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0)) + + // While testStats* are already initialized with addEntry, verify content added + // matches expectation. + for (i in expectedEntriesInStats2.indices) { + val entry = testStats2.getValues(i, null) + assertEquals(expectedEntriesInStats2[i], entry) + } + + // Verify entry updated with addEntry. + val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9)) + assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9), + stats.getValues(3, null)) + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testAdd() { + var stats = NetworkStats(0L, 0) + assertNetworkStatsEquals(testStatsEmpty, stats) + stats = stats.add(testStats2) + assertNetworkStatsEquals(testStats2, stats) + stats = stats.add(testStats1) + // EMPTY + STATS2 + STATS1 = STATS3 + assertNetworkStatsEquals(testStats3, stats) + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testParcelUnparcel() { + assertParcelingIsLossless(testStatsEmpty) + assertParcelingIsLossless(testStats1) + assertParcelingIsLossless(testStats2) + assertFieldCountEquals(15, NetworkStats::class.java) + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testDescribeContents() { + assertEquals(0, testStatsEmpty.describeContents()) + assertEquals(0, testStats1.describeContents()) + assertEquals(0, testStats2.describeContents()) + assertEquals(0, testStats3.describeContents()) + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testSubtract() { + // STATS3 - STATS2 = STATS1 + assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2)) + // STATS3 - STATS1 = STATS2 + assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1)) + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testMethodsDontModifyReceiver() { + listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach { + val origStats = it.clone() + it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45)) + it.add(testStats3) + it.subtract(testStats1) + assertNetworkStatsEquals(origStats, it) + } + } +}
\ No newline at end of file diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index e71d5995255d..98f705f45e98 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -503,6 +503,53 @@ public class NetworkStatsTest { } @Test + public void testRemoveEmptyEntries() throws Exception { + // Test empty stats. + final NetworkStats statsEmpty = new NetworkStats(TEST_START, 3); + assertEquals(0, statsEmpty.removeEmptyEntries().size()); + + // Test stats with non-zero entry. + final NetworkStats statsNonZero = new NetworkStats(TEST_START, 1) + .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L); + assertEquals(1, statsNonZero.size()); + final NetworkStats expectedNonZero = statsNonZero.removeEmptyEntries(); + assertEquals(1, expectedNonZero.size()); + assertValues(expectedNonZero, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L); + + // Test stats with empty entry. + final NetworkStats statsZero = new NetworkStats(TEST_START, 1) + .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); + assertEquals(1, statsZero.size()); + final NetworkStats expectedZero = statsZero.removeEmptyEntries(); + assertEquals(1, statsZero.size()); // Assert immutable. + assertEquals(0, expectedZero.size()); + + // Test stats with multiple entries. + final NetworkStats statsMultiple = new NetworkStats(TEST_START, 0) + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 0L, 8L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 4L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 2L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 1L); + assertEquals(9, statsMultiple.size()); + final NetworkStats expectedMultiple = statsMultiple.removeEmptyEntries(); + assertEquals(9, statsMultiple.size()); // Assert immutable. + assertEquals(7, expectedMultiple.size()); + assertValues(expectedMultiple.getTotalIncludingTags(null), 14L, 104L, 4L, 4L, 21L); + + // Test stats with multiple empty entries. + assertEquals(statsMultiple.size(), statsMultiple.subtract(statsMultiple).size()); + assertEquals(0, statsMultiple.subtract(statsMultiple).removeEmptyEntries().size()); + } + + @Test public void testClone() throws Exception { final NetworkStats original = new NetworkStats(TEST_START, 5) .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java index 9b248878fe96..d0ebb5283f49 100644 --- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java +++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java @@ -181,7 +181,7 @@ public class Nat464XlatTest { Nat464Xlat nat = makeNat464Xlat(); ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); - nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX)); + nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX)); // Start clat. nat.start(); @@ -222,7 +222,7 @@ public class Nat464XlatTest { ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); InOrder inOrder = inOrder(mNetd, mConnectivity); - nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX)); + nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX)); nat.start(); @@ -309,7 +309,7 @@ public class Nat464XlatTest { Nat464Xlat nat = makeNat464Xlat(); ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class); - nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX)); + nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX)); nat.start(); @@ -348,7 +348,7 @@ public class Nat464XlatTest { public void testStopBeforeClatdStarts() throws Exception { Nat464Xlat nat = makeNat464Xlat(); - nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX)); + nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX)); nat.start(); @@ -380,7 +380,7 @@ public class Nat464XlatTest { public void testStopAndClatdNeverStarts() throws Exception { Nat464Xlat nat = makeNat464Xlat(); - nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX)); + nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX)); nat.start(); diff --git a/wifi/Android.bp b/wifi/Android.bp index 2029479fb09f..99beb7bfa043 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -81,7 +81,6 @@ java_library { libs: [ "framework-annotations-lib", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage - "framework-telephony-stubs", ], srcs: [ ":framework-wifi-updatable-sources", |