Merge "Wrapping the inflater into InjectionInflationController." into qt-dev
diff --git a/Android.bp b/Android.bp
index b4110fa..0fcc0d5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -320,7 +320,7 @@
"core/java/android/service/vr/IVrManager.aidl",
"core/java/android/service/vr/IVrStateCallbacks.aidl",
"core/java/android/service/watchdog/IExplicitHealthCheckService.aidl",
- "core/java/android/service/watchdog/PackageInfo.aidl",
+ "core/java/android/service/watchdog/PackageConfig.aidl",
"core/java/android/print/ILayoutResultCallback.aidl",
"core/java/android/print/IPrinterDiscoveryObserver.aidl",
"core/java/android/print/IPrintDocumentAdapter.aidl",
diff --git a/api/current.txt b/api/current.txt
index b7a951c..f62c689 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3763,6 +3763,7 @@
method public void onDetachedFromWindow();
method public void onEnterAnimationComplete();
method public boolean onGenericMotionEvent(android.view.MotionEvent);
+ method @NonNull public java.util.List<android.app.DirectAction> onGetDirectActions();
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
@@ -3782,6 +3783,7 @@
method public void onOptionsMenuClosed(android.view.Menu);
method public void onPanelClosed(int, @NonNull android.view.Menu);
method @CallSuper protected void onPause();
+ method public void onPerformDirectAction(@NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.os.Bundle>);
method public void onPictureInPictureModeChanged(boolean, android.content.res.Configuration);
method @Deprecated public void onPictureInPictureModeChanged(boolean);
method @CallSuper protected void onPostCreate(@Nullable android.os.Bundle);
@@ -4603,6 +4605,22 @@
field @Deprecated public static final int STYLE_NO_TITLE = 1; // 0x1
}
+ public final class DirectAction implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.os.Bundle getExtras();
+ method @NonNull public String getId();
+ method @Nullable public android.content.LocusId getLocusId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.DirectAction> CREATOR;
+ }
+
+ public static final class DirectAction.Builder {
+ ctor public DirectAction.Builder(@NonNull String);
+ method @NonNull public android.app.DirectAction build();
+ method @NonNull public android.app.DirectAction.Builder setExtras(@Nullable android.os.Bundle);
+ method @NonNull public android.app.DirectAction.Builder setLocusId(@Nullable android.content.LocusId);
+ }
+
public class DownloadManager {
method public long addCompletedDownload(String, String, boolean, String, String, long, boolean);
method public long addCompletedDownload(String, String, boolean, String, String, long, boolean, android.net.Uri, android.net.Uri);
@@ -6338,9 +6356,13 @@
public final class VoiceInteractor {
method public android.app.VoiceInteractor.Request getActiveRequest(String);
method public android.app.VoiceInteractor.Request[] getActiveRequests();
+ method public boolean isDestroyed();
+ method public void notifyDirectActionsChanged();
+ method public boolean registerOnDestroyedCallback(@NonNull java.util.concurrent.Executor, @NonNull Runnable);
method public boolean submitRequest(android.app.VoiceInteractor.Request);
method public boolean submitRequest(android.app.VoiceInteractor.Request, String);
method public boolean[] supportsCommands(String[]);
+ method public boolean unregisterOnDestroyedCallback(@NonNull Runnable);
}
public static class VoiceInteractor.AbortVoiceRequest extends android.app.VoiceInteractor.Request {
@@ -41790,9 +41812,11 @@
method public void onCreate();
method public android.view.View onCreateContentView();
method public void onDestroy();
+ method public void onDirectActionsInvalidated(@NonNull android.service.voice.VoiceInteractionSession.ActivityId);
method public boolean[] onGetSupportedCommands(String[]);
- method public void onHandleAssist(@Nullable android.os.Bundle, @Nullable android.app.assist.AssistStructure, @Nullable android.app.assist.AssistContent);
- method public void onHandleAssistSecondary(@Nullable android.os.Bundle, @Nullable android.app.assist.AssistStructure, @Nullable android.app.assist.AssistContent, int, int);
+ method @Deprecated public void onHandleAssist(@Nullable android.os.Bundle, @Nullable android.app.assist.AssistStructure, @Nullable android.app.assist.AssistContent);
+ method public void onHandleAssist(@NonNull android.service.voice.VoiceInteractionSession.AssistState);
+ method @Deprecated public void onHandleAssistSecondary(@Nullable android.os.Bundle, @Nullable android.app.assist.AssistStructure, @Nullable android.app.assist.AssistContent, int, int);
method public void onHandleScreenshot(@Nullable android.graphics.Bitmap);
method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
@@ -41811,6 +41835,8 @@
method public void onTaskFinished(android.content.Intent, int);
method public void onTaskStarted(android.content.Intent, int);
method public void onTrimMemory(int);
+ method public final void performDirectAction(@NonNull android.app.DirectAction, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.os.Bundle>);
+ method public final void requestDirectActions(@NonNull android.service.voice.VoiceInteractionSession.ActivityId, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>);
method public void setContentView(android.view.View);
method public void setDisabledShowContext(int);
method public void setKeepAwake(boolean);
@@ -41835,6 +41861,19 @@
method public void sendAbortResult(android.os.Bundle);
}
+ public static class VoiceInteractionSession.ActivityId {
+ }
+
+ public static final class VoiceInteractionSession.AssistState {
+ method @NonNull public android.service.voice.VoiceInteractionSession.ActivityId getActivityId();
+ method @Nullable public android.app.assist.AssistContent getAssistContent();
+ method @Nullable public android.os.Bundle getAssistData();
+ method @Nullable public android.app.assist.AssistStructure getAssistStructure();
+ method @IntRange(from=0) public int getCount();
+ method @IntRange(from=0xffffffff) public int getIndex();
+ method public boolean isFocused();
+ }
+
public static final class VoiceInteractionSession.CommandRequest extends android.service.voice.VoiceInteractionSession.Request {
method public String getCommand();
method public void sendIntermediateResult(android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index 8cd722b..3350ed7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6839,19 +6839,19 @@
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.PackageInfo> onGetSupportedPackages();
+ method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages();
method public abstract void onRequestHealthCheck(@NonNull String);
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 final class PackageInfo implements android.os.Parcelable {
- ctor public PackageInfo(@NonNull String, long);
+ 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.PackageInfo> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> CREATOR;
}
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 3cde3f2..39020b4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -117,6 +117,7 @@
method public void startActivity(@NonNull android.content.Intent);
method public void startActivity(@NonNull android.content.Intent, android.os.UserHandle);
method public void startActivity(@NonNull android.app.PendingIntent);
+ method public void startActivity(@NonNull android.app.PendingIntent, @NonNull android.app.ActivityOptions);
}
public abstract static class ActivityView.StateCallback {
@@ -369,6 +370,7 @@
method public android.os.ParcelFileDescriptor[] executeShellCommandRw(String);
method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
+ method public void syncInputTransactions();
}
public class UiModeManager {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index c8bd275..9ae0aa0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -65,6 +65,7 @@
import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.GraphicsEnvironment;
import android.os.Handler;
import android.os.IBinder;
@@ -148,8 +149,11 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
@@ -788,6 +792,7 @@
private Instrumentation mInstrumentation;
@UnsupportedAppUsage
private IBinder mToken;
+ private IBinder mAssistToken;
@UnsupportedAppUsage
private int mIdent;
@UnsupportedAppUsage
@@ -866,7 +871,7 @@
private boolean mEnableDefaultActionBarUp;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private VoiceInteractor mVoiceInteractor;
+ VoiceInteractor mVoiceInteractor;
@UnsupportedAppUsage
private CharSequence mTitle;
@@ -1858,9 +1863,12 @@
void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
if (mVoiceInteractor != null) {
- for (Request activeRequest: mVoiceInteractor.getActiveRequests()) {
- activeRequest.cancel();
- activeRequest.clear();
+ final Request[] requests = mVoiceInteractor.getActiveRequests();
+ if (requests != null) {
+ for (Request activeRequest : mVoiceInteractor.getActiveRequests()) {
+ activeRequest.cancel();
+ activeRequest.clear();
+ }
}
}
if (voiceInteractor == null) {
@@ -2316,6 +2324,47 @@
}
/**
+ * Returns the list of direct actions supported by the app.
+ *
+ * <p>You should return the list of actions that could be executed in the
+ * current context, which is in the current state of the app. If the actions
+ * that could be executed by the app changes you should report that via
+ * calling {@link VoiceInteractor#notifyDirectActionsChanged()}.
+ *
+ * <p>To get the voice interactor you need to call {@link #getVoiceInteractor()}
+ * which would return non <code>null<c/ode> only if there is an ongoing voice
+ * interaction session. You an also detect when the voice interactor is no
+ * longer valid because the voice interaction session that is backing is finished
+ * by calling {@link VoiceInteractor#registerOnDestroyedCallback(Executor, Runnable)}.
+ *
+ * <p>This method will be called only after {@link #onStart()} is being called and
+ * before {@link #onStop()} is being called.
+ *
+ * @return The currently supported direct actions which cannot be <code>null</code>
+ * or contain <code>null</null> elements.
+ */
+ @NonNull
+ public List<DirectAction> onGetDirectActions() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * This is called to perform an action previously defined by the app.
+ * Apps also have access to {@link #getVoiceInteractor()} to follow up on the action.
+ *
+ * @param actionId The ID for the action
+ * @param arguments Any additional arguments provided by the caller
+ * @param cancellationSignal A signal to cancel the operation in progress, or {@code null}
+ * if none.
+ * @param resultListener The callback to provide the result back to the caller
+ *
+ * @see #onGetDirectActions()
+ */
+ public void onPerformDirectAction(@NonNull String actionId,
+ @Nullable Bundle arguments, @Nullable CancellationSignal cancellationSignal,
+ @NonNull Consumer<Bundle> resultListener) { }
+
+ /**
* Request the Keyboard Shortcuts screen to show up. This will trigger
* {@link #onProvideKeyboardShortcuts} to retrieve the shortcuts for the foreground activity.
*/
@@ -7626,7 +7675,7 @@
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
- Window window, ActivityConfigCallback activityConfigCallback) {
+ Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
@@ -7647,6 +7696,7 @@
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
+ mAssistToken = assistToken;
mIdent = ident;
mApplication = application;
mIntent = intent;
@@ -7698,6 +7748,11 @@
}
/** @hide */
+ public final IBinder getAssistToken() {
+ return mParent != null ? mParent.getAssistToken() : mAssistToken;
+ }
+
+ /** @hide */
@VisibleForTesting
public final ActivityThread getActivityThread() {
return mMainThread;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9cd42a5..583103c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -88,6 +88,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
@@ -95,6 +96,7 @@
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.LocaleList;
import android.os.Looper;
import android.os.Message;
@@ -121,6 +123,7 @@
import android.renderscript.RenderScriptCacheDir;
import android.security.NetworkSecurityPolicy;
import android.security.net.config.NetworkSecurityConfigProvider;
+import android.service.voice.VoiceInteractionSession;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.system.StructStat;
@@ -160,6 +163,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -450,6 +454,7 @@
public static final class ActivityClientRecord {
@UnsupportedAppUsage
public IBinder token;
+ public IBinder assistToken;
int ident;
@UnsupportedAppUsage
Intent intent;
@@ -526,8 +531,10 @@
String referrer, IVoiceInteractor voiceInteractor, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, boolean isForward,
- ProfilerInfo profilerInfo, ClientTransactionHandler client) {
+ ProfilerInfo profilerInfo, ClientTransactionHandler client,
+ IBinder assistToken) {
this.token = token;
+ this.assistToken = assistToken;
this.ident = ident;
this.intent = intent;
this.referrer = referrer;
@@ -1057,6 +1064,7 @@
}
public void scheduleApplicationInfoChanged(ApplicationInfo ai) {
+ mH.removeMessages(H.APPLICATION_INFO_CHANGED);
sendMessage(H.APPLICATION_INFO_CHANGED, ai);
}
@@ -1645,6 +1653,33 @@
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
+
+ @Override
+ public void requestDirectActions(@NonNull IBinder activityToken,
+ @NonNull IVoiceInteractor interactor, @NonNull RemoteCallback callback) {
+ mH.sendMessage(PooledLambda.obtainMessage(ActivityThread::handleRequestDirectActions,
+ ActivityThread.this, activityToken, interactor, callback));
+ }
+
+ @Override
+ public void performDirectAction(IBinder activityToken, String actionId, Bundle arguments,
+ RemoteCallback cancellationCallback, RemoteCallback resultCallback) {
+ final CancellationSignal cancellationSignal;
+ if (cancellationCallback != null) {
+ final ICancellationSignal transport = CancellationSignal.createTransport();
+ cancellationSignal = CancellationSignal.fromTransport(transport);
+ final Bundle cancellationResult = new Bundle();
+ cancellationResult.putBinder(VoiceInteractor.KEY_CANCELLATION_SIGNAL,
+ transport.asBinder());
+ cancellationCallback.sendResult(cancellationResult);
+ } else {
+ cancellationSignal = new CancellationSignal();
+ }
+
+ mH.sendMessage(PooledLambda.obtainMessage(ActivityThread::handlePerformDirectAction,
+ ActivityThread.this, activityToken, actionId, arguments,
+ cancellationSignal, resultCallback));
+ }
}
class H extends Handler {
@@ -2877,9 +2912,10 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public final Activity startActivityNow(Activity parent, String id,
Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
- Activity.NonConfigurationInstances lastNonConfigurationInstances) {
+ Activity.NonConfigurationInstances lastNonConfigurationInstances, IBinder assistToken) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
+ r.assistToken = assistToken;
r.ident = 0;
r.intent = intent;
r.state = state;
@@ -3120,7 +3156,8 @@
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
- r.referrer, r.voiceInteractor, window, r.configCallback);
+ r.referrer, r.voiceInteractor, window, r.configCallback,
+ r.assistToken);
if (customIntent != null) {
activity.mIntent = customIntent;
@@ -3352,7 +3389,6 @@
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
-
}
private void deliverNewIntents(ActivityClientRecord r, List<ReferrerIntent> intents) {
@@ -3432,6 +3468,7 @@
r.activity.onProvideAssistContent(content);
}
}
+
}
if (structure == null) {
structure = new AssistStructure();
@@ -3451,6 +3488,68 @@
}
}
+ /** Fetches the user actions for the corresponding activity */
+ private void handleRequestDirectActions(@NonNull IBinder activityToken,
+ @NonNull IVoiceInteractor interactor, @NonNull RemoteCallback callback) {
+ final ActivityClientRecord r = mActivities.get(activityToken);
+ if (r != null) {
+ final int lifecycleState = r.getLifecycleState();
+ if (lifecycleState < ON_START || lifecycleState >= ON_STOP) {
+ callback.sendResult(null);
+ return;
+ }
+ if (r.activity.mVoiceInteractor == null
+ || r.activity.mVoiceInteractor.mInteractor.asBinder()
+ != interactor.asBinder()) {
+ if (r.activity.mVoiceInteractor != null) {
+ r.activity.mVoiceInteractor.destroy();
+ }
+ r.activity.mVoiceInteractor = new VoiceInteractor(interactor, r.activity,
+ r.activity, Looper.myLooper());
+ }
+ final List<DirectAction> actions = r.activity.onGetDirectActions();
+ Preconditions.checkNotNull(actions);
+ Preconditions.checkCollectionElementsNotNull(actions, "actions");
+ if (actions != null && !actions.isEmpty()) {
+ final int actionCount = actions.size();
+ for (int i = 0; i < actionCount; i++) {
+ final DirectAction action = actions.get(i);
+ action.setSource(r.activity.getTaskId(), r.activity.getAssistToken());
+ }
+ final Bundle result = new Bundle();
+ result.putParcelable(DirectAction.KEY_ACTIONS_LIST,
+ new ParceledListSlice<>(actions));
+ callback.sendResult(result);
+ }
+ }
+ callback.sendResult(null);
+ }
+
+ /** Performs an actions in the corresponding activity */
+ private void handlePerformDirectAction(@NonNull IBinder activityToken,
+ @NonNull String actionId, @Nullable Bundle arguments,
+ @NonNull CancellationSignal cancellationSignal,
+ @NonNull RemoteCallback resultCallback) {
+ final ActivityClientRecord r = mActivities.get(activityToken);
+ if (r != null) {
+ final int lifecycleState = r.getLifecycleState();
+ if (lifecycleState < ON_START || lifecycleState >= ON_STOP) {
+ resultCallback.sendResult(null);
+ return;
+ }
+ final Bundle nonNullArguments = (arguments != null) ? arguments : Bundle.EMPTY;
+ final WeakReference<RemoteCallback> weakCallback = new WeakReference<>(resultCallback);
+ r.activity.onPerformDirectAction(actionId, nonNullArguments, cancellationSignal,
+ (b) -> {
+ final RemoteCallback strongCallback = weakCallback.get();
+ if (strongCallback != null) {
+ strongCallback.sendResult(b);
+ }
+ });
+ }
+ resultCallback.sendResult(null);
+ }
+
public void handleTranslucentConversionComplete(IBinder token, boolean drawComplete) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
@@ -5028,6 +5127,7 @@
* handling current transaction item before relaunching the activity.
*/
void scheduleRelaunchActivity(IBinder token) {
+ mH.removeMessages(H.RELAUNCH_ACTIVITY, token);
sendMessage(H.RELAUNCH_ACTIVITY, token);
}
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 0ccaf62..fc6fffa 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -255,6 +255,34 @@
}
/**
+ * Launch a new activity into this container.
+ * <p>Activity resolved by the provided {@link PendingIntent} must have
+ * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
+ * launched here. Also, if activity is not owned by the owner of this container, it must allow
+ * embedding and the caller must have permission to embed.
+ * <p>Note: This class must finish initializing and
+ * {@link StateCallback#onActivityViewReady(ActivityView)} callback must be triggered before
+ * this method can be called.
+ *
+ * @param pendingIntent Intent used to launch an activity.
+ * @param options options for the activity
+ *
+ * @see StateCallback
+ * @see #startActivity(Intent)
+ */
+ public void startActivity(@NonNull PendingIntent pendingIntent,
+ @NonNull ActivityOptions options) {
+ options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
+ try {
+ pendingIntent.send(null /* context */, 0 /* code */, null /* intent */,
+ null /* onFinished */, null /* handler */, null /* requiredPermission */,
+ options.toBundle());
+ } catch (PendingIntent.CanceledException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* Check if container is ready to launch and create {@link ActivityOptions} to target the
* virtual display.
*/
diff --git a/core/java/android/app/DirectAction.java b/core/java/android/app/DirectAction.java
new file mode 100644
index 0000000..d191f4b
--- /dev/null
+++ b/core/java/android/app/DirectAction.java
@@ -0,0 +1,188 @@
+/*
+ * 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 android.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.LocusId;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Represents a abstract action that can be perform on this app. This are requested from
+ * outside the app's UI (eg by SystemUI or assistant).
+ */
+public final class DirectAction implements Parcelable {
+
+ /**
+ * @hide
+ */
+ public static final String KEY_ACTIONS_LIST = "actions_list";
+
+ private int mTaskId;
+ private IBinder mActivityId;
+
+ @NonNull
+ private final String mID;
+ @Nullable
+ private final Bundle mExtras;
+ @Nullable
+ private final LocusId mLocusId;
+
+ /** @hide */
+ public DirectAction(@NonNull String id, @Nullable Bundle extras,
+ @Nullable LocusId locusId) {
+ mID = Preconditions.checkStringNotEmpty(id);
+ mExtras = extras;
+ mLocusId = locusId;
+ }
+
+ /** @hide */
+ public void setSource(int taskId, IBinder activityId) {
+ mTaskId = taskId;
+ mActivityId = activityId;
+ }
+
+ /**
+ * @hide
+ */
+ public DirectAction(@NonNull DirectAction original) {
+ mTaskId = original.mTaskId;
+ mActivityId = original.mActivityId;
+ mID = original.mID;
+ mExtras = original.mExtras;
+ mLocusId = original.mLocusId;
+ }
+
+ private DirectAction(Parcel in) {
+ mTaskId = in.readInt();
+ mActivityId = in.readStrongBinder();
+ mID = in.readString();
+ mExtras = in.readBundle();
+ final String idString = in.readString();
+ mLocusId = (idString != null) ? new LocusId(idString) : null;
+ }
+
+ /** @hide */
+ public int getTaskId() {
+ return mTaskId;
+ }
+
+ /** @hide */
+ public IBinder getActivityId() {
+ return mActivityId;
+ }
+
+ /**
+ * Returns the ID for this action.
+ */
+ @NonNull
+ public String getId() {
+ return mID;
+ }
+
+ /**
+ * Returns any extras associated with this action.
+ */
+ @Nullable
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Returns the LocusId for the current state for the app
+ */
+ @Nullable
+ public LocusId getLocusId() {
+ return mLocusId;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTaskId);
+ dest.writeStrongBinder(mActivityId);
+ dest.writeString(mID);
+ dest.writeBundle(mExtras);
+ dest.writeString(mLocusId.getId());
+ }
+
+ /**
+ * Builder for construction of DirectAction.
+ */
+ public static final class Builder {
+ private @NonNull String mId;
+ private @Nullable Bundle mExtras;
+ private @Nullable LocusId mLocusId;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param id The mandatory action id.
+ */
+ public Builder(@NonNull String id) {
+ Preconditions.checkNotNull(id);
+ mId = id;
+ }
+
+ /**
+ * Sets the optional action extras.
+ *
+ * @param extras The extras.
+ * @return This builder.
+ */
+ public @NonNull Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Sets the optional locus id.
+ *
+ * @param locusId The locus id.
+ * @return This builder.
+ */
+ public @NonNull Builder setLocusId(@Nullable LocusId locusId) {
+ mLocusId = locusId;
+ return this;
+ }
+
+ /**
+ * @return A newly constructed instance.
+ */
+ public @NonNull DirectAction build() {
+ return new DirectAction(mId, mExtras, mLocusId);
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<DirectAction> CREATOR =
+ new Parcelable.Creator<DirectAction>() {
+ public DirectAction createFromParcel(Parcel in) {
+ return new DirectAction(in);
+ }
+ public DirectAction[] newArray(int size) {
+ return new DirectAction[size];
+ }
+ };
+}
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 3a09c4c..ac55c53 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -140,4 +140,9 @@
void scheduleApplicationInfoChanged(in ApplicationInfo ai);
void setNetworkBlockSeq(long procStateSeq);
void scheduleTransaction(in ClientTransaction transaction);
+ void requestDirectActions(IBinder activityToken, IVoiceInteractor intractor,
+ in RemoteCallback callback);
+ void performDirectAction(IBinder activityToken, String actionId,
+ in Bundle arguments, in RemoteCallback cancellationCallback,
+ in RemoteCallback resultCallback);
}
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 96da72a..8c3180b 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -37,6 +37,7 @@
void connect(IAccessibilityServiceClient client, int flags);
void disconnect();
boolean injectInputEvent(in InputEvent event, boolean sync);
+ void syncInputTransactions();
boolean setRotation(int rotation);
Bitmap takeScreenshot(in Rect crop, int rotation);
boolean clearWindowContentFrameStats(int windowId);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 4f94209..41733b3 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1206,7 +1206,7 @@
public Activity newActivity(Class<?> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
- Object lastNonConfigurationInstance) throws InstantiationException,
+ Object lastNonConfigurationInstance) throws InstantiationException,
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
@@ -1218,7 +1218,7 @@
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
- null /* window */, null /* activityConfigCallback */);
+ null /* window */, null /* activityConfigCallback */, null /*assistToken*/);
return activity;
}
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 94b1d77..19575b2 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -144,7 +144,7 @@
r.activityInfo = mActivityThread.resolveActivityInfo(r.intent);
}
r.activity = mActivityThread.startActivityNow(
- mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance);
+ mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance, r);
if (r.activity == null) {
return;
}
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 4944673..3935628 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -602,6 +602,25 @@
}
/**
+ * A request for WindowManagerService to wait until all animations have completed and input
+ * information has been sent from WindowManager to native InputManager.
+ *
+ * @hide
+ */
+ @TestApi
+ public void syncInputTransactions() {
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ }
+ try {
+ // Calling out without a lock held.
+ mUiAutomationConnection.syncInputTransactions();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while syncing input transactions!", re);
+ }
+ }
+
+ /**
* Sets the device rotation. A client can freeze the rotation in
* desired state or freeze the rotation to its current state or
* unfreeze the rotation (rotating the device changes its rotation
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 7e07446..dc07df8 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -128,19 +128,30 @@
: InputManager.INJECT_INPUT_EVENT_MODE_ASYNC;
final long identity = Binder.clearCallingIdentity();
try {
- IWindowManager manager = IWindowManager.Stub.asInterface(
- ServiceManager.getService(Context.WINDOW_SERVICE));
- try {
- return manager.injectInputAfterTransactionsApplied(event, mode);
- } catch (RemoteException e) {
- }
- return false;
+ return mWindowManager.injectInputAfterTransactionsApplied(event, mode);
+ } catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
+ return false;
}
@Override
+ public void syncInputTransactions() {
+ synchronized (mLock) {
+ throwIfCalledByNotTrustedUidLocked();
+ throwIfShutdownLocked();
+ throwIfNotConnectedLocked();
+ }
+
+ try {
+ mWindowManager.syncInputTransactions();
+ } catch (RemoteException e) {
+ }
+ }
+
+
+ @Override
public boolean setRotation(int rotation) {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 36ba78b..78285738 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -16,11 +16,13 @@
package android.app;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
@@ -29,15 +31,20 @@
import android.util.ArrayMap;
import android.util.DebugUtils;
import android.util.Log;
+
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.IVoiceInteractorCallback;
import com.android.internal.app.IVoiceInteractorRequest;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.concurrent.Executor;
/**
* Interface for an {@link Activity} to interact with the user through voice. Use
@@ -67,7 +74,12 @@
static final Request[] NO_REQUESTS = new Request[0];
- final IVoiceInteractor mInteractor;
+ /** @hide */
+ public static final String KEY_CANCELLATION_SIGNAL = "key_cancellation_signal";
+ /** @hide */
+ public static final String KEY_KILL_SIGNAL = "key_kill_signal";
+
+ IVoiceInteractor mInteractor;
Context mContext;
Activity mActivity;
@@ -189,13 +201,20 @@
}
@Override
- public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException {
+ public void deliverCancel(IVoiceInteractorRequest request) {
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(
MSG_CANCEL_RESULT, request, null));
}
+
+ @Override
+ public void destroy() {
+ mHandlerCaller.getHandler().sendMessage(PooledLambda.obtainMessage(
+ VoiceInteractor::destroy, VoiceInteractor.this));
+ }
};
final ArrayMap<IBinder, Request> mActiveRequests = new ArrayMap<>();
+ final ArrayMap<Runnable, Executor> mOnDestroyCallbacks = new ArrayMap<>();
static final int MSG_CONFIRMATION_RESULT = 1;
static final int MSG_PICK_OPTION_RESULT = 2;
@@ -887,6 +906,11 @@
mContext = context;
mActivity = activity;
mHandlerCaller = new HandlerCaller(context, looper, mHandlerCallerCallback, true);
+ try {
+ mInteractor.setKillCallback(new KillCallback(this));
+ } catch (RemoteException e) {
+ /* ignore */
+ }
}
Request pullRequest(IVoiceInteractorRequest request, boolean complete) {
@@ -957,6 +981,27 @@
mActivity = null;
}
+ void destroy() {
+ final int requestCount = mActiveRequests.size();
+ for (int i = requestCount - 1; i >= 0; i--) {
+ final Request request = mActiveRequests.valueAt(i);
+ mActiveRequests.removeAt(i);
+ request.cancel();
+ }
+
+ final int callbackCount = mOnDestroyCallbacks.size();
+ for (int i = callbackCount - 1; i >= 0; i--) {
+ final Runnable callback = mOnDestroyCallbacks.keyAt(i);
+ final Executor executor = mOnDestroyCallbacks.valueAt(i);
+ executor.execute(callback);
+ mOnDestroyCallbacks.removeAt(i);
+ }
+
+ // destroyed now
+ mInteractor = null;
+ mActivity.setVoiceInteractor(null);
+ }
+
public boolean submitRequest(Request request) {
return submitRequest(request, null);
}
@@ -973,6 +1018,10 @@
* @return Returns true of the request was successfully submitted, else false.
*/
public boolean submitRequest(Request request, String name) {
+ if (isDestroyed()) {
+ Log.w(TAG, "Cannot interact with a destroyed voice interactor");
+ return false;
+ }
try {
if (request.mRequestInterface != null) {
throw new IllegalStateException("Given " + request + " is already active");
@@ -997,6 +1046,10 @@
* Return all currently active requests.
*/
public Request[] getActiveRequests() {
+ if (isDestroyed()) {
+ Log.w(TAG, "Cannot interact with a destroyed voice interactor");
+ return null;
+ }
synchronized (mActiveRequests) {
final int N = mActiveRequests.size();
if (N <= 0) {
@@ -1018,6 +1071,10 @@
* @return Returns the active request with that name, or null if there was none.
*/
public Request getActiveRequest(String name) {
+ if (isDestroyed()) {
+ Log.w(TAG, "Cannot interact with a destroyed voice interactor");
+ return null;
+ }
synchronized (mActiveRequests) {
final int N = mActiveRequests.size();
for (int i=0; i<N; i++) {
@@ -1040,6 +1097,10 @@
* @return Array of booleans indicating whether each command is supported or not.
*/
public boolean[] supportsCommands(String[] commands) {
+ if (isDestroyed()) {
+ Log.w(TAG, "Cannot interact with a destroyed voice interactor");
+ return new boolean[commands.length];
+ }
try {
boolean[] res = mInteractor.supportsCommands(mContext.getOpPackageName(), commands);
if (DEBUG) Log.d(TAG, "supportsCommands: cmds=" + commands + " res=" + res);
@@ -1049,6 +1110,64 @@
}
}
+ /**
+ * @return whether the voice interactor is destroyed. You should not interact
+ * with a destroyed voice interactor.
+ */
+ public boolean isDestroyed() {
+ return mInteractor == null;
+ }
+
+ /**
+ * Registers a callback to be called when the VoiceInteractor is destroyed.
+ *
+ * @param executor Executor on which to run the callback.
+ * @param callback The callback to run.
+ * @return whether the callback was registered.
+ */
+ public boolean registerOnDestroyedCallback(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Runnable callback) {
+ Preconditions.checkNotNull(executor);
+ Preconditions.checkNotNull(callback);
+ if (isDestroyed()) {
+ Log.w(TAG, "Cannot interact with a destroyed voice interactor");
+ return false;
+ }
+ mOnDestroyCallbacks.put(callback, executor);
+ return true;
+ }
+
+ /**
+ * Unregisters a previously registered onDestroy callback
+ *
+ * @param callback The callback to remove.
+ * @return whether the callback was unregistered.
+ */
+ public boolean unregisterOnDestroyedCallback(@NonNull Runnable callback) {
+ Preconditions.checkNotNull(callback);
+ if (isDestroyed()) {
+ Log.w(TAG, "Cannot interact with a destroyed voice interactor");
+ return false;
+ }
+ return mOnDestroyCallbacks.remove(callback) != null;
+ }
+
+ /**
+ * Notifies the assist framework that the direct actions supported by the app changed.
+ */
+ public void notifyDirectActionsChanged() {
+ if (isDestroyed()) {
+ Log.w(TAG, "Cannot interact with a destroyed voice interactor");
+ return;
+ }
+ try {
+ mInteractor.notifyDirectActionsChanged(mActivity.getTaskId(),
+ mActivity.getAssistToken());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Voice interactor has died", e);
+ }
+ }
+
void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
String innerPrefix = prefix + " ";
if (mActiveRequests.size() > 0) {
@@ -1066,4 +1185,21 @@
writer.println(mInteractor.asBinder());
writer.print(prefix); writer.print(" mActivity="); writer.println(mActivity);
}
+
+ private static final class KillCallback extends ICancellationSignal.Stub {
+ private final WeakReference<VoiceInteractor> mInteractor;
+
+ KillCallback(VoiceInteractor interactor) {
+ mInteractor= new WeakReference<>(interactor);
+ }
+
+ @Override
+ public void cancel() {
+ final VoiceInteractor voiceInteractor = mInteractor.get();
+ if (voiceInteractor != null) {
+ voiceInteractor.mHandlerCaller.getHandler().sendMessage(PooledLambda
+ .obtainMessage(VoiceInteractor::destroy, voiceInteractor));
+ }
+ }
+ }
}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index ed3a296..0d5a763 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -2300,6 +2300,7 @@
/**
* @return The task id for the associated activity.
+ *
* @hide
*/
public int getTaskId() {
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index cdf5d49..1236e0a 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -63,6 +63,7 @@
private List<ReferrerIntent> mPendingNewIntents;
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
+ private IBinder mAssistToken;
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
@@ -78,7 +79,7 @@
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
- mProfilerInfo, client);
+ mProfilerInfo, client, mAssistToken);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -99,14 +100,15 @@
Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo,
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
- List<ReferrerIntent> pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo) {
+ List<ReferrerIntent> pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo,
+ IBinder assistToken) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
instance = new LaunchActivityItem();
}
setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
voiceInteractor, procState, state, persistentState, pendingResults,
- pendingNewIntents, isForward, profilerInfo);
+ pendingNewIntents, isForward, profilerInfo, assistToken);
return instance;
}
@@ -114,7 +116,7 @@
@Override
public void recycle() {
setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
- false, null);
+ false, null, null);
ObjectPool.recycle(this);
}
@@ -139,6 +141,7 @@
dest.writeTypedList(mPendingNewIntents, flags);
dest.writeBoolean(mIsForward);
dest.writeTypedObject(mProfilerInfo, flags);
+ dest.writeStrongBinder(mAssistToken);
}
/** Read from Parcel. */
@@ -152,7 +155,8 @@
in.readPersistableBundle(getClass().getClassLoader()),
in.createTypedArrayList(ResultInfo.CREATOR),
in.createTypedArrayList(ReferrerIntent.CREATOR), in.readBoolean(),
- in.readTypedObject(ProfilerInfo.CREATOR));
+ in.readTypedObject(ProfilerInfo.CREATOR),
+ in.readStrongBinder());
}
public static final @android.annotation.NonNull Creator<LaunchActivityItem> CREATOR =
@@ -187,7 +191,8 @@
&& Objects.equals(mPendingResults, other.mPendingResults)
&& Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
&& mIsForward == other.mIsForward
- && Objects.equals(mProfilerInfo, other.mProfilerInfo);
+ && Objects.equals(mProfilerInfo, other.mProfilerInfo)
+ && Objects.equals(mAssistToken, other.mAssistToken);
}
@Override
@@ -206,6 +211,7 @@
result = 31 * result + Objects.hashCode(mPendingNewIntents);
result = 31 * result + (mIsForward ? 1 : 0);
result = 31 * result + Objects.hashCode(mProfilerInfo);
+ result = 31 * result + Objects.hashCode(mAssistToken);
return result;
}
@@ -247,6 +253,7 @@
+ ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState
+ ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
+ ",pendingNewIntents=" + mPendingNewIntents + ",profilerInfo=" + mProfilerInfo
+ + " assistToken=" + mAssistToken
+ "}";
}
@@ -256,7 +263,7 @@
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
- boolean isForward, ProfilerInfo profilerInfo) {
+ boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken) {
instance.mIntent = intent;
instance.mIdent = ident;
instance.mInfo = info;
@@ -272,5 +279,6 @@
instance.mPendingNewIntents = pendingNewIntents;
instance.mIsForward = isForward;
instance.mProfilerInfo = profilerInfo;
+ instance.mAssistToken = assistToken;
}
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 74ceeb92..388161d 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -56,7 +56,8 @@
* returned by {@link BluetoothAdapter#getBondedDevices()
* BluetoothAdapter.getBondedDevices()}. You can then open a
* {@link BluetoothSocket} for communication with the remote device, using
- * {@link #createRfcommSocketToServiceRecord(UUID)}.
+ * {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using
+ * {@link #createL2capChannel(int)} over Bluetooth LE.
*
* <p class="note"><strong>Note:</strong>
* Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 4e88625..c06b837 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -35,21 +35,28 @@
* On the client side, use a single {@link BluetoothSocket} to both initiate
* an outgoing connection and to manage the connection.
*
- * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
- * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
- * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
+ * <p>For Bluetooth BR/EDR, the most common type of socket is RFCOMM, which is the type supported by
+ * the Android APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth BR/EDR. It
+ * is also known as the Serial Port Profile (SPP). To create a listening
+ * {@link BluetoothServerSocket} that's ready for incoming Bluetooth BR/EDR connections, use {@link
+ * BluetoothAdapter#listenUsingRfcommWithServiceRecord
+ * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}.
*
- * <p>To create a listening {@link BluetoothServerSocket} that's ready for
- * incoming connections, use
- * {@link BluetoothAdapter#listenUsingRfcommWithServiceRecord
- * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}. Then call
- * {@link #accept()} to listen for incoming connection requests. This call
- * will block until a connection is established, at which point, it will return
- * a {@link BluetoothSocket} to manage the connection. Once the {@link
- * BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on
- * the {@link BluetoothServerSocket} when it's no longer needed for accepting
- * connections. Closing the {@link BluetoothServerSocket} will <em>not</em>
- * close the returned {@link BluetoothSocket}.
+ * <p>For Bluetooth LE, the socket uses LE Connection-oriented Channel (CoC). LE CoC is a
+ * connection-oriented, streaming transport over Bluetooth LE and has a credit-based flow control.
+ * Correspondingly, use {@link BluetoothAdapter#listenUsingL2capChannel
+ * BluetoothAdapter.listenUsingL2capChannel()} to create a listening {@link BluetoothServerSocket}
+ * that's ready for incoming Bluetooth LE CoC connections. For LE CoC, you can use {@link #getPsm()}
+ * to get the protocol/service multiplexer (PSM) value that the peer needs to use to connect to your
+ * socket.
+ *
+ * <p> After the listening {@link BluetoothServerSocket} is created, call {@link #accept()} to
+ * listen for incoming connection requests. This call will block until a connection is established,
+ * at which point, it will return a {@link BluetoothSocket} to manage the connection. Once the
+ * {@link BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on the {@link
+ * BluetoothServerSocket} when it's no longer needed for accepting
+ * connections. Closing the {@link BluetoothServerSocket} will <em>not</em> close the returned
+ * {@link BluetoothSocket}.
*
* <p>{@link BluetoothServerSocket} is thread
* safe. In particular, {@link #close} will always immediately abort ongoing
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 03e8c15..db23cfa 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -396,9 +396,6 @@
*/
void setNetworkPermission(int netId, int permission);
- void setPermission(String permission, in int[] uids);
- void clearPermission(in int[] uids);
-
/**
* Allow UID to call protect().
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 24f42d4..4da0d2d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7983,6 +7983,16 @@
"lock_screen_show_notifications";
/**
+ * Indicates whether the lock screen should display silent notifications.
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ public static final String LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS =
+ "lock_screen_show_silent_notifications";
+
+ /**
* List of TV inputs that are currently hidden. This is a string
* containing the IDs of all hidden TV inputs. Each ID is encoded by
* {@link android.net.Uri#encode(String)} and separated by ':'.
@@ -8838,6 +8848,7 @@
LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
LOCK_SCREEN_CUSTOM_CLOCK_FACE,
LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
ZEN_DURATION,
SHOW_ZEN_UPGRADE_NOTIFICATION,
SHOW_ZEN_SETTINGS_SUGGESTION,
@@ -9013,6 +9024,7 @@
VALIDATORS.put(IN_CALL_NOTIFICATION_ENABLED, IN_CALL_NOTIFICATION_ENABLED_VALIDATOR);
VALIDATORS.put(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, BOOLEAN_VALIDATOR);
VALIDATORS.put(LOCK_SCREEN_SHOW_NOTIFICATIONS, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, BOOLEAN_VALIDATOR);
VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR);
VALIDATORS.put(SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 78e6bc3..c142a53 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
+import android.os.IBinder;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
@@ -30,8 +31,8 @@
oneway interface IVoiceInteractionSession {
void show(in Bundle sessionArgs, int flags, IVoiceInteractionSessionShowCallback showCallback);
void hide();
- void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content,
- int index, int count);
+ void handleAssist(int taskId, in IBinder activityId, in Bundle assistData,
+ in AssistStructure structure, in AssistContent content, int index, int count);
void handleScreenshot(in Bitmap screenshot);
void taskStarted(in Intent intent, int taskId);
void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 5b5f3b8..81b84e1 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -18,9 +18,13 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Dialog;
+import android.app.DirectAction;
import android.app.Instrumentation;
import android.app.VoiceInteractor;
import android.app.assist.AssistContent;
@@ -28,6 +32,7 @@
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -36,9 +41,12 @@
import android.inputmethodservice.SoftInputWindow;
import android.os.Binder;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.Message;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -52,6 +60,7 @@
import android.view.WindowManager;
import android.widget.FrameLayout;
+import com.android.internal.annotations.Immutable;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
@@ -59,10 +68,16 @@
import com.android.internal.app.IVoiceInteractorRequest;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* An active voice interaction session, providing a facility for the implementation
@@ -156,6 +171,8 @@
final WeakReference<VoiceInteractionSession> mWeakRef
= new WeakReference<VoiceInteractionSession>(this);
+ ICancellationSignal mKillCallback;
+
final IVoiceInteractor mInteractor = new IVoiceInteractor.Stub() {
@Override
public IVoiceInteractorRequest startConfirmation(String callingPackage,
@@ -230,6 +247,19 @@
}
return new boolean[commands.length];
}
+
+ @Override
+ public void notifyDirectActionsChanged(int taskId, IBinder assistToken) {
+ mHandlerCaller.getHandler().sendMessage(PooledLambda.obtainMessage(
+ VoiceInteractionSession::onDirectActionsInvalidated,
+ VoiceInteractionSession.this, new ActivityId(taskId, assistToken))
+ );
+ }
+
+ @Override
+ public void setKillCallback(ICancellationSignal callback) {
+ mKillCallback = callback;
+ }
};
final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
@@ -248,8 +278,9 @@
}
@Override
- public void handleAssist(final Bundle data, final AssistStructure structure,
- final AssistContent content, final int index, final int count) {
+ public void handleAssist(final int taskId, final IBinder assistToken, final Bundle data,
+ final AssistStructure structure, final AssistContent content, final int index,
+ final int count) {
// We want to pre-warm the AssistStructure before handing it off to the main
// thread. We also want to do this on a separate thread, so that if the app
// is for some reason slow (due to slow filling in of async children in the
@@ -267,9 +298,19 @@
failure = e;
}
}
- mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOII(MSG_HANDLE_ASSIST,
- data, failure == null ? structure : null, failure, content,
- index, count));
+
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = taskId;
+ args.arg1 = data;
+ args.arg2 = (failure == null) ? structure : null;
+ args.arg3 = failure;
+ args.arg4 = content;
+ args.arg5 = assistToken;
+ args.argi5 = index;
+ args.argi6 = count;
+
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(
+ MSG_HANDLE_ASSIST, args));
}
};
retriever.start();
@@ -855,17 +896,13 @@
break;
case MSG_HANDLE_ASSIST:
args = (SomeArgs)msg.obj;
- if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
+ if (DEBUG) Log.d(TAG, "onHandleAssist: taskId=" + args.argi1
+ + "assistToken=" + args.arg5 + " data=" + args.arg1
+ " structure=" + args.arg2 + " content=" + args.arg3
+ " activityIndex=" + args.argi5 + " activityCount=" + args.argi6);
- if (args.argi5 == 0) {
- doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
- (Throwable) args.arg3, (AssistContent) args.arg4);
- } else {
- doOnHandleAssistSecondary((Bundle) args.arg1, (AssistStructure) args.arg2,
- (Throwable) args.arg3, (AssistContent) args.arg4,
- args.argi5, args.argi6);
- }
+ doOnHandleAssist(args.argi1, (IBinder) args.arg5, (Bundle) args.arg1,
+ (AssistStructure) args.arg2, (Throwable) args.arg3,
+ (AssistContent) args.arg4, args.argi5, args.argi6);
break;
case MSG_HANDLE_SCREENSHOT:
if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
@@ -1062,6 +1099,13 @@
void doDestroy() {
onDestroy();
+ if (mKillCallback != null) {
+ try {
+ mKillCallback.cancel();
+ } catch (RemoteException e) {
+ /* ignore */
+ }
+ }
if (mInitialized) {
mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(
mInsetsComputer);
@@ -1301,6 +1345,94 @@
}
/**
+ * Requests a list of supported actions from an app.
+ *
+ * @param activityId Ths activity id of the app to get the actions from.
+ * @param resultExecutor The handler to receive the callback
+ * @param callback The callback to receive the response
+ */
+ public final void requestDirectActions(@NonNull ActivityId activityId,
+ @NonNull @CallbackExecutor Executor resultExecutor,
+ @NonNull Consumer<List<DirectAction>> callback) {
+ if (mToken == null) {
+ throw new IllegalStateException("Can't call before onCreate()");
+ }
+ try {
+ mSystemService.requestDirectActions(mToken, activityId.getTaskId(),
+ activityId.getAssistToken(), new RemoteCallback(new DirectActionsReceiver(
+ Preconditions.checkNotNull(resultExecutor),
+ Preconditions.checkNotNull(callback))));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Called when the direct actions are invalidated.
+ */
+ public void onDirectActionsInvalidated(@NonNull ActivityId activityId) {
+
+ }
+
+ /**
+ * Asks that an action be performed by the app. This will send a request to the app which
+ * provided this action.
+ *
+ * <p> An action could take time to execute and the result is provided asynchronously
+ * via a callback. If the action is taking longer and you want to cancel its execution
+ * you can pass in a cancellation signal through which to notify the app to abort the
+ * action.
+ *
+ * @param action The action to be performed.
+ * @param extras Any optional extras sent to the app as part of the request
+ * @param cancellationSignal A signal to cancel the operation in progress,
+ * or {@code null} if none.
+ * @param resultExecutor The handler to receive the callback.
+ * @param resultListener The callback to receive the response.
+ *
+ * @see #requestDirectActions(ActivityId, Executor, Consumer)
+ * @see Activity#onGetDirectActions()
+ */
+ public final void performDirectAction(@NonNull DirectAction action, @Nullable Bundle extras,
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull @CallbackExecutor Executor resultExecutor,
+ @NonNull Consumer<Bundle> resultListener) {
+ if (mToken == null) {
+ throw new IllegalStateException("Can't call before onCreate()");
+ }
+ Preconditions.checkNotNull(resultExecutor);
+ Preconditions.checkNotNull(resultListener);
+
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
+ final RemoteCallback remoteCallback = new RemoteCallback(b -> {
+ if (b != null) {
+ final IBinder cancellation = b.getBinder(VoiceInteractor.KEY_CANCELLATION_SIGNAL);
+ if (cancellation != null) {
+ if (cancellationSignal != null) {
+ cancellationSignal.setRemote(ICancellationSignal.Stub.asInterface(
+ cancellation));
+ }
+ } else {
+ resultExecutor.execute(() -> resultListener.accept(b));
+ }
+ } else {
+ resultExecutor.execute(() -> resultListener.accept(Bundle.EMPTY));
+ }
+ });
+
+ try {
+ mSystemService.performDirectAction(mToken, action.getId(), extras,
+ action.getTaskId(), action.getActivityId(), remoteCallback,
+ remoteCallback);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Set whether this session will keep the device awake while it is running a voice
* activity. By default, the system holds a wake lock for it while in this state,
* so that it can work even if the screen is off. Setting this to false removes that
@@ -1434,20 +1566,14 @@
mContentFrame.requestApplyInsets();
}
- void doOnHandleAssist(Bundle data, AssistStructure structure, Throwable failure,
- AssistContent content) {
+ void doOnHandleAssist(int taskId, IBinder assistToken, Bundle data, AssistStructure structure,
+ Throwable failure, AssistContent content, int index, int count) {
if (failure != null) {
onAssistStructureFailure(failure);
}
- onHandleAssist(data, structure, content);
- }
-
- void doOnHandleAssistSecondary(Bundle data, AssistStructure structure, Throwable failure,
- AssistContent content, int index, int count) {
- if (failure != null) {
- onAssistStructureFailure(failure);
- }
- onHandleAssistSecondary(data, structure, content, index, count);
+ AssistState assistState = new AssistState(new ActivityId(taskId, assistToken),
+ data, structure, content, index, count);
+ onHandleAssist(assistState);
}
/**
@@ -1480,12 +1606,41 @@
* May be null if assist data has been disabled by the user or device policy; will
* not be automatically filled in with data from the app if the app has marked its
* window as secure.
+ *
+ * @deprecated use {@link #onHandleAssist(AssistState)}
*/
+ @Deprecated
public void onHandleAssist(@Nullable Bundle data, @Nullable AssistStructure structure,
@Nullable AssistContent content) {
}
/**
+ * Called to receive data from the application that the user was currently viewing when
+ * an assist session is started. If the original show request did not specify
+ * {@link #SHOW_WITH_ASSIST}, this method will not be called.
+ *
+ * <p>This method is called for all activities along with an index and count that indicates
+ * which activity the data is for. {@code index} will be between 0 and {@code count}-1 and
+ * this method is called once for each activity in no particular order. The {@code count}
+ * indicates how many activities to expect assist data for, including the top focused one.
+ * The focused activity can be determined by calling {@link AssistState#isFocused()}.
+ *
+ * <p>To be responsive to assist requests, process assist data as soon as it is received,
+ * without waiting for all queued activities to return assist data.
+ *
+ * @param state The state object capturing the state of an activity.
+ */
+ public void onHandleAssist(@NonNull AssistState state) {
+ if (state.getIndex() == 0) {
+ onHandleAssist(state.getAssistData(), state.getAssistStructure(),
+ state.getAssistContent());
+ } else {
+ onHandleAssistSecondary(state.getAssistData(), state.getAssistStructure(),
+ state.getAssistContent(), state.getIndex(), state.getCount());
+ }
+ }
+
+ /**
* Called to receive data from other applications that the user was or is interacting with,
* that are currently on the screen in a multi-window display environment, not including the
* currently focused activity. This could be
@@ -1519,7 +1674,10 @@
* @param count the total number of additional activities for which the assist data is being
* returned, including the focused activity that is returned via
* {@link #onHandleAssist}.
+ *
+ * @deprecated use {@link #onHandleAssist(AssistState)}
*/
+ @Deprecated
public void onHandleAssistSecondary(@Nullable Bundle data, @Nullable AssistStructure structure,
@Nullable AssistContent content, int index, int count) {
}
@@ -1742,4 +1900,166 @@
}
}
}
+
+ private static class DirectActionsReceiver implements RemoteCallback.OnResultListener {
+
+ @NonNull
+ private final Executor mResultExecutor;
+ private final Consumer<List<DirectAction>> mCallback;
+
+ DirectActionsReceiver(Executor resultExecutor, Consumer<List<DirectAction>> callback) {
+ mResultExecutor = resultExecutor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onResult(Bundle result) {
+ final List<DirectAction> list;
+ if (result == null) {
+ list = Collections.emptyList();
+ } else {
+ final ParceledListSlice<DirectAction> pls = result.getParcelable(
+ DirectAction.KEY_ACTIONS_LIST);
+ if (pls != null) {
+ final List<DirectAction> receivedList = pls.getList();
+ list = (receivedList != null) ? receivedList : Collections.emptyList();
+ } else {
+ list = Collections.emptyList();
+ }
+ }
+ mResultExecutor.execute(() -> mCallback.accept(list));
+ }
+ }
+
+ /**
+ * Represents assist state captured when this session was started.
+ * It contains the various assist data objects and a reference to
+ * the source activity.
+ */
+ @Immutable
+ public static final class AssistState {
+ private final @NonNull ActivityId mActivityId;
+ private final int mIndex;
+ private final int mCount;
+ private final @Nullable Bundle mData;
+ private final @Nullable AssistStructure mStructure;
+ private final @Nullable AssistContent mContent;
+
+ AssistState(@NonNull ActivityId activityId, @Nullable Bundle data,
+ @Nullable AssistStructure structure, @Nullable AssistContent content,
+ int index, int count) {
+ mActivityId = activityId;
+ mIndex = index;
+ mCount = count;
+ mData = data;
+ mStructure = structure;
+ mContent = content;
+ }
+
+ /**
+ * @return whether the source activity is focused.
+ */
+ public boolean isFocused() {
+ return mIndex == 0;
+ }
+
+ /**
+ * @return the index of the activity that this state is for.
+ */
+ public @IntRange(from = -1) int getIndex() {
+ return mIndex;
+ }
+
+ /**s
+ * @return the total number of activities for which the assist data is
+ * being returned.
+ */
+ public @IntRange(from = 0) int getCount() {
+ return mCount;
+ }
+
+ /**
+ * @return the id of the source activity
+ */
+ public @NonNull ActivityId getActivityId() {
+ return mActivityId;
+ }
+
+ /**
+ * @return Arbitrary data supplied by the app through
+ * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+ * May be null if assist data has been disabled by the user or device policy.
+ */
+ public @Nullable Bundle getAssistData() {
+ return mData;
+ }
+
+ /**
+ * @return If available, the structure definition of all windows currently
+ * displayed by the app. May be null if assist data has been disabled by the user
+ * or device policy; will be an empty stub if the application has disabled assist
+ * by marking its window as secure.
+ */
+ public @Nullable AssistStructure getAssistStructure() {
+ return mStructure;
+ }
+
+ /**
+ * @return Additional content data supplied by the app through
+ * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
+ * May be null if assist data has been disabled by the user or device policy; will
+ * not be automatically filled in with data from the app if the app has marked its
+ * window as secure.
+ */
+ public @Nullable AssistContent getAssistContent() {
+ return mContent;
+ }
+ }
+
+ /**
+ * Represents the id of an assist source activity.
+ */
+ public static class ActivityId {
+ private final int mTaskId;
+ private final IBinder mAssistToken;
+
+ ActivityId(int taskId, IBinder assistToken) {
+ mTaskId = taskId;
+ mAssistToken = assistToken;
+ }
+
+ int getTaskId() {
+ return mTaskId;
+ }
+
+ IBinder getAssistToken() {
+ return mAssistToken;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ ActivityId that = (ActivityId) o;
+
+ if (mTaskId != that.mTaskId) {
+ return false;
+ }
+ return mAssistToken != null
+ ? mAssistToken.equals(that.mAssistToken)
+ : that.mAssistToken == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mTaskId;
+ result = 31 * result + (mAssistToken != null ? mAssistToken.hashCode() : 0);
+ return result;
+ }
+ }
}
diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
index 682b872..eeefb4a 100644
--- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java
+++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
@@ -16,6 +16,8 @@
package android.service.watchdog;
+import static android.os.Parcelable.Creator;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -26,13 +28,18 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.TimeUnit;
/**
* A service to provide packages supporting explicit health checks and route checks to these
@@ -61,7 +68,7 @@
private static final String TAG = "ExplicitHealthCheckService";
/**
- * {@link Bundle} key for a {@link List} of {@link PackageInfo} value.
+ * {@link Bundle} key for a {@link List} of {@link PackageConfig} value.
*
* {@hide}
*/
@@ -130,7 +137,7 @@
*
* @return all packages supporting explicit health checks
*/
- @NonNull public abstract List<PackageInfo> onGetSupportedPackages();
+ @NonNull public abstract List<PackageConfig> onGetSupportedPackages();
/**
* Called when the system requests for all the packages that it has currently requested
@@ -167,6 +174,112 @@
});
}
+ /**
+ * A PackageConfig contains a package supporting explicit health checks and the
+ * timeout in {@link System#uptimeMillis} across reboots after which health
+ * check requests from clients are failed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final class PackageConfig implements Parcelable {
+ // TODO: Receive from DeviceConfig flag
+ private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1);
+
+ private final String mPackageName;
+ private final long mHealthCheckTimeoutMillis;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param packageName the package name
+ * @param durationMillis the duration in milliseconds, must be greater than or
+ * equal to 0. If it is 0, it will use a system default value.
+ */
+ public PackageConfig(@NonNull String packageName, long healthCheckTimeoutMillis) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ if (healthCheckTimeoutMillis == 0) {
+ mHealthCheckTimeoutMillis = DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS;
+ } else {
+ mHealthCheckTimeoutMillis = Preconditions.checkArgumentNonnegative(
+ healthCheckTimeoutMillis);
+ }
+ }
+
+ private PackageConfig(Parcel parcel) {
+ mPackageName = parcel.readString();
+ mHealthCheckTimeoutMillis = parcel.readLong();
+ }
+
+ /**
+ * Gets the package name.
+ *
+ * @return the package name
+ */
+ public @NonNull String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Gets the timeout in milliseconds to evaluate an explicit health check result after a
+ * request.
+ *
+ * @return the duration in {@link System#uptimeMillis} across reboots
+ */
+ public long getHealthCheckTimeoutMillis() {
+ return mHealthCheckTimeoutMillis;
+ }
+
+ @Override
+ public String toString() {
+ return "PackageConfig{" + mPackageName + ", " + mHealthCheckTimeoutMillis + "}";
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof PackageConfig)) {
+ return false;
+ }
+
+ PackageConfig otherInfo = (PackageConfig) other;
+ return Objects.equals(otherInfo.getHealthCheckTimeoutMillis(),
+ mHealthCheckTimeoutMillis)
+ && Objects.equals(otherInfo.getPackageName(), mPackageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPackageName, mHealthCheckTimeoutMillis);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mPackageName);
+ parcel.writeLong(mHealthCheckTimeoutMillis);
+ }
+
+ public static final @NonNull Creator<PackageConfig> CREATOR = new Creator<PackageConfig>() {
+ @Override
+ public PackageConfig createFromParcel(Parcel source) {
+ return new PackageConfig(source);
+ }
+
+ @Override
+ public PackageConfig[] newArray(int size) {
+ return new PackageConfig[size];
+ }
+ };
+ }
+
+
private class ExplicitHealthCheckServiceWrapper extends IExplicitHealthCheckService.Stub {
@Override
public void setCallback(RemoteCallback callback) throws RemoteException {
@@ -188,7 +301,7 @@
@Override
public void getSupportedPackages(RemoteCallback callback) throws RemoteException {
mHandler.post(() -> {
- List<PackageInfo> packages =
+ List<PackageConfig> packages =
ExplicitHealthCheckService.this.onGetSupportedPackages();
Objects.requireNonNull(packages, "Supported package list must be non-null");
Bundle bundle = new Bundle();
diff --git a/core/java/android/service/watchdog/PackageInfo.aidl b/core/java/android/service/watchdog/PackageConfig.aidl
similarity index 95%
rename from core/java/android/service/watchdog/PackageInfo.aidl
rename to core/java/android/service/watchdog/PackageConfig.aidl
index 5605aec..0131586 100644
--- a/core/java/android/service/watchdog/PackageInfo.aidl
+++ b/core/java/android/service/watchdog/PackageConfig.aidl
@@ -19,4 +19,4 @@
/**
* @hide
*/
-parcelable PackageInfo;
+parcelable PackageConfig;
diff --git a/core/java/android/service/watchdog/PackageInfo.java b/core/java/android/service/watchdog/PackageInfo.java
deleted file mode 100644
index cee9b6d..0000000
--- a/core/java/android/service/watchdog/PackageInfo.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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 android.service.watchdog;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A PackageInfo contains a package supporting explicit health checks and the
- * timeout in {@link System#uptimeMillis} across reboots after which health
- * check requests from clients are failed.
- *
- * @hide
- */
-@SystemApi
-public final class PackageInfo implements Parcelable {
- // TODO: Receive from DeviceConfig flag
- private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1);
-
- private final String mPackageName;
- private final long mHealthCheckTimeoutMillis;
-
- /**
- * Creates a new instance.
- *
- * @param packageName the package name
- * @param durationMillis the duration in milliseconds, must be greater than or
- * equal to 0. If it is 0, it will use a system default value.
- */
- public PackageInfo(@NonNull String packageName, long healthCheckTimeoutMillis) {
- mPackageName = Preconditions.checkNotNull(packageName);
- if (healthCheckTimeoutMillis == 0) {
- mHealthCheckTimeoutMillis = DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS;
- } else {
- mHealthCheckTimeoutMillis = Preconditions.checkArgumentNonnegative(
- healthCheckTimeoutMillis);
- }
- }
-
- private PackageInfo(Parcel parcel) {
- mPackageName = parcel.readString();
- mHealthCheckTimeoutMillis = parcel.readLong();
- }
-
- /**
- * Gets the package name.
- *
- * @return the package name
- */
- public @NonNull String getPackageName() {
- return mPackageName;
- }
-
- /**
- * Gets the timeout in milliseconds to evaluate an explicit health check result after a request.
- *
- * @return the duration in {@link System#uptimeMillis} across reboots
- */
- public long getHealthCheckTimeoutMillis() {
- return mHealthCheckTimeoutMillis;
- }
-
- @Override
- public String toString() {
- return "PackageInfo{" + mPackageName + ", " + mHealthCheckTimeoutMillis + "}";
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == this) {
- return true;
- }
- if (!(other instanceof PackageInfo)) {
- return false;
- }
-
- PackageInfo otherInfo = (PackageInfo) other;
- return Objects.equals(otherInfo.getHealthCheckTimeoutMillis(), mHealthCheckTimeoutMillis)
- && Objects.equals(otherInfo.getPackageName(), mPackageName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mPackageName, mHealthCheckTimeoutMillis);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeString(mPackageName);
- parcel.writeLong(mHealthCheckTimeoutMillis);
- }
-
- public static final @NonNull Creator<PackageInfo> CREATOR = new Creator<PackageInfo>() {
- @Override
- public PackageInfo createFromParcel(Parcel source) {
- return new PackageInfo(source);
- }
-
- @Override
- public PackageInfo[] newArray(int size) {
- return new PackageInfo[size];
- }
- };
-}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 6c37319..c730fe2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -640,5 +640,14 @@
* This is needed for testing since the system add windows and injects input
* quick enough that the windows don't have time to get sent to InputManager.
*/
- boolean injectInputAfterTransactionsApplied(in InputEvent ev, int mode);
+ boolean injectInputAfterTransactionsApplied(in InputEvent ev, int mode);
+
+ /**
+ * Waits until all animations have completed and input information has been sent from
+ * WindowManager to native InputManager.
+ *
+ * This is needed for testing since we need to ensure input information has been propagated to
+ * native InputManager before proceeding with tests.
+ */
+ void syncInputTransactions();
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 420749e..fb5e006 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
+import android.os.RemoteCallback;
import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
@@ -157,4 +158,17 @@
* Provide hints for showing UI.
*/
void setUiHints(in IVoiceInteractionService service, in Bundle hints);
+
+ /**
+ * Requests a list of supported actions from a specific activity.
+ */
+ void requestDirectActions(in IBinder token, int taskId, IBinder assistToken,
+ in RemoteCallback callback);
+
+ /**
+ * Requests performing an action from a specific activity.
+ */
+ void performDirectAction(in IBinder token, String actionId, in Bundle arguments, int taskId,
+ IBinder assistToken, in RemoteCallback cancellationCallback,
+ in RemoteCallback resultCallback);
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractor.aidl b/core/java/com/android/internal/app/IVoiceInteractor.aidl
index 44feafb..d50dc0b 100644
--- a/core/java/com/android/internal/app/IVoiceInteractor.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractor.aidl
@@ -18,6 +18,7 @@
import android.app.VoiceInteractor;
import android.os.Bundle;
+import android.os.ICancellationSignal;
import com.android.internal.app.IVoiceInteractorCallback;
import com.android.internal.app.IVoiceInteractorRequest;
@@ -38,4 +39,6 @@
IVoiceInteractorRequest startCommand(String callingPackage,
IVoiceInteractorCallback callback, String command, in Bundle extras);
boolean[] supportsCommands(String callingPackage, in String[] commands);
+ void notifyDirectActionsChanged(int taskId, IBinder assistToken);
+ void setKillCallback(in ICancellationSignal callback);
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl
index 1331e74..2d13b03 100644
--- a/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractorCallback.aidl
@@ -33,4 +33,5 @@
void deliverAbortVoiceResult(IVoiceInteractorRequest request, in Bundle result);
void deliverCommandResult(IVoiceInteractorRequest request, boolean finished, in Bundle result);
void deliverCancel(IVoiceInteractorRequest request);
+ void destroy();
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a296d64..3a25e67 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -26,6 +26,7 @@
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
+#include <audiomanager/AudioManager.h>
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
#include <media/MicrophoneInfo.h>
@@ -353,7 +354,15 @@
static jint
android_media_AudioSystem_newAudioPlayerId(JNIEnv *env, jobject thiz)
{
- return AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_PLAYER);
+ int id = AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_CLIENT);
+ return id != AUDIO_UNIQUE_ID_ALLOCATE ? id : PLAYER_PIID_INVALID;
+}
+
+static jint
+android_media_AudioSystem_newAudioRecorderId(JNIEnv *env, jobject thiz)
+{
+ int id = AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_CLIENT);
+ return id != AUDIO_UNIQUE_ID_ALLOCATE ? id : RECORD_RIID_INVALID;
}
static jint
@@ -470,9 +479,10 @@
env->CallStaticVoidMethod(clazz,
gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
- event, (jint) clientInfo->uid, clientInfo->session,
- clientInfo->source, clientInfo->port_id, clientInfo->silenced,
- recParamArray, jClientEffects, jEffects, source);
+ event, (jint) clientInfo->riid, (jint) clientInfo->uid,
+ clientInfo->session, clientInfo->source, clientInfo->port_id,
+ clientInfo->silenced, recParamArray, jClientEffects, jEffects,
+ source);
env->DeleteLocalRef(clazz);
env->DeleteLocalRef(recParamArray);
env->DeleteLocalRef(jClientEffects);
@@ -2246,6 +2256,7 @@
{"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
{"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
{"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
+ {"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
{"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
{"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
{"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;I)I", (void *)android_media_AudioSystem_handleDeviceConfigChange},
@@ -2440,7 +2451,7 @@
"dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative =
GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
- "recordingCallbackFromNative", "(IIIIIZ[I[Landroid/media/audiofx/AudioEffect$Descriptor;[Landroid/media/audiofx/AudioEffect$Descriptor;I)V");
+ "recordingCallbackFromNative", "(IIIIIIZ[I[Landroid/media/audiofx/AudioEffect$Descriptor;[Landroid/media/audiofx/AudioEffect$Descriptor;I)V");
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index cc7d7ea..347c7c9 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Laat program toe om metodes te benut om gesigtemplate vir gebruik by te voeg en uit te vee."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gebruik gesigstawinghardeware"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Laat die program toe om gesigstawinghardeware vir stawing te gebruik"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Kon nie gesigdata akkuraat vasvang nie. Probeer weer."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Te helder. Probeer sagter beligting."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Te donker. Probeer helderder beligting."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 268b803..eb52ad9 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"መተግበሪያው ጥቅም ላይ እንዲውሉ የፊት ቅንብር ደንቦችን ለማከል እና ለመሰረዝ የሚያስችሉ ስልቶችን እንዲያስጀምር ያስችለዋል።"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"የፊት ማረጋገጫ ሃርድዌር ይጠቀሙ"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"መተግበሪያው የማረጋገጫ ሃርድዌር ለማረጋገጥ ሥራ እንዲጠቀም ያስችለዋል"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"ትክክለኛ የፊት ውሂብ ማንሳት አልተቻለም። እንደገና ይሞክሩ።"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ከልክ በላይ ፈካ ያለ። ይበልጥ ረጋ ያለ ብርሃን አጠቃቀምን ይሞክሩ።"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ከልክ በላይ ጨለማ ነው። ከዚህ ፈካ ያለ ብርሃን አጠቃቀምን ይሞክሩ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 93edf6d..6d725b7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -565,6 +565,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"السماح للتطبيق باستدعاء طرق لإضافة نماذج من الوجوه وحذفها"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"استخدام أجهزة مصادقة الوجه"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"السماح للتطبيق باستخدام أجهزة مصادقة الوجه"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"تعذّر تسجيل بيانات دقيقة للوجه. حاول مرة أخرى."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ساطع للغاية. تجربة مستوى سطوع أقلّ."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"الصورة معتمة للغاية. يُرجى زيادة السطوع."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index ed8c354..c51764a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"মুখমণ্ডলৰ টেম্প্লেট যোগ কৰাৰ বা মচাৰ পদ্ধতি কামত লগাবলৈ আহ্বান কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"মুখমণ্ডল সত্যাপন হাৰ্ডৱেৰ ব্যৱহাৰ কৰক"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"বিশ্বাসযোগ্য়তা প্ৰমাণীকৰণৰ বাবে এপক মুখমণ্ডল সত্যাপন হাৰ্ডৱেৰ ব্য়ৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"সঠিক মুখমণ্ডলৰ ডেটা কেপচাৰ নহ’ল। আকৌ চেষ্টা কৰক।"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"অতি উজ্জ্বল। ইয়াতকৈ কম পোহৰৰ উৎস ব্যৱহাৰ কৰক।"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"অতি আন্ধাৰ। উজ্জ্বল লাইট ব্যৱহাৰ কৰক।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 6b9d9f6..e046eca 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Proqramdan istifadə üçün barmaq izi şablonlarını əlavə etmək və silmək məqsədilə üsullara müraciət etməyə imkan verir."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"üz identifikasiyası proqramından istifadə edin"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Tətbiqin üz identifikasiyası proqramından identifikasiya zamanı istifadə etməsinə icazə verir"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Dəqiq üz datası əldə edilmədi. Yenidən cəhd edin."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Çox işıqlıdır. Daha az işıqlı şəkli sınayın."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Çox qaranlıqdır. Parlaq işıqdan istifadə edin."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index d35c9f1..2e6f11c 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -556,6 +556,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Dozvoljava da aplikacija aktivira metode za dodavanje i brisanje šablona lica radi korišćenja."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"korišćenje hardv. za potvrdu identiteta pomoću lica"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Dozvoljava da aplikacija koristi hardver za potvrdu identiteta pomoću lica"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Snimanje lica nije uspelo. Probajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Previše je svetlo. Probajte sa slabijim osvetljenjem."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Pretamno je. Probajte sa jačim osvetljenjem."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index c0ec4b4..f6c18a7 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Праграма зможа дадаваць і выдаляць шаблоны твару."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"карыстацца абсталяваннем для распазнавання твару"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Праграма зможа выкарыстоўваць абсталяванне распазнавання твару для аўтэнтыфікацыі"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Не атрымалася распазнаць твар. Паўтарыце спробу."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Занадта светла. Прыглушыце асвятленне."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Занадта цёмна. Павялічце асвятленне."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index bd02eeb..f2f928f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Разрешава на прил. да извиква методи за добавяне и изтриване на лицеви шаблони за ползване"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"използване на хардуера за удостоверяване с лице"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Разрешава на приложението при необходимост да използва хардуера за удостоверяване с лице"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Лицето не бе заснето точно. Опитайте отново."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Твърде светло е. Опитайте при по-слабо осветление."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Твърде тъмно е. Опитайте при по-силно осветление."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2177210..04f8102 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ব্যবহার করার জন্য ফেস টেম্পলেট যোগ করা এবং মোছার পদ্ধতি গ্রহণ করতে অ্যাপটিকে অনুমতি দেয়৷"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ফেস যাচাইকরণ হার্ডওয়্যার ব্যবহার করুন"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"প্রমাণীকরণের জন্য ফেস যাচাইকরণ হার্ডওয়্যার ব্যবহার করার অনুমতি অ্যাপটিকে দেয়"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"মুখের সঠিক ডেটা পাওয়া যায়নি। আবার চেষ্টা করুন।"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"খুব উজ্জ্বল। আলো কমিয়ে চেষ্টা করে দেখুন।"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"খুব অন্ধকার। আরও উজ্জ্বল আলো ব্যবহার করে দেখুন।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 95d18d0..bc47dec 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -556,6 +556,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Omogućava aplikaciji korištenje metoda za dodavanje i brisanje šablona lica za upotrebu."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"upotreba hardvera za autentifikaciju licem"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Omogućava aplikaciji da za autentifikaciju koristi hardver za autentifikaciju licem"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Lice nije snimljeno precizno. Pokušajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Previše svijetlo. Probajte s blažim osvjetljenjem."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Previše je tamno. Pokušajte s jačim osvjetljenjem."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index bbc5adb..4206ed2 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permet que l\'aplicació afegeixi i suprimeixi plantilles de cares que es puguin fer servir."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utilitza el maquinari d\'autenticació facial"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permet que l\'aplicació faci servir maquinari d\'autenticació facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"No es reconeix la teva cara. Torna-ho a provar."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Massa brillant Prova una il·luminació més suau."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Massa fosc. Prova una il·luminació més brillant."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index bc745d9..4815ba7 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Umožňuje aplikaci volat metody k přidání a smazání šablon obličeje, které budou použity."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"použití hardwaru k ověření obličeje"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Umožňuje aplikaci provést ověření pomocí hardwaru k ověření obličeje"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Obličej se nepodařilo zachytit. Zkuste to znovu."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Je příliš světlo. Zmírněte osvětlení."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Je moc velká tma. Přejděte na světlo."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index bf80d40..93a3813 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Tillader, at appen kan bruge metoder til at tilføje og slette ansigtsskabeloner."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"brug hardware til ansigtsgenkendelse"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Tillader, at appen bruger ansigtsgenkendelseshardware til godkendelse"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Der blev ikke registreret ansigtsdata. Prøv igen."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Der er for lyst. Prøv en mere dæmpet belysning."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"For mørkt. Prøv med mere belysning."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 5d4fb79..1a53e61 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Ermöglicht der App, Gesichtsvorlagen hinzuzufügen oder zu entfernen."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"Gesichtserkennungshardware verwenden"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Ermöglicht der App, für die Authentifizierung Gesichtserkennungshardware zu verwenden"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Gesichtsdaten nicht gut erfasst. Erneut versuchen."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Zu hell. Schwächere Beleuchtung ausprobieren."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Zu dunkel. Probier eine hellere Beleuchtung aus."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0746a20..4177a15 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Επιτρέπει στην εφαρμογή να επικαλείται μεθόδους προσθήκης/διαγραφής προτύπων για χρήση."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"χρήση υλικολογισμικού ελέγχου ταυτότητας προσώπου"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί υλικολογισμικό για έλεγχο ταυτότητας"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Αδύνατη λήψη ακριβών δεδομ. προσώπου. Επανάληψη."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Υπερβολικά έντονος φωτισμός. Δοκιμάστε πιο ήπιο."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Πολύ σκοτεινό περιβάλλον. Φροντίστε τον φωτισμό."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index fd74bd6..798293e 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Couldn’t capture accurate face data. Try again."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Too bright. Try gentler lighting."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Too dark. Try brighter lighting."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 29372e7..b27e709 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Couldn’t capture accurate face data. Try again."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Too bright. Try gentler lighting."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Too dark. Try brighter lighting."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index fd74bd6..798293e 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Couldn’t capture accurate face data. Try again."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Too bright. Try gentler lighting."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Too dark. Try brighter lighting."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index fd74bd6..798293e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Couldn’t capture accurate face data. Try again."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Too bright. Try gentler lighting."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Too dark. Try brighter lighting."</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index ad80b7b..fbe82b7 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -553,6 +553,9 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Allows the app to invoke methods to add and delete facial templates for use."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"use face authentication hardware"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Allows the app to use face authentication hardware for authentication"</string>
+ <string name="face_recalibrate_notification_name" msgid="3976629945250435054">"Face Authentication"</string>
+ <string name="face_recalibrate_notification_title" msgid="4087620069451499365">"Re-enroll your face"</string>
+ <string name="face_recalibrate_notification_content" msgid="5530308842361499835">"To improve recognition, please re-enroll your face"</string>
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Couldn’t capture accurate face data. Try again."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Too bright. Try gentler lighting."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Too dark. Try brighter lighting."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 1d3ea55..e7edfe1 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que la app emplee métodos para agregar y borrar plantillas de rostros para su uso."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar el hardware de autenticación facial"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que la app use el hardware de autenticación facial para reconocerte"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Datos faciales imprecisos. Vuelve a intentarlo."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Demasiado brillante. Prueba con menos iluminación."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Demasiado oscuro. Prueba con más iluminación."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9107212..31c655f 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que la app use métodos para añadir y suprimir plantillas de caras para su uso."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar el hardware de autenticación facial"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que la aplicación utilice el hardware de autenticación facial para autenticarte"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Datos faciales no reconocidos. Vuelve a intentarlo."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Hay demasiada luz. Busca un sitio menos iluminado."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Demasiado oscuro. Prueba en un lugar con más luz."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 7ba0b1f..c8c17bd 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Lubab rakendusel tühistada meetodid kasutatavate näomallide lisamiseks ja kustutamiseks."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"kasutada näo autentimise riistvara"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Võimaldab rakendusel autentimiseks kasutada näo autentimise riistvara"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Näoandmeid ei saanud jäädvustada. Proovige uuesti."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Liiga ere. Proovige hämaramat valgust."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Liiga pime. Proovige parema valgustusega kohas."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3b97a0f..d368a54 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Aurpegi-txantiloiak gehitu eta ezabatzeko metodoei dei egitea baimentzen dio aplikazioari."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"erabili aurpegi bidez autentifikatzeko hardwarea"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Aurpegi bidez autentifikatzeko hardwarea erabiltzea baimentzen dio aplikazioari"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Ezin izan dira bildu argazkiaren datu zehatzak. Saiatu berriro."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Argi gehiegi dago. Joan toki ilunago batera."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Ilunegi dago. Erabili argi gehiago."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 2ef3cb1..f09a15e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"به برنامه امکان میدهد روشهایی را برای افزودن و حذف الگوهای چهره جهت استفاده فرابخواند."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"استفاده از سختافزار احراز هویت با چهره"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"به برنامه امکان میدهد از سختافزار احراز هویت با چهره برای احراز هویت استفاده کند"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"دادههای دقیق چهره ضبط نشد. دوباره امتحان کنید."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"خیلی روشن است. روشناییاش را ملایمتر کنید."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"خیلی تاریک است. تصویر را روشنتر کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3c9d45c..3014a0b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Sallii sovelluksen käyttää menetelmiä, joilla voidaan lisätä tai poistaa kasvomalleja."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"käyttää kasvojentodennuslaitteistoa"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Sallii sovelluksen käyttää todennuslaitteistoa todennukseen"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Tarkan kasvodatan tallennus epäonnistui. Yritä uudelleen."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Liian kirkasta. Kokeile pehmeämpää valaistusta."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Liian pimeää. Kokeile kirkkaampaa valaistusta."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2bdc2f6..f713efb 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permet à l\'appli d\'employer des méthodes d\'aj. et de suppr. de modèles de reconn. visage."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utiliser le matériel d\'authentification de visage"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permet à l\'appli d\'utiliser du matériel de reconnaissance du visage pour l\'authentification"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Imposs. capt. données visage précises. Réessayez."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Trop lumineux. Essayez un éclairage plus faible."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Trop sombre. Essayez avec un éclairage plus fort."</string>
@@ -1919,8 +1925,8 @@
<string name="app_category_productivity" msgid="3742083261781538852">"Productivité"</string>
<string name="device_storage_monitor_notification_channel" msgid="3295871267414816228">"Mémoire de l\'appareil"</string>
<string name="adb_debugging_notification_channel_tv" msgid="5537766997350092316">"Débogage USB"</string>
- <string name="time_picker_hour_label" msgid="2979075098868106450">"heure"</string>
- <string name="time_picker_minute_label" msgid="5168864173796598399">"minute"</string>
+ <string name="time_picker_hour_label" msgid="2979075098868106450">"heures"</string>
+ <string name="time_picker_minute_label" msgid="5168864173796598399">"minutes"</string>
<string name="time_picker_header_text" msgid="143536825321922567">"Définir l\'heure"</string>
<string name="time_picker_input_error" msgid="7574999942502513765">"Entrez une heure valide"</string>
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Entrez l\'heure"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index d3d3c94..fb7b88f 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Autorise l\'appli à invoquer des méthodes pour ajouter et supprimer des modèles de visages."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utiliser le matériel d\'authentification faciale"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Autorise l\'appli à utiliser le matériel d\'authentification faciale pour l\'authentification"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Capture du visage impossible. Réessayez."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Trop lumineux. Essayez de baisser la lumière."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Trop sombre. Essayez une éclairage plus lumineux."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 64c68f4..8c8bcd9 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que a aplicación invoque métodos para engadir e eliminar modelos faciais de uso."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar hardware de autenticación facial"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que a aplicación utilice hardware facial para a autenticación"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Sen datos faciais exactos. Téntao de novo."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Hai demasiada iluminación. Proba cunha máis suave."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Hai demasiada escuridade. Proba con máis luz."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 639a0e0..3c429a3 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ઍપને ઉપયોગ માટે ચહેરાના નમૂના ઉમેરવા અને ડિલીટ કરવાની પદ્ધતિને રદ કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ચહેરા પ્રમાણીકરણના હાર્ડવેરનો ઉપયોગ કરો"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ઍપને પ્રમાણીકરણ માટે ચહેરા પ્રમાણીકરણના હાર્ડવેરનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"ચહેરાનો સચોટ ડેટા કૅપ્ચર ન થયો. ફરી પ્રયાસ કરો."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"અતિશય પ્રકાશિત. થોડો હળવો પ્રકાશ અજમાવી જુઓ."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"અતિશય ઘેરી. વધુ ઝળહળતો પ્રકાશ અજમાવો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 67ef4b3..96b07db 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ऐप्लिकेशन को चेहरे के टेम्पलेट इस्तेमाल के तरीके जोड़ने और मिटाने की मंज़ूरी मिलती है."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"चेहरे की पुष्टि करने वाला हार्डवेयर इस्तेमाल करें"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ऐप्लिकेशन को चेहरे की पुष्टि करने वाले हार्डवेयर का इस्तेमाल करने की मंज़ूरी मिलती है"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"चेहरे से जुड़ा सटीक डेटा कैप्चर नहीं किया जा सका. फिर से कोशिश करें."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"बहुत रोशनी है. हल्की रोशनी आज़माएं."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"बहुत अंधेरा है. बेहतर रोशनी में आज़माएं."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0f2664d..8bfcd17 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -556,6 +556,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Aplikaciji omogućuje pozivanje načina za dodavanje i brisanje predložaka lica za upotrebu."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"upotrebljavati hardver za autentifikaciju lica"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Aplikaciji omogućuje upotrebu hardvera za autentifikaciju lica radi autentifikacije"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Podaci o licu nisu točni. Pokušajte ponovo."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Presvijetlo je. Pokušajte sa slabijim svjetlom."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Pretamno je. Pokušajte s jačim osvjetljenjem."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 7e790b9..4af3e0b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Engedélyezi, hogy az alkalmazás arcsablon-hozzáadási és -törlési metódusokat hívjon."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"arcfelismerő hardver használata"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Engedélyezi, hogy az alkalmazás hitelesítésre használja az arcfelismerő hardvert"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Sikertelen az arc pontos rögzítése. Próbálja újra."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Túl világos. Próbálja kevésbé erős világítással."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Túl sötét. Próbálja jobb megvilágítás mellett."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index e2c00a6..da024b5 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Հավելվածին թույլ է տալիս ավելացնել և հեռացնել դեմքի նմուշներ:"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"օգտագործել դեմքի ճանաչման սարքը"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Հավելվածին թույլ է տալիս օգտագործել նույնականացման համար նախատեսված սարքը"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Չհաջողվեց գրանցել դեմքի ճշգրիտ տվյալները։ Կրկնեք։"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Շատ լուսավոր է։ Փորձեք ավելի թեթև լուսավորություն։"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Շատ մութ է։ Փորձեք ավելի պայծառ լուսավորություն։"</string>
@@ -1122,7 +1128,7 @@
<string name="whichApplicationNamed" msgid="8260158865936942783">"Եզրափակել գործողությունը՝ օգտագործելով %1$s"</string>
<string name="whichApplicationLabel" msgid="7425855495383818784">"Ավարտել գործողությունը"</string>
<string name="whichViewApplication" msgid="3272778576700572102">"Բացել հետևյալ ծրագրով՝"</string>
- <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Բացել ծրագրով՝ %1$s"</string>
+ <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Բացել հավելվածով՝ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Բացել"</string>
<string name="whichGiveAccessToApplication" msgid="8279395245414707442">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթը հղումները բացվեն հետևյալ հավելվածում՝"</string>
<string name="whichGiveAccessToApplicationNamed" msgid="7992388824107710849">"Թույլատրեք, որ <xliff:g id="HOST">%1$s</xliff:g> տիրույթի հղումները բացվեն <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածում"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 9b9222f..b4355cb 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Mengizinkan apl memicu metode untuk menambah & menghapus template wajah untuk digunakan."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gunakan hardware autentikasi wajah"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Mengizinkan aplikasi untuk menggunakan hardware autentikasi wajah untuk autentikasi"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Tidak bisa mengambil data wajah akurat. Coba lagi."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Terlalu terang. Coba cahaya yang lebih lembut."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Terlalu gelap. Coba pencahayaan yang lebih cerah."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index e761e08..30c36ab 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Leyfir forritinu að beita aðferðum til að bæta við og eyða andlitssniðmátum til notkunar."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"nota vélbúnað andlitsgreiningar"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Leyfir forritinu að nota andlitsgreiningarvélbúnað til auðkenningar"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Nákvæm andlitsgögn fengust ekki. Reyndu aftur."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Of bjart. Prófaðu mýkri lýsingu."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Of dimmt. Prófaðu sterkari lýsingu."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index bebb79c..724e0aa 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Consente all\'app di richiamare i metodi per aggiungere e rimuovere i modelli di volti."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utilizza l\'hardware per l\'autenticazione dei volti"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Consente all\'app di utilizzare hardware per l\'autenticazione dei volti"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Impossibile acquisire dati viso accurati. Riprova."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Troppa luce. Prova con una luce più soft."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Troppo buio. Prova con più luce."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 30d9a90..6165910 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -297,7 +297,7 @@
<string name="permgroupdesc_sms" msgid="4656988620100940350">"שליחה והצגה של הודעות SMS"</string>
<string name="permgrouprequest_sms" msgid="7168124215838204719">"לתת לאפליקציה <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> הרשאה לשלוח הודעות SMS ולהציג אותן?"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"אחסון"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"גישה אל תמונות, מדיה וקבצים במכשיר שלך"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"גישה לתמונות, למדיה ולקבצים במכשיר שלך"</string>
<string name="permgrouprequest_storage" msgid="7885942926944299560">"לתת לאפליקציה <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> הרשאת גישה לתמונות, למדיה ולקבצים במכשיר?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"מיקרופון"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"הקלטת אודיו"</string>
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"מאפשרת לאפליקציה להפעיל שיטות להוספה ומחיקה של תבניות פנים שבהן ייעשה שימוש."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"שימוש בחומרה של זיהוי פנים לצורך אימות"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"מאפשרת לאפליקציה להשתמש בחומרה של זיהוי פנים לצורך אימות"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"לא ניתן היה לקלוט את הפנים במדויק. יש לנסות שוב."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"בהיר מדי. צריך תאורה עדינה יותר."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"התמונה חשוכה מדי. צריך תאורה חזקה יותר."</string>
@@ -1347,7 +1353,7 @@
<string name="sms_control_title" msgid="7296612781128917719">"שולח הודעות SMS"</string>
<string name="sms_control_message" msgid="3867899169651496433">"<b> <xliff:g id="APP_NAME">%1$s</xliff:g> </ b> שולח מספר רב של הודעות SMS. האם ברצונך לאפשר לאפליקציה זו להמשיך לשלוח הודעות?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"כן, זה בסדר"</string>
- <string name="sms_control_no" msgid="625438561395534982">"לא, אין מצב"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"עדיף שלא"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> רוצה לשלוח הודעה אל <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
<string name="sms_short_code_details" msgid="5873295990846059400">"הדבר "<b>"עלול לגרום לחיובים"</b>" בחשבון המכשיר הנייד שלך."</string>
<string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"הדבר יגרום לחיובים בחשבון המכשיר הנייד שלך."</b></string>
@@ -1403,7 +1409,7 @@
<string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"שיתוף דוח על באג…"</string>
<string name="share_remote_bugreport_notification_message_finished" msgid="6029609949340992866">"מנהל המערכת ביקש דוח על באג כדי לסייע בפתרון בעיות במכשיר זה. ייתכן שאפליקציות ונתונים ישותפו."</string>
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"שתף"</string>
- <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"לא, אין מצב"</string>
+ <string name="decline_remote_bugreport_action" msgid="6230987241608770062">"עדיף שלא"</string>
<string name="select_input_method" msgid="4653387336791222978">"בחר שיטת הזנה"</string>
<string name="show_ime" msgid="2506087537466597099">"להשאיר במסך בזמן שהמקלדת הפיזית פעילה"</string>
<string name="hardware" msgid="194658061510127999">"הצג מקלדת וירטואלית"</string>
@@ -1482,7 +1488,7 @@
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"האם ברצונך לאפשר בקשה זו?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"בקשת גישה"</string>
<string name="allow" msgid="7225948811296386551">"כן, זה בסדר"</string>
- <string name="deny" msgid="2081879885755434506">"לא, אין מצב"</string>
+ <string name="deny" msgid="2081879885755434506">"עדיף שלא"</string>
<string name="permission_request_notification_title" msgid="6486759795926237907">"בקשת הרשאה"</string>
<string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"נדרשת הרשאה\nלחשבון <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="forward_intent_to_owner" msgid="1207197447013960896">"אתה משתמש באפליקציה זו מחוץ לפרופיל העבודה שלך"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index cc1ab7e..c14b99b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"使用する顔テンプレートの追加や削除を行うメソッドの呼び出しをアプリに許可します。"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"顔認証ハードウェアの使用"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"顔認証ハードウェアを認証に使用することをアプリに許可します"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"顔を認識できませんでした。もう一度お試しください。"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"明るすぎます。もっと暗い場所でお試しください。"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"暗すぎます。もっと明るい場所でお試しください。"</string>
@@ -1058,7 +1064,7 @@
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"この動画はこのデバイスにストリーミングできません。"</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"この動画を再生できません。"</string>
<string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
- <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g> <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>、<xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="noon" msgid="7245353528818587908">"正午"</string>
<string name="Noon" msgid="3342127745230013127">"正午"</string>
<string name="midnight" msgid="7166259508850457595">"午前0時"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 34d218e..d435881 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"საშუალებას აძლევს აპს, დაამატოს და წაშალოს სახეების შაბლონები."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"სახის ამოცნობის აპარატურის გამოყენება"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"საშუალებას აძლევს აპს, ავტორიზაციისთვის გამოიყენოს სახის ამოცნობის აპარატურა"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"სახის ზუსტი მონაცემები არ აღიბეჭდა. ცადეთ ხელახლა."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"მეტისმეტად ნათელია. ცადეთ უფრო სუსტი განათება."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"მეტისმეტად ბნელია. ცადეთ უფრო ძლიერი განათება."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index b8bebe4..2b78e1b 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Қолданбаға пайдаланатын бет үлгілерін енгізу және жою әдістерін шақыруға мүмкіндік береді."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"бетті тану жабдығын пайдалану"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Қолданбаға бетті тану жабдығын қолдануға рұқсат етеді"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Бет деректері дұрыс алынбады. Әрекетті қайталаңыз."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Тым ашық. Күңгірттеу жарық керек."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Тым қараңғы. Молырақ жарық керек."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 0332f39..3f885de 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"អនុញ្ញាតឱ្យកម្មវិធីប្រើវិធីសាស្ត្រដើម្បីបញ្ចូល និងលុបទម្រង់គំរូផ្ទៃមុខសម្រាប់ប្រើប្រាស់។"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ប្រើផ្នែករឹងផ្ទៀងផ្ទាត់ផ្ទៃមុខ"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"អនុញ្ញាតឱ្យកម្មវិធីប្រើផ្នែករឹងផ្ទៀងផ្ទាត់ផ្ទៃមុខសម្រាប់ការផ្ទៀងផ្ទាត់"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"មិនអាចថតទិន្នន័យទម្រង់មុខបានត្រឹមត្រូវទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ភ្លឺពេក។ សូមសាកល្បងប្រើពន្លឺស្រាលជាងនេះ។"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ងងឹតជ្រុល។ សូមសាកល្បងប្រើពន្លឺភ្លឺជាងនេះ។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 22a5bce..88c0c97 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ಬಳಕೆಗೆ ಮುಖದ ಟೆಂಪ್ಲೇಟ್ಗಳನ್ನು ಸೇರಿಸಲು ಮತ್ತು ಅಳಿಸಲು ವಿಧಾನಗಳನ್ನು ಮನವಿ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ಮುಖ ದೃಢೀಕರಣ ಹಾರ್ಡ್ವೇರ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ಧೃಡೀಕರಣಕ್ಕಾಗಿ ಮುಖದ ಹಾರ್ಡ್ವೇರ್ ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"ಸರಿಯಾಗಿ ಮುಖ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಲಾಗಲಿಲ್ಲ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ತುಂಬಾ ಪ್ರಕಾಶಮಾನವಾಗಿದೆ ಮಂದ ಪ್ರಕಾಶಮಾನವಿರುವ ಲೈಟ್ ಬಳಸಿ"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ತುಂಬಾ ಕಪ್ಪು ಛಾಯೆಯಿದೆ. ಪ್ರಕಾಶಮಾನವಾದ ಲೈಟಿಂಗ್ ಬಳಸಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0046527..04fcc88 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"사용할 얼굴 템플릿의 추가 및 삭제 메서드를 앱에서 호출하도록 허용합니다."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"얼굴 인증 하드웨어 사용"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"앱에서 얼굴 인증 하드웨어를 인증에 사용하도록 허용합니다."</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"정확한 얼굴 데이터를 캡처하지 못했습니다. 다시 시도하세요."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"너무 밝습니다. 조명 밝기를 조금 낮춰보세요."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"너무 어둡습니다. 조명을 밝게 해 보세요."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c5c5bf7..92c057a 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Колдонмого пайдалануу үчүн жүздүн үлгүлөрүн кошуу жана жок кылуу мүмкүндүгүн берет."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"жүздүн аныктыгын текшерүүчү аппараттык камсыздоону колдонуу"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Колдонмого аныктыгын текшерүү үчүн жүздүн аныктыгын текшерүүчү аппараттык камсыздоону пайдалануу мүмкүндүгүн берет"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Жүзүңүз жакшы тартылган жок. Кайра аракет кылыңыз."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Өтө жарык. Жарыктыкты азайтып көрүңүз."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Өтө караңгы. Жарыгыраак жерден тартып көрүңүз."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index acfdac8..9dae27a 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ອະນຸຍາດໃຫ້ແອັບເປີດວິທີການຕ່າງໆເພື່ອເພີ່ມ ແລະ ລຶບແມ່ແບບໃບໜ້າສຳລັບການນຳໃຊ້."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ໃຊ້ຮາດແວການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າ"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ຮາດແວການກວດສອບຄວາມຖືກຕ້ອງດ້ວຍໃບໜ້າສຳລັບການກວດສອບຄວາມຖືກຕ້ອງ"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"ບໍ່ສາມາດບັນທຶກຂໍ້ມູນໃບໜ້າທີ່ຖືກຕ້ອງໄດ້. ກະລຸນາລອງໃໝ່."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ແຈ້ງເກີນໄປ. ລອງຄ່ອຍແສງໄຟລົງ."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ມືດເກີນ. ກະລຸນາລອງໃຊ້ສະພາບແສງທີ່ແຈ້ງຂຶ້ນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 3882576..c221e86 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Programai leidžiama aktyv. metodus, norint pridėti ir ištrinti naudojamus veidų šablonus."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"naudoti veido autentifikavimo aparatinę įrangą"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Programai leidžiama naudoti veido autentifikavimo aparatinę įrangą tapatybei nustatyti"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Neužfiks. tikslūs veido duom. Bandykite dar kartą."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Per šviesu. Išbandykite mažesnį apšvietimą."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Per tamsu. Išbandykite šviesesnį apšvietimą."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3063768..94693a6 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -556,6 +556,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Atļauj lietotnei izsaukt metodes izmantojamo sejas veidņu pievienošanai un dzēšanai."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"izmantot sejas autentifikācijas aparatūru"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Atļauj lietotnei izmantot sejas autentifikācijas aparatūru autentificēšanai"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Neizdevās tvert sejas datus. Mēģiniet vēlreiz."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Pārāk spilgts. Izmēģiniet maigāku apgaismojumu."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Pārāk tumšs. Izmēģiniet spožāku apgaismojumu."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 6b465cc..6014443 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Дозволува апликац. да повика начини за додавање и бришење шаблони на лице за користење."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"користи хардвер за проверка на лице"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Дозволува апликацијата да користи хардвер за лице за проверка"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Не се сними прецизна слика. Обидете се повторно."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Премногу светла. Пробајте со послабо осветлување."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Премногу темна. Пробајте со посилно осветлување."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 9e308fb..ba4beee 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ഉപയോഗിക്കാനായി, മുഖത്തിന്റെ ടെംപ്ലേറ്റുകൾ ചേർക്കാനും ഇല്ലാതാക്കാനുമുള്ള രീതികൾ അഭ്യർത്ഥിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"മുഖം തിരിച്ചറിയൽ ഹാർഡ്വെയർ ഉപയോഗിക്കുക"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"പരിശോധിച്ചുറപ്പിക്കലിനായി മുഖം തിരിച്ചറിയൽ ഹാർഡ്വെയർ ഉപയോഗിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"കൃത്യ മുഖ ഡാറ്റ എടുക്കാനായില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"വളരെയധികം തെളിച്ചം. സൗമ്യതയേറിയ പ്രകാശം ശ്രമിക്കൂ."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"വളരെ ഇരുണ്ടത്. തിളക്കമേറിയ ലൈറ്റിംഗ് പരീക്ഷിക്കുക."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index e8344a0..42943b8 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Аппад царайны загварыг ашиглахын тулд нэмэх эсвэл устгах аргыг идэвхжүүлэхийг зөвшөөрдөг."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"царай танилтын техник хангамжийг ашиглах"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Аппад царай танилтын техник хангамжийг баталгаажуулалтад ашиглахыг зөвшөөрдөг"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Царайн өгөгдлийг зөв авч чадсангүй. Дахин оролдоно уу."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Хэт цайвар байна. Гэрэл багатай газар оролдоно уу."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Хэт харанхуй байна. Гэрэлтэй орчинд туршина уу."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 9e82565..789ed86 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"अॅपला वापरासाठी चेहरा टेम्पलेट जोडण्याच्या आणि हटवण्याच्या पद्धती जारी करू देते."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"चेहरा ऑथेंटिकेशन हार्डवेअर वापरा"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"अॅपला चेहरा ऑथेंटिकेशनसाठी ऑथेंटिकेशन हार्डवेअर वापरू देते"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"अचूक फेस डेटा कॅप्चर करता आला नाही. पुन्हा करा."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"खूप प्रखर. आणखी सौम्य प्रकाश वापरून पहा."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"खूप गडद. आणखी प्रखर प्रकाश वापरून पहा."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 4a5dbe0..f3cb1be 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Membenarkan apl menggunakan kaedah untuk menambahkan dan memadamkan templat wajah untuk digunakan."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gunakan perkakasan pengesahan wajah"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Membenarkan apl menggunakan perkakasan pengesahan wajah untuk pengesahan"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Gagal menangkap data wajah dgn tepat. Cuba lagi."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Terlalu terang. Cuba pencahayaan yang lebih lembut."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Terlalu gelap. Cuba pencahayaan yang lebih cerah."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 96bd45a..011eb9a 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"အသုံးပြုရန်အတွက် မျက်နှာပုံစံထည့်ရန် (သို့) ဖျက်ရန်နည်းလမ်းကို အက်ပ်အား သုံးခွင့်ပြုသည်။"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"မျက်နှာအထောက်အထားစိစစ်ခြင်း စက်ပစ္စည်းကို သုံးပါ"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"အထောက်အထားစိစစ်ရန်အတွက် ဤအက်ပ်အား မျက်နှာအထောက်အထားစိစစ်ခြင်း စက်ပစ္စည်းကိုသုံးခွင့်ပြုသည်"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"မျက်နှာဒေတာ အမှန် မရိုက်ယူနိုင်ပါ၊ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"အလွန် လင်းသည်။ အလင်းလျှော့ကြည့်ပါ။"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"အလွန်မှောင်သည်။ ပိုလင်းအောင် လုပ်ကြည့်ပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c01cfb3..025571c 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Lar appen bruke metoder for å legge til og slette ansiktmaler for bruk."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"bruke maskinvare for ansiktsautentisering"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Lar appen bruke maskinvare for ansiktsautentisering til autentisering"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Kunne ikke ta opp nøyaktige ansiktsdata Prøv igjen"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"For lyst. Prøv svakere belysning."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"For mørkt. Prøv sterkere belysning."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0da308f..d8fc560 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"अनुप्रयोगलाई प्रयोगका लागि अनुहार टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"अनुहार प्रमाणिकरण हार्डवेयर प्रयोग गर्नुहोस्"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"अनुप्रयोगलाई प्रमाणीकरणका लागि अनुहार प्रमाणीकरण हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"अनुहारको सटीक डेटा खिच्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ज्यादै चम्किलो। अझ मधुरो प्रकाश प्रयोग गरी हेर्नु…"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ज्यादै अँध्यारो छ। अझ बढी प्रकाशमा गई हेर्नुहोस्"</string>
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 98f209d..cc6a311 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -62,6 +62,19 @@
<item name="listDivider">@color/list_divider_color_dark</item>
</style>
+ <style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.BaseDialog">
+ <!-- Color palette -->
+ <item name="colorPrimary">@color/primary_dark_device_default_settings</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+ <item name="colorSecondary">@color/secondary_device_default_settings</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorError">@color/error_color_device_default_dark</item>
+ <item name="colorBackground">@color/primary_dark_device_default_settings</item>
+
+ <!-- Dialog attributes -->
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+ </style>
+
<!-- Theme for the dialog shown when an app crashes or ANRs. -->
<style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" />
<style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Dialog.Alert" />
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ea954e4..8dc5cfc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Hiermee kan de app methoden aanroepen om gezichtstemplates toe te voegen en te verwijderen voor gebruik."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"hardware voor gezichtsherkenning gebruiken"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Hiermee kan de app hardware voor gezichtsherkenning gebruiken voor verificatie"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Geen accurate gegevens. Probeer het nog eens."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Overbelicht. Probeer een minder felle belichting."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Te donker. Probeer een fellere verlichting."</string>
@@ -936,8 +942,8 @@
<string name="permdesc_setAlarm" msgid="316392039157473848">"Hiermee kan de app een wekker instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"voicemail toevoegen"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Hiermee kan de app berichten toevoegen aan de inbox van je voicemail."</string>
- <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"geolocatiemachtigingen voor browser aanpassen"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Hiermee kan de app de geolocatiemachtigingen van de browser aanpassen. Schadelijke apps kunnen dit gebruiken om locatiegegevens te verzenden naar willekeurige websites."</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"geolocatierechten voor browser aanpassen"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Hiermee kan de app de geolocatierechten van de browser aanpassen. Schadelijke apps kunnen dit gebruiken om locatiegegevens te verzenden naar willekeurige websites."</string>
<string name="save_password_message" msgid="767344687139195790">"Wil je dat de browser dit wachtwoord onthoudt?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
@@ -1331,7 +1337,7 @@
<string name="date_time_done" msgid="2507683751759308828">"Gereed"</string>
<string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NIEUW: "</font></string>
<string name="perms_description_app" msgid="5139836143293299417">"Geleverd door <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
- <string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
+ <string name="no_permissions" msgid="7283357728219338112">"Geen rechten nodig"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"hieraan kunnen kosten zijn verbonden"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<string name="usb_charging_notification_title" msgid="1595122345358177163">"Dit apparaat wordt opgeladen via USB"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 0c43569..44d721c 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ବ୍ୟବହାର ପାଇଁ ଆପ୍କୁ ଫେସିଆଲ୍ ଟେମ୍ପଲେଟ୍ ଯୋଡିବା ଓ ଡିଲିଟ୍ ର ପଦ୍ଧତି ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ଫେସ୍ ପ୍ରମାଣୀକରଣ ହାର୍ଡୱେର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ଫେସ୍ ପ୍ରମାଣୀକରଣ ହାର୍ଡୱେର୍ର ପ୍ରମାଣ ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"ମୁହଁର ଡାଟା କ୍ୟାପଚର୍ ହେଲାନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ଅତ୍ୟଧିକ ଉଜ୍ଵଳ। କମ୍ ଉଜ୍ବଳକରଣରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ଅତ୍ୟଧିକ ଅନ୍ଧକାର। ଉଜ୍ବଳ ଲାଇଟ୍ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 474b7d6..6662ad8 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ਐਪ ਨੂੰ ਵਰਤਣ ਲਈ ਚਿਹਰਾ ਟੈਮਪਲੇਟ ਸ਼ਾਮਲ ਕਰਨ ਜਾਂ ਮਿਟਾਉਣ ਦੀਆਂ ਵਿਧੀਆਂ ਦੀ ਬੇਨਤੀ ਕਰਨ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਰਨ ਹਾਰਡਵੇਅਰ ਵਰਤੋ"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ਐਪ ਨੂੰ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਚਿਹਰਾ ਪ੍ਰਮਾਣੀਕਰਨ ਹਾਰਡਵੇਅਰ ਵਰਤਣ ਦਿੰਦੀ ਹੈ"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"ਸਟੀਕ ਚਿਹਰਾ ਡਾਟਾ ਕੈਪਚਰ ਨਹੀਂ ਹੋਇਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ। ਹਲਕੀ ਚਮਕ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ਬਹੁਤ ਗੂੜ੍ਹਾ। ਤੇਜ਼ ਰੋਸ਼ਨੀ ਕਰਕੇ ਦੇਖੋ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index caf7eb6..1b096da 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Zezwala na aktywowanie przez aplikację metody dodawania i usuwania szablonów twarzy."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"używanie sprzętu do uwierzytelniania za pomocą twarzy"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Zezwala na używanie przez aplikację sprzętu do analizy twarzy na potrzeby uwierzytelniania"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Nie udało się zarejestrować danych twarzy. Spróbuj ponownie."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Zbyt jasno. Spróbuj przy słabszym świetle."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Zbyt ciemno. Spróbuj w jaśniejszym świetle."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 3129e12..d3cc969 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que o app execute métodos para adicionar e excluir modelos de rosto para uso."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar hardware de autenticação facial"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que o app use o hardware de autenticação facial para autenticação"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Dados precisos não capturados. Tente novamente."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Muito iluminado. Diminua a iluminação."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Muito escuro. Use uma iluminação mais clara."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2fc483c..8bd1054 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permite à aplicação invocar métodos para adicionar e eliminar modelos faciais para uso."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"utilizar hardware de autenticação facial"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que a aplicação utilize hardware de autenticação facial para autenticação."</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Imp. capt. dados rosto precisos. Tente novamente."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Demasiado clara. Experimente uma luz mais suave."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Demasiado escura. Experimente local com mais luz."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3129e12..d3cc969 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permite que o app execute métodos para adicionar e excluir modelos de rosto para uso."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"usar hardware de autenticação facial"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite que o app use o hardware de autenticação facial para autenticação"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Dados precisos não capturados. Tente novamente."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Muito iluminado. Diminua a iluminação."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Muito escuro. Use uma iluminação mais clara."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2111707..62a090b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -556,6 +556,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Permite aplicației să invoce metode pentru a adăuga și a șterge șabloane faciale pentru utilizare."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"să folosească hardware de autentificare facială"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Permite aplicației să folosească hardware de autentificare facială pentru autentificare"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Nu s-a putut fotografia fața cu precizie. Încercați din nou."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Prea luminos. Încercați o lumină mai slabă."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Prea întunecat. Încercați o lumină mai puternică."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7216112..7b7c547 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Приложение сможет добавлять и удалять шаблоны лиц."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"Использовать оборудование для распознавания лиц"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Приложение сможет использовать распознающее оборудование для аутентификации."</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Не удалось собрать данные. Повторите попытку."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Слишком светло. Сделайте освещение менее ярким."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Слишком темно. Сделайте освещение ярче."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index f28d334..70740b9 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"මුහුණු අච්චු එකතු කිරීමට සහ ඉවත් කිරීමට අදාළ ක්රම භාවිතය සඳහා මෙම යෙදුමට ඉඩ දෙයි."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"මුහුණු සත්යාපක දෘඪාංග භාවිතා කරන්න"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"සත්යාපනය සඳහා සත්යාපක දෘඪාංග භාවිත කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"නිරවද්ය මුහුණු දත්ත ගත නොහැකි විය. නැවත උත්සාහ කරන්න."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"දීප්තිය වැඩියි. තවත් මඳ ආලෝකය උත්සාහ කරන්න."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"ඉතා අඳුරුයි. තවත් දීප්තිමත් ආලෝකය උත්සාහ කරන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 412eef4..43a6744 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Umožňuje aplikácii vyvolať metódy, ktoré pridávajú a odstraňujú šablóny tvárí."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"používanie hardvéru na overenie tváre"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Umožňuje aplikácii používať na overenie totožnosti hardvér na overenie tváre"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Nepodarilo sa nasnímať presné údaje o tvári. Skúste to znova."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Príliš veľa svetla. Skúste jemnejšie osvetlenie."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Príliš veľká tma. Skúste lepšie osvetlenie."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index f7c3168..904ad3c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Aplikaciji omogoča sprožanje načinov za dodajanje in brisanje predlog z obrazi za uporabo."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"uporaba strojne opreme za preverjanje pristnosti obraza"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Aplikaciji omogoča uporabo strojne opreme za preverjanje pristnosti obraza"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Točnih podatkov o obrazu ni bilo mogoče zajeti. Poskusite znova."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Presvetlo. Poskusite z blažjo osvetlitvijo."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Pretemno. Poskusite z močnejšo osvetlitvijo."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index e0d29bc..ad58352 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Lejon aplikacionin të aktivizojë mënyra për shtim e fshirje të shablloneve të përdorura."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"përdor harduerin për vërtetimin e fytyrës"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Lejon aplikacionin të përdorë harduer vërtetimi të fytyrës për procesin e vërtetimit"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"S\'mund të regjistroheshin të dhëna të sakta të fytyrës. Provo përsëri."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Me shumë ndriçim. Provo një ndriçim më të butë."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Shumë i errët. Provo një ndriçim më të fortë."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 454cc9c..abe1809bf 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -556,6 +556,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Дозвољава да апликација активира методе за додавање и брисање шаблона лица ради коришћења."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"коришћење хардв. за потврду идентитета помоћу лица"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Дозвољава да апликација користи хардвер за потврду идентитета помоћу лица"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Снимање лица није успело. Пробајте поново."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Превише је светло. Пробајте са слабијим осветљењем."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Претамно је. Пробајте са јачим осветљењем."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index c55bcb0..3a84c8a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Tillåter att appen anropar metoder för att lägga till och radera ansiktsmallar."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"använda maskinvara för ansiktsautentisering"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Tillåter att appen använder maskinvara för ansiktsigenkänning vid autentisering"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Det gick inte att fånga ansiktsdata. Försök igen."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Det är för ljust. Testa lägre belysning."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Det är för mörkt. Testa med bättre belysning."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 9702f62..1f7f1ac 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Huruhusu programu iombe njia za kuongeza na kufuta violezo vya uso vitakavyotumiwa."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"tumia maunzi ya kuthibistiha uso"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Huruhusu programu ithibitishe uso kwa kutumia maunzi ya kuthibitisha"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Imeshindwa kunasa data sahihi ya uso. Jaribu tena."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Inang\'aa mno. Jaribu mwangaza hafifu"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Hakuna mwangaza wa kutosha. Jaribu kuongeza mwangaza."</string>
@@ -1472,7 +1478,7 @@
<string name="disable_tether_notification_title" msgid="7526977944111313195">"Umezima kipengele cha kusambaza mtandao"</string>
<string name="disable_tether_notification_message" msgid="2913366428516852495">"Wasiliana na msimamizi wako ili upate maelezo zaidi"</string>
<string name="back_button_label" msgid="2300470004503343439">"Nyuma"</string>
- <string name="next_button_label" msgid="1080555104677992408">"Ifuatayo"</string>
+ <string name="next_button_label" msgid="1080555104677992408">"Endelea"</string>
<string name="skip_button_label" msgid="1275362299471631819">"Ruka"</string>
<string name="no_matches" msgid="8129421908915840737">"Hakuna vinavyolingana"</string>
<string name="find_on_page" msgid="1946799233822820384">"Pata kwenye ukurasa"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 0602594..5a24e4a 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -348,9 +348,9 @@
<string name="permlab_sendSms" msgid="7544599214260982981">"SMS செய்திகளை அனுப்புதல் மற்றும் பார்த்தல்"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"SMS செய்திகளை அனுப்ப பயன்பாட்டை அனுமதிக்கிறது. இதற்கு எதிர்பாராத பேமெண்ட்கள் விதிக்கப்படலாம். தீங்கு விளைவிக்கும் பயன்பாடுகள் உங்களின் உறுதிப்படுத்தல் எதுவுமின்றி செய்திகளை அனுப்பி உங்களுக்குக் கட்டணம் விதிக்கலாம்."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"உங்கள் உரைச் செய்திகளை (SMS அல்லது MMS) படித்தல்"</string>
- <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"இந்தப் பயன்பாடு உங்கள் டேப்லெட்டில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
- <string name="permdesc_readSms" product="tv" msgid="5796670395641116592">"இந்தப் பயன்பாடு உங்கள் டிவியில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
- <string name="permdesc_readSms" product="default" msgid="6826832415656437652">"இந்தப் பயன்பாடு உங்கள் மொபைலில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"இந்த ஆப்ஸ் உங்கள் டேப்லெட்டில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
+ <string name="permdesc_readSms" product="tv" msgid="5796670395641116592">"இந்த ஆப்ஸ் உங்கள் டிவியில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
+ <string name="permdesc_readSms" product="default" msgid="6826832415656437652">"இந்த ஆப்ஸ் உங்கள் மொபைலில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"உரைச் செய்திகளைப் (WAP) பெறுதல்"</string>
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"WAP செய்திகளைப் பெற, செயற்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது. உங்களுக்கு அனுப்பப்படும் செய்திகளை உங்களுக்குக் காட்டாமல் கண்காணிக்க அல்லது நீக்குவதற்கான திறன் இந்த அனுமதியில் உள்ளடங்கும்."</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"இயங்கும் பயன்பாடுகளை மீட்டெடுத்தல்"</string>
@@ -363,12 +363,12 @@
<string name="permdesc_enableCarMode" msgid="4853187425751419467">"கார் முறையை இயக்க, பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"பிற பயன்பாடுகளை மூடுதல்"</string>
<string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"பிற பயன்பாடுகளின் பின்புலச் செயல்முறைகளை நிறுத்த பயன்பாட்டை அனுமதிக்கிறது. இதனால் பிற பயன்பாடுகள் இயங்குவதை நிறுத்தலாம்."</string>
- <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"இந்தப் பயன்பாடு பிற பயன்பாடுகளின் மேலே தோன்றலாம்"</string>
- <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"இந்தப் பயன்பாடு பிற பயன்பாடுகளின் மேலே அல்லது திரையின் பிற பகுதிகளில் தோன்றலாம். இது வழக்கமான பயன்பாட்டு உபயோகத்தில் குறுக்கிட்டு, பிற பயன்பாடுகள் தோன்றும் விதத்தை மாற்றக்கூடும்."</string>
+ <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"இந்த ஆப்ஸ் பிற பயன்பாடுகளின் மேலே தோன்றலாம்"</string>
+ <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"இந்த ஆப்ஸ் பிற பயன்பாடுகளின் மேலே அல்லது திரையின் பிற பகுதிகளில் தோன்றலாம். இது வழக்கமான பயன்பாட்டு உபயோகத்தில் குறுக்கிட்டு, பிற பயன்பாடுகள் தோன்றும் விதத்தை மாற்றக்கூடும்."</string>
<string name="permlab_runInBackground" msgid="7365290743781858803">"பின்னணியில் இயக்கு"</string>
- <string name="permdesc_runInBackground" msgid="7370142232209999824">"இந்தப் பயன்பாடு, பின்னணியில் இயங்கலாம். இதனால் பேட்டரி விரைவாகத் தீர்ந்துவிடக்கூடும்."</string>
+ <string name="permdesc_runInBackground" msgid="7370142232209999824">"இந்த ஆப்ஸ், பின்னணியில் இயங்கலாம். இதனால் பேட்டரி விரைவாகத் தீர்ந்துவிடக்கூடும்."</string>
<string name="permlab_useDataInBackground" msgid="8694951340794341809">"பின்னணியில் தரவைப் பயன்படுத்து"</string>
- <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"இந்தப் பயன்பாடு, பின்னணியில் டேட்டாவை உபயோகிக்கலாம். இதனால் டேட்டா உபயோகம் அதிகரிக்கக்கூடும்."</string>
+ <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"இந்த ஆப்ஸ், பின்னணியில் டேட்டாவை உபயோகிக்கலாம். இதனால் டேட்டா உபயோகம் அதிகரிக்கக்கூடும்."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"பயன்பாட்டை எப்போதும் இயங்குமாறு செய்தல்"</string>
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"நினைவகத்தில் நிலையாக இருக்கும் தன்னுடைய பகுதிகளை உருவாக்கப் பயன்பாட்டை அனுமதிக்கிறது. இதனால பிற பயன்பாடுகளுக்குக் கிடைக்கும் நினைவகம் வரையறுக்கப்பட்டு, டேப்லெட்டின் வேகத்தைக் குறைக்கலாம்."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"பயன்பாடு தனது உள்ளடக்கத்தை நினைவகத்தில் தொடர்ந்து வைத்திருக்க, அனுமதிக்கிறது. பிற பயன்பாடுகளுக்கென இருக்கும் நினைவகத்தை இது கட்டுப்படுத்தி, டிவியின் செயல்திறனைக் குறைக்கலாம்."</string>
@@ -396,7 +396,7 @@
<string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"உங்கள் டிவியில் சேமிக்கப்பட்ட தொடர்புகள் பற்றிய தரவை மாற்ற, பயன்பாட்டை அனுமதிக்கிறது, இதில் குறிப்பிட்ட தொடர்பை எத்தனைமுறை அழைத்தீர்கள், மின்னஞ்சல் செய்தீர்கள் அல்லது பிறவழிகளில் தொடர்புகொண்டீர்கள் என்பதும் அடங்கும். இது தொடர்புத் தரவை நீக்க, பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"குறிப்பிட்ட தொடர்புகளுடன் நீங்கள் அழைத்த, மின்னஞ்சல் அனுப்பிய அல்லது வேறு வழியில் தொடர்புகொண்டதின் எண்ணிக்கை உள்பட, உங்கள் மொபைலில் சேமிக்கப்பட்ட உங்கள் தொடர்புகள் குறித்த தரவைத் திருத்த பயன்பாட்டை அனுமதிக்கிறது. இந்த அனுமதியானது தொடர்புத் தரவை நீக்கப் பயன்பாடுகளை அனுமதிக்கிறது."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"அழைப்புப் பதிவைப் படித்தல்"</string>
- <string name="permdesc_readCallLog" msgid="3204122446463552146">"இந்தப் பயன்பாடு உங்கள் அழைப்பு வரலாற்றைப் படிக்கலாம்."</string>
+ <string name="permdesc_readCallLog" msgid="3204122446463552146">"இந்த ஆப்ஸ் உங்கள் அழைப்பு வரலாற்றைப் படிக்கலாம்."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"அழைப்புப் பதிவை எழுதுதல்"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"உள்வரும் மற்றும் வெளிச்செல்லும் அழைப்புகள் குறித்த தகவல் உள்பட உங்கள் டேப்லெட்டின் அழைப்புப் பதிவைத் திருத்துவதற்குப் பயன்பாட்டை அனுமதிக்கிறது. உங்கள் அழைப்பின் பதிவை அழிக்க அல்லது திருத்த தீங்கு விளைவிக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"உள்வரும் மற்றும் வெளிச்செல்லும் அழைப்புகள் குறித்த தகவல் உள்ளிட்ட உங்கள் டிவியின் அழைப்பு பதிவைத் திருத்த, பயன்பாட்டை அனுமதிக்கிறது. உங்கள் அழைப்பு பதிவை அழிக்க அல்லது திருத்த தீங்கு விளைவிக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
@@ -404,13 +404,13 @@
<string name="permlab_bodySensors" msgid="4683341291818520277">"உடல் உணர்விகளை (இதயத் துடிப்பு மானிட்டர்கள் போன்றவை) அணுகுதல்"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"உங்கள் இதயத்துடிப்பு விகிதம் போன்ற உங்கள் உடல்நிலையைக் கண்காணிக்கும் உணர்விகளில் இருந்து தரவை அணுக பயன்பாடுகளை அனுமதிக்கும்."</string>
<string name="permlab_readCalendar" msgid="6716116972752441641">"கேலெண்டர் நிகழ்வுகளையும் விவரங்களையும் படிக்கலாம்"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"இந்தப் பயன்பாடு உங்கள் டேப்லெட்டில் சேமிக்கப்பட்டுள்ள கேலெண்டர் நிகழ்வுகள் அனைத்தையும் படிக்கலாம், உங்கள் கேலெண்டர் தரவைப் பகிரலாம் அல்லது சேமிக்கலாம்."</string>
- <string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"இந்தப் பயன்பாடு உங்கள் டிவியில் சேமிக்கப்பட்டுள்ள எல்லா கேலெண்டர் நிகழ்வுகளையும் படிக்கலாம், உங்கள் கேலெண்டர் தரவைப் பகிரலாம் அல்லது சேமிக்கலாம்."</string>
- <string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"இந்தப் பயன்பாடு உங்கள் மொபைலில் சேமிக்கப்பட்டுள்ள கேலெண்டர் நிகழ்வுகள் அனைத்தையும் படிக்கலாம், உங்கள் கேலெண்டர் தரவைப் பகிரலாம் அல்லது சேமிக்கலாம்."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"இந்த ஆப்ஸ் உங்கள் டேப்லெட்டில் சேமிக்கப்பட்டுள்ள கேலெண்டர் நிகழ்வுகள் அனைத்தையும் படிக்கலாம், உங்கள் கேலெண்டர் தரவைப் பகிரலாம் அல்லது சேமிக்கலாம்."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"இந்த ஆப்ஸ் உங்கள் டிவியில் சேமிக்கப்பட்டுள்ள எல்லா கேலெண்டர் நிகழ்வுகளையும் படிக்கலாம், உங்கள் கேலெண்டர் தரவைப் பகிரலாம் அல்லது சேமிக்கலாம்."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"இந்த ஆப்ஸ் உங்கள் மொபைலில் சேமிக்கப்பட்டுள்ள கேலெண்டர் நிகழ்வுகள் அனைத்தையும் படிக்கலாம், உங்கள் கேலெண்டர் தரவைப் பகிரலாம் அல்லது சேமிக்கலாம்."</string>
<string name="permlab_writeCalendar" msgid="8438874755193825647">"உரிமையாளருக்குத் தெரியாமல் கேலெண்டர் நிகழ்வுகளைச் சேர்த்தல் அல்லது மாற்றுதல் மற்றும் விருந்தினர்களுக்கு மின்னஞ்சல் அனுப்புதல்"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="1675270619903625982">"இந்தப் பயன்பாடு உங்கள் டேப்லெட்டில் கேலெண்டர் நிகழ்வுகளைச் சேர்க்கலாம், அகற்றலாம் அல்லது மாற்றலாம். இந்தப் பயன்பாடு கேலெண்டர் உரிமையாளர்கள் அனுப்பியது போல் தோன்றும் செய்திகளை அனுப்பலாம் அல்லது உரிமையாளர்களிடம் தெரிவிக்காமலே கேலெண்டரில் நிகழ்வுகளை மாற்றலாம்."</string>
- <string name="permdesc_writeCalendar" product="tv" msgid="9017809326268135866">"இந்தப் பயன்பாடு உங்கள் டிவியில் கேலெண்டர் நிகழ்வுகளைச் சேர்க்கலாம், அகற்றலாம் அல்லது மாற்றலாம். இந்தப் பயன்பாடு கேலெண்டர் உரிமையாளர்கள் அனுப்பியது போல் தோன்றும் செய்திகளை அனுப்பலாம் அல்லது உரிமையாளர்களிடம் தெரிவிக்காமலே கேலெண்டரில் நிகழ்வுகளை மாற்றலாம்."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"இந்தப் பயன்பாடு உங்கள் மொபைலில் கேலெண்டர் நிகழ்வுகளைச் சேர்க்கலாம், அகற்றலாம் அல்லது மாற்றலாம். இந்தப் பயன்பாடு கேலெண்டர் உரிமையாளர்கள் அனுப்பியது போல் தோன்றும் செய்திகளை அனுப்பலாம் அல்லது உரிமையாளர்களிடம் தெரிவிக்காமலே கேலெண்டரில் நிகழ்வுகளை மாற்றலாம்."</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="1675270619903625982">"இந்த ஆப்ஸ் உங்கள் டேப்லெட்டில் கேலெண்டர் நிகழ்வுகளைச் சேர்க்கலாம், அகற்றலாம் அல்லது மாற்றலாம். இந்த ஆப்ஸ் கேலெண்டர் உரிமையாளர்கள் அனுப்பியது போல் தோன்றும் செய்திகளை அனுப்பலாம் அல்லது உரிமையாளர்களிடம் தெரிவிக்காமலே கேலெண்டரில் நிகழ்வுகளை மாற்றலாம்."</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="9017809326268135866">"இந்த ஆப்ஸ் உங்கள் டிவியில் கேலெண்டர் நிகழ்வுகளைச் சேர்க்கலாம், அகற்றலாம் அல்லது மாற்றலாம். இந்த ஆப்ஸ் கேலெண்டர் உரிமையாளர்கள் அனுப்பியது போல் தோன்றும் செய்திகளை அனுப்பலாம் அல்லது உரிமையாளர்களிடம் தெரிவிக்காமலே கேலெண்டரில் நிகழ்வுகளை மாற்றலாம்."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"இந்த ஆப்ஸ் உங்கள் மொபைலில் கேலெண்டர் நிகழ்வுகளைச் சேர்க்கலாம், அகற்றலாம் அல்லது மாற்றலாம். இந்த ஆப்ஸ் கேலெண்டர் உரிமையாளர்கள் அனுப்பியது போல் தோன்றும் செய்திகளை அனுப்பலாம் அல்லது உரிமையாளர்களிடம் தெரிவிக்காமலே கேலெண்டரில் நிகழ்வுகளை மாற்றலாம்."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"கூடுதல் இட வழங்குநரின் கட்டளைகளின் அணுகல்"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"கூடுதல் இட வழங்குநர் கட்டளைகளை அணுகப் பயன்பாட்டை அனுமதிக்கிறது. இது, GPS அல்லது பிற இருப்பிட மூலங்களின் செயல்பாட்டை இடைமறிக்க பயன்பாட்டை அனுமதிக்கலாம்."</string>
<string name="permlab_accessFineLocation" msgid="6265109654698562427">"முன்புலத்தில் இயங்கும்போது மட்டும் துல்லியமான இருப்பிடத்தைக் கண்டறிதல்"</string>
@@ -424,13 +424,13 @@
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"எனது ஆடியோ அமைப்புகளை மாற்றுதல்"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ஒலியளவு மற்றும் வெளியீட்டிற்கு ஸ்பீக்கர்கள் பயன்படுத்தப்படுவது போன்ற ஒட்டுமொத்த ஆடியோ அமைப்புகளைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"ஆடியோவைப் பதிவுசெய்தல்"</string>
- <string name="permdesc_recordAudio" msgid="4245930455135321433">"இந்தப் பயன்பாடு எப்போது வேண்டுமானாலும் மைக்ரோஃபோனைப் பயன்படுத்தி ஆடியோவை ரெக்கார்டு செய்யலாம்."</string>
+ <string name="permdesc_recordAudio" msgid="4245930455135321433">"இந்த ஆப்ஸ் எப்போது வேண்டுமானாலும் மைக்ரோஃபோனைப் பயன்படுத்தி ஆடியோவை ரெக்கார்டு செய்யலாம்."</string>
<string name="permlab_sim_communication" msgid="2935852302216852065">"கட்டளைகளை சிம்மிற்கு அனுப்புதல்"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"சிம் க்குக் கட்டளைகளை அனுப்ப பயன்பாட்டை அனுமதிக்கிறது. இது மிகவும் ஆபத்தானதாகும்."</string>
<string name="permlab_activityRecognition" msgid="3634590230567608356">"உடல் செயல்பாட்டைக் கண்டறிதல்"</string>
<string name="permdesc_activityRecognition" msgid="3143453925156552894">"உங்கள் உடல் செயல்பாட்டை இந்த ஆப்ஸால் கண்டறிய முடியும்."</string>
<string name="permlab_camera" msgid="3616391919559751192">"படங்கள் மற்றும் வீடியோக்களை எடுத்தல்"</string>
- <string name="permdesc_camera" msgid="5392231870049240670">"இந்தப் பயன்பாடு எப்போது வேண்டுமானாலும் கேமராவைப் பயன்படுத்தி படங்களை எடுக்கலாம், வீடியோக்களை ரெக்கார்டு செய்யலாம்."</string>
+ <string name="permdesc_camera" msgid="5392231870049240670">"இந்த ஆப்ஸ் எப்போது வேண்டுமானாலும் கேமராவைப் பயன்படுத்தி படங்களை எடுக்கலாம், வீடியோக்களை ரெக்கார்டு செய்யலாம்."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"அதிர்வைக் கட்டுப்படுத்துதல்"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"அதிர்வைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string>
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"உபயோகிப்பதற்காக முக டெம்ப்ளேட்டுகளை சேர்க்கும்/நீக்கும் முறைகளை இயக்க, ஆப்ஸை அனுமதிக்கும்."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"முக அங்கீகாரத்திற்கான வன்பொருளைப் பயன்படுத்துதல்"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"அடையாளம் காண்பதற்கு, முக அங்கீகார வன்பொருளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கிறது"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"முகம் தெளிவாகப் பதிவாகவில்லை. மீண்டும் முயலவும்."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"அதிக ஒளிர்வு. மிதமான ஒளியில் முயலவும்."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"இருட்டாக உள்ளது. பிரகாசமான ஒளியில் முயலவும்."</string>
@@ -1892,7 +1898,7 @@
<string name="work_mode_off_title" msgid="1118691887588435530">"பணிச் சுயவிவரத்தை ஆன் செய்யவா?"</string>
<string name="work_mode_off_message" msgid="5130856710614337649">"பணி ஆப்ஸ், அறிவிப்புகள், தரவு மற்றும் பிற பணிச் சுயவிவர அம்சங்கள் ஆன் செய்யப்படும்"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"இயக்கு"</string>
- <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"இந்தப் பயன்பாடு Android இன் பழைய பதிப்புக்காக உருவாக்கப்பட்டதால், சரியாக வேலை செய்யாமல் போகலாம். புதுப்பிப்புகள் ஏதேனும் உள்ளதா எனப் பார்க்கவும் அல்லது டெவெலப்பரைத் தொடர்புகொள்ளவும்."</string>
+ <string name="deprecated_target_sdk_message" msgid="1449696506742572767">"இந்த ஆப்ஸ் Android இன் பழைய பதிப்புக்காக உருவாக்கப்பட்டதால், சரியாக வேலை செய்யாமல் போகலாம். புதுப்பிப்புகள் ஏதேனும் உள்ளதா எனப் பார்க்கவும் அல்லது டெவெலப்பரைத் தொடர்புகொள்ளவும்."</string>
<string name="deprecated_target_sdk_app_store" msgid="5032340500368495077">"புதுப்பிப்பு உள்ளதா எனப் பார்"</string>
<string name="new_sms_notification_title" msgid="8442817549127555977">"புதிய செய்திகள் வந்துள்ளன"</string>
<string name="new_sms_notification_content" msgid="7002938807812083463">"பார்க்க, SMS பயன்பாட்டைத் திறக்கவும்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 09c9561..312e615 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"వినియోగం కోసం ముఖ టెంప్లేట్లను జోడించే మరియు తొలగించే పద్ధతులను అమలు చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ముఖ ప్రమాణీకరణ హార్డ్వేర్ను వాడండి"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ప్రమాణీకరణ కోసం ముఖ ప్రామాణీకరణ హార్డ్వేర్ను ఉపయోగించడానికి యాప్ని అనుమతిస్తుంది"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"ముఖం డేటా సరిగ్గా రాలేదు. మళ్లీ ప్రయత్నించండి."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"వెలుతురు అధికంగా ఉంది. తక్కువ ఉండేలా చూడండి."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"చాలా చీకటిగా ఉంది. బాగా వెలుతురులో ప్రయత్నించండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a1b7e15..500e9c3 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"อนุญาตให้แอปเรียกใช้วิธีเพิ่มและลบเทมเพลตใบหน้าสำหรับการใช้งาน"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"ใช้ฮาร์ดแวร์ตรวจสอบสิทธิ์ด้วยใบหน้า"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"อนุญาตให้แอปใช้ฮาร์ดแวร์ตรวจสอบสิทธิ์ด้วยใบหน้าเพื่อตรวจสอบสิทธิ์"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"บันทึกข้อมูลใบหน้าที่ถูกต้องไม่ได้ ลองอีกครั้ง"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"สว่างเกินไป ลองหาตำแหน่งที่แสงน้อยกว่านี้"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"มืดเกินไป ลองหาตำแหน่งที่สว่างขึ้น"</string>
@@ -975,7 +981,7 @@
<string name="last_month" msgid="3959346739979055432">"เดือนที่แล้ว"</string>
<string name="older" msgid="5211975022815554840">"เก่ากว่า"</string>
<string name="preposition_for_date" msgid="9093949757757445117">"ในวันที่ <xliff:g id="DATE">%s</xliff:g>"</string>
- <string name="preposition_for_time" msgid="5506831244263083793">"ที่ <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="preposition_for_time" msgid="5506831244263083793">"<xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ใน <xliff:g id="YEAR">%s</xliff:g>"</string>
<string name="day" msgid="8144195776058119424">"วัน"</string>
<string name="days" msgid="4774547661021344602">"วัน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index ea18ba7..efa6339 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -301,7 +301,7 @@
<string name="permgrouprequest_activityRecognition" msgid="7626438016904799383">"Payagan ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na i-access ang iyong pisikal na aktibidad?"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Camera"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"kumuha ng mga larawan at mag-record ng video"</string>
- <string name="permgrouprequest_camera" msgid="1299833592069671756">"Payagan ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na kumuha ng mga larawan at mag-record ng video?"</string>
+ <string name="permgrouprequest_camera" msgid="1299833592069671756">"Payagan ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na kumuha ng larawan at mag-record ng video?"</string>
<string name="permgrouplab_calllog" msgid="8798646184930388160">"Mga log ng tawag"</string>
<string name="permgroupdesc_calllog" msgid="3006237336748283775">"binabasa at sinusulat ang log ng tawag sa telepono"</string>
<string name="permgrouprequest_calllog" msgid="8487355309583773267">"Payagan ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> na i-access ang iyong mga log ng tawag sa telepono?"</string>
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Pumapayag na mag-invoke ang app ng paraang magdagdag at mag-delete ng template ng mukha."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"gumamit ng hardware sa pag-authenticate ng mukha"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Pumapayag na gumamit ng face authentication hardware ang app para sa pag-authenticate"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Hindi makakuha ng tamang face data. Subukang muli."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Masyadong maliwanag. Subukang bawasan ang liwanag."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Masyadong madilim. Subukan sa mas maliwanag."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 4517ed1..50c5168 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Uygulamanın, kullanılacak yüz şablonlarını ekleme ve silme yöntemlerini başlatmasına izin verir."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"yüz kimlik doğrulaması donanımını kullanma"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Uygulamanın yüz kimlik doğrulaması donanımı kullanmasına izin verir"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Doğru yüz verileri yakalanamadı. Tekrar deneyin."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Çok parlak. Parlaklığı daha az bir ışıklandırma deneyin."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Çok karanlık. Daha parlak ışıkta deneyin."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index c923a3d..f39a0eff 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -559,6 +559,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Додаток може активувати способи додавання й видалення шаблонів облич."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"застосовувати обладнання для автентифікації облич"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Додаток може застосовувати обладнання для автентифікації облич"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Не вдалося чітко зняти обличчя. Повторіть спробу."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Занадто яскраво. Потрібно менше світла."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Занадто темно. Потрібно більше світла."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 8c1ced6f..64379c9 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"ایپ کو چہرے کی تمثیلات شامل اور حذف کرنے کے طریقوں کو کالعدم قرار دینے کی اجازت دیتا ہے۔"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"چہرے کی توثیق کا ہارڈویئر استعمال کریں"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"ایپ کو توثیق کیلئے چہرے کا ہارڈ ویئر استعمال کرنے کی اجازت دیتا ہے"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"چہرے کا درست ڈيٹا کیپچر نہیں ہو سکا۔ پھر آزمائيں۔"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"کافی روشنی ہے۔ ہلکی روشنی میں آزمائیں۔"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"کافی اندھیرا ہے۔ تیز روشنی میں آزمائیں۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index cc5c492..c91ba57 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Ilova foydalanish uchun yuz namunalarini qo‘shish va o‘chirish usullarini tatbiq qilishi mumkin."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"yuzni aniqlash qurilmasidan foydalanish"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Haqiqiylikni tekshirish uchun skanerdan foydalanish imkonini beradi"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Yuz ravshan suratga olinmadi. Qaytadan urining."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Juda yorqin. Biroz soyaroq joy tanlang."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Juda qorongʻi. Atrofingizni yoriting."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 14d0e28..0ba50b3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Cho phép ứng dụng gọi ra các phương pháp để thêm và xóa mẫu khuôn mặt sử dụng."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"sử dụng phần cứng xác thực khuôn mặt"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Cho phép ứng dụng sử dụng phần cứng xác thực khuôn mặt để tiến hành xác thực"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Không thể ghi lại đúng dữ liệu mặt. Hãy thử lại."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Quá sáng. Hãy thử giảm độ sáng."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Quá tối. Hãy thử tăng độ sáng."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7f478fb..a8fb4f1 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"允许该应用调用方法来添加和删除可用的人脸模板。"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"使用人脸身份验证硬件"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"允许该应用使用人脸身份验证硬件进行身份验证"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"无法捕获准确的人脸数据,请重试。"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"亮度过高,请尝试使用较柔和的亮度。"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"亮度不足,请尝试将光线调亮。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index cdb150e..81913e9 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"允許應用程式調用方法,以加入和刪除可用的臉孔範本。"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"使用臉孔驗證硬件"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"允許應用程式使用臉孔驗證硬件來驗證"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"無法擷取準確的臉容資料。請再試一次。"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"影像太亮。請嘗試在更暗的環境下使用。"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"影像太暗。請嘗試在更明亮的環境下使用。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1f2673c..a0324ab 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"允許應用程式呼叫方法來新增及移除可用的臉孔範本。"</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"使用臉孔驗證硬體"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"允許應用程式使用臉孔驗證硬體進行驗證"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"無法擷取精準臉孔資料,請再試一次。"</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"亮度過高,請嘗試使用較柔和的照明方式。"</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"亮度不足,請嘗試使用較明亮的照明方式。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f71bb74..268cab1 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -553,6 +553,12 @@
<string name="permdesc_manageFace" msgid="8919637120670185330">"Ivumela uhlelo lokusebenza ukuthi luhoxise izindlela zokungeza nokususa amathempulethi obuso azosetshenziswa."</string>
<string name="permlab_useFaceAuthentication" msgid="8996134460546804535">"sebenzisa izingxenyekazi zekhompuyutha zokufakazela ubuqiniso kobuso"</string>
<string name="permdesc_useFaceAuthentication" msgid="5011118722951833089">"Ivumela uhlelo lokusebenza ukuthi lusebenzise ukufakazela ubuqiniso bobuso bezingxenyekazi ukuze kufakazelwe ubuqiniso"</string>
+ <!-- no translation found for face_recalibrate_notification_name (3976629945250435054) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_title (4087620069451499365) -->
+ <skip />
+ <!-- no translation found for face_recalibrate_notification_content (5530308842361499835) -->
+ <skip />
<string name="face_acquired_insufficient" msgid="2767330364802375742">"Ayikwazanga ukuthwebula idatha enembile yobuso. Zama futhi."</string>
<string name="face_acquired_too_bright" msgid="5005650874582450967">"Kukhanya kakhulu. Zama ukukhanya okuthambile."</string>
<string name="face_acquired_too_dark" msgid="1966194696381394616">"Kumnyama kakhulu Zama ukukhanyisa okukhanyayo."</string>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0ed9860..2e98460 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1564,10 +1564,7 @@
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
</style>
- <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
- <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
- <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
-
+ <style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog">
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_settings</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
@@ -1576,8 +1573,15 @@
<item name="colorError">@color/error_color_device_default_light</item>
<!-- Dialog attributes -->
- <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<!-- Text styles -->
<item name="textAppearanceButton">@style/TextAppearance.DeviceDefault.Widget.Button</item>
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 5c8bced..1e49c0a 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -33,6 +33,7 @@
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.PersistableBundle;
import android.platform.test.annotations.Presubmit;
@@ -140,13 +141,14 @@
bundle.putString("key", "value");
PersistableBundle persistableBundle = new PersistableBundle();
persistableBundle.putInt("k", 4);
+ IBinder assistToken = new Binder();
LaunchActivityItem emptyItem = LaunchActivityItem.obtain(null, 0, null, null, null, null,
- null, null, 0, null, null, null, null, false, null);
+ null, null, 0, null, null, null, null, false, null, null);
LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
- true /* isForward */, null /* profilerInfo */);
+ true /* isForward */, null /* profilerInfo */, assistToken);
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
@@ -156,7 +158,7 @@
LaunchActivityItem item2 = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
- true /* isForward */, null /* profilerInfo */);
+ true /* isForward */, null /* profilerInfo */, assistToken);
assertSame(item, item2);
assertFalse(item2.equals(emptyItem));
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
index 1cca799..1410f4f 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java
@@ -266,7 +266,8 @@
null, /* overrideConfig */ null /* compatInfo */, null /* referrer */ ,
null /* voiceInteractor */, 0 /* procState */, null /* state */,
null /* persistentState */, null /* pendingResults */,
- null /* pendingNewIntents */, false /* isForward */, null /* profilerInfo */));
+ null /* pendingNewIntents */, false /* isForward */, null /* profilerInfo */,
+ null /* assistToken*/));
launchTransaction.addCallback(launchItem);
mExecutor.execute(launchTransaction);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index bffeb2a..1b63b7e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -242,7 +242,7 @@
LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo,
config(), overrideConfig, compat, referrer, null /* voiceInteractor */,
procState, bundle, persistableBundle, resultInfoList(), referrerIntentList(),
- true /* isForward */, null /* profilerInfo */);
+ true /* isForward */, null /* profilerInfo */, new Binder());
writeAndPrepareForReading(item);
// Read from parcel and assert
@@ -626,5 +626,15 @@
@Override
public final void runIsolatedEntryPoint(String entryPoint, String[] entryPointArgs) {
}
+
+ @Override
+ public void requestDirectActions(IBinder activityToken, IVoiceInteractor intractor,
+ RemoteCallback callback) {
+ }
+
+ @Override
+ public void performDirectAction(IBinder activityToken, String actionId, Bundle arguments,
+ RemoteCallback cancellationCallback, RemoteCallback resultCallback) {
+ }
}
}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 86d55ea..b3f6fdb 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -347,7 +347,7 @@
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
null /* voiceInteractor */, null /* state */, null /* persistentState */,
null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */,
- null /* profilerInfo */, mThread /* client */);
+ null /* profilerInfo */, mThread /* client */, null /* asssitToken */);
}
@Override
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f8e43437..bcc57d2 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3766,9 +3766,24 @@
* with frameworks/av/include/media/AudioPolicy.h
*/
/** @hide */
- public final static int RECORD_CONFIG_EVENT_START = 1;
+ public static final int RECORD_CONFIG_EVENT_NONE = -1;
/** @hide */
- public final static int RECORD_CONFIG_EVENT_STOP = 0;
+ public static final int RECORD_CONFIG_EVENT_START = 0;
+ /** @hide */
+ public static final int RECORD_CONFIG_EVENT_STOP = 1;
+ /** @hide */
+ public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
+ /** @hide */
+ public static final int RECORD_CONFIG_EVENT_DEATH = 3;
+ /**
+ * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
+ */
+ /** @hide */
+ public static final int RECORD_RIID_INVALID = -1;
+ /** @hide */
+ public static final int RECORDER_STATE_STARTED = 0;
+ /** @hide */
+ public static final int RECORDER_STATE_STOPPED = 1;
/**
* All operations on this list are sync'd on mRecordCallbackLock.
diff --git a/media/java/android/media/AudioRecordingConfiguration.java b/media/java/android/media/AudioRecordingConfiguration.java
index 82bcbc1..74e6618 100644
--- a/media/java/android/media/AudioRecordingConfiguration.java
+++ b/media/java/android/media/AudioRecordingConfiguration.java
@@ -157,7 +157,7 @@
return new AudioRecordingConfiguration( /*anonymized uid*/ -1,
in.mClientSessionId, in.mClientSource, in.mClientFormat,
in.mDeviceFormat, in.mPatchHandle, "" /*empty package name*/,
- in.mClientPortId, in.mClientSilenced, in.mDeviceSource, in.mClientEffects,
+ /*anonymized portId*/ -1, in.mClientSilenced, in.mDeviceSource, in.mClientEffects,
in.mDeviceEffects);
}
@@ -270,11 +270,12 @@
}
/**
+ * @hide
* Returns the system unique ID assigned for the AudioRecord object corresponding to this
* AudioRecordingConfiguration client.
* @return the port ID.
*/
- int getClientPortId() {
+ public int getClientPortId() {
return mClientPortId;
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index d105fa3..987db8b 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -220,6 +220,11 @@
*/
public static native int newAudioPlayerId();
+ /**
+ * Returns a new unused audio recorder ID
+ */
+ public static native int newAudioRecorderId();
+
/*
* Sets a group generic audio configuration parameters. The use of these parameters
@@ -347,6 +352,7 @@
/**
* Callback for recording activity notifications events
* @param event
+ * @param riid recording identifier
* @param uid uid of the client app performing the recording
* @param session
* @param source
@@ -361,7 +367,7 @@
* 6: patch handle
* @param packName package name of the client app performing the recording. NOT SUPPORTED
*/
- void onRecordingConfigurationChanged(int event, int uid, int session, int source,
+ void onRecordingConfigurationChanged(int event, int riid, int uid, int session, int source,
int portId, boolean silenced, int[] recordingFormat,
AudioEffect.Descriptor[] clienteffects, AudioEffect.Descriptor[] effects,
int activeSource, String packName);
@@ -379,16 +385,23 @@
/**
* Callback from native for recording configuration updates.
* @param event
+ * @param riid
+ * @param uid
* @param session
* @param source
+ * @param portId
+ * @param silenced
* @param recordingFormat see
- * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int,\
- boolean, int[], AudioEffect.Descriptor[], AudioEffect.Descriptor[], int, String)}
+ * {@link AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int, int, \
+ int, boolean, int[], AudioEffect.Descriptor[], AudioEffect.Descriptor[], int, String)}
* for the description of the record format.
+ * @param cleintEffects
+ * @param effects
+ * @param activeSource
*/
@UnsupportedAppUsage
- private static void recordingCallbackFromNative(int event, int uid, int session, int source,
- int portId, boolean silenced, int[] recordingFormat,
+ private static void recordingCallbackFromNative(int event, int riid, int uid, int session,
+ int source, int portId, boolean silenced, int[] recordingFormat,
AudioEffect.Descriptor[] clientEffects, AudioEffect.Descriptor[] effects,
int activeSource) {
AudioRecordingCallback cb = null;
@@ -401,7 +414,7 @@
if (cb != null) {
// TODO receive package name from native
- cb.onRecordingConfigurationChanged(event, uid, session, source, portId, silenced,
+ cb.onRecordingConfigurationChanged(event, riid, uid, session, source, portId, silenced,
recordingFormat, clientEffects, effects, activeSource, "");
}
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 85de00a..81ddcdb4 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -60,6 +60,10 @@
oneway void releasePlayer(in int piid);
+ int trackRecorder(in IBinder recorder);
+
+ oneway void recorderEvent(in int riid, in int event);
+
// Java-only methods below.
oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 7860f36..b2baff5 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -238,7 +238,7 @@
}
mSingleThreadExecutor.submit(() -> {
NotificationEntry entry =
- new NotificationEntry(mPackageManager, sbn.cloneLight(), channel, mSmsHelper);
+ new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper);
SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry);
if (DEBUG) {
Log.d(TAG, String.format(
@@ -296,7 +296,7 @@
Ranking ranking = getRanking(sbn.getKey(), rankingMap);
if (ranking != null && ranking.getChannel() != null) {
NotificationEntry entry = new NotificationEntry(mPackageManager,
- sbn.cloneLight(), ranking.getChannel(), mSmsHelper);
+ sbn, ranking.getChannel(), mSmsHelper);
String key = getKey(
sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
index 69e91d1..765e9f9 100644
--- a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
@@ -16,11 +16,12 @@
package android.ext.services.watchdog;
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
import android.content.ComponentName;
import android.content.Intent;
import android.provider.DeviceConfig;
import android.service.watchdog.ExplicitHealthCheckService;
-import android.service.watchdog.PackageInfo;
import android.util.Log;
import java.util.ArrayList;
@@ -74,8 +75,8 @@
}
@Override
- public List<PackageInfo> onGetSupportedPackages() {
- List<PackageInfo> packages = new ArrayList<>();
+ public List<PackageConfig> onGetSupportedPackages() {
+ List<PackageConfig> packages = new ArrayList<>();
long requestTimeoutMillis = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS,
@@ -84,7 +85,7 @@
requestTimeoutMillis = DEFAULT_REQUEST_TIMEOUT_MILLIS;
}
for (ExplicitHealthChecker checker : mSupportedCheckers.values()) {
- PackageInfo pkg = new PackageInfo(checker.getSupportedPackageName(),
+ PackageConfig pkg = new PackageConfig(checker.getSupportedPackageName(),
requestTimeoutMillis);
packages.add(pkg);
}
diff --git a/packages/FusedLocation/res/values-or/strings.xml b/packages/FusedLocation/res/values-or/strings.xml
index b95bc37a..b50e63d 100644
--- a/packages/FusedLocation/res/values-or/strings.xml
+++ b/packages/FusedLocation/res/values-or/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="5379477904423203699">"ଫ୍ୟୁଜ୍ଡ୍ ଲୋକେଶନ୍"</string>
+ <string name="app_label" msgid="5379477904423203699">"ଫ୍ୟୁଜ୍ଡ୍ ଲୋକେସନ୍"</string>
</resources>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index bc23b7a..b161c9a 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="8016145283189546017">"أجهزة إدخال بيانات"</string>
+ <string name="app_label" msgid="8016145283189546017">"أجهزة إدخال البيانات"</string>
<string name="keyboard_layouts_label" msgid="6688773268302087545">"لوحة مفاتيح Android"</string>
<string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"الإنجليزية (المملكة المتحدة)"</string>
<string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"الإنجليزية (الولايات المتحدة)"</string>
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
index fccb719..93a34c0 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -73,7 +74,12 @@
mIcon.setImageDrawable(barViewInfo.getIcon());
mBarTitle.setText(barViewInfo.getTitle());
mBarSummary.setText(barViewInfo.getSummary());
- mIcon.setContentDescription(barViewInfo.getContentDescription());
+
+ final CharSequence barViewInfoContent = barViewInfo.getContentDescription();
+ if (!TextUtils.isEmpty(barViewInfoContent)
+ && !TextUtils.equals((barViewInfo.getTitle()), barViewInfoContent)) {
+ mIcon.setContentDescription(barViewInfo.getContentDescription());
+ }
}
@VisibleForTesting
diff --git a/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml
index d446b20..297ecdb 100644
--- a/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-sw/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1604061903696928905">"Mipangilio ya utafutaji"</string>
+ <string name="search_menu" msgid="1604061903696928905">"Tafuta mipangilio"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
index 95f98c8..f54ef3b 100644
--- a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1604061903696928905">"Tìm kiếm mục cài đặt"</string>
+ <string name="search_menu" msgid="1604061903696928905">"Tìm kiếm trong các mục cài đặt"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index e280d62..5eccd1b 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -21,7 +21,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="wifi_fail_to_scan" msgid="1265540342578081461">"لا يمكن فحص الشبكات"</string>
- <string name="wifi_security_none" msgid="7985461072596594400">"بدون"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"بلا أمان"</string>
<string name="wifi_remembered" msgid="4955746899347821096">"تم الحفظ"</string>
<string name="wifi_disabled_generic" msgid="4259794910584943386">"غير مفعّلة"</string>
<string name="wifi_disabled_network_failure" msgid="2364951338436007124">"تعذّرت تهيئة عنوان IP"</string>
@@ -421,7 +421,7 @@
<string name="charge_length_format" msgid="8978516217024434156">"قبل <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="remaining_length_format" msgid="7886337596669190587">"يتبقى <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="screen_zoom_summary_small" msgid="5867245310241621570">"صغير"</string>
- <string name="screen_zoom_summary_default" msgid="2247006805614056507">"تلقائي"</string>
+ <string name="screen_zoom_summary_default" msgid="2247006805614056507">"الإعداد التلقائي"</string>
<string name="screen_zoom_summary_large" msgid="4835294730065424084">"كبير"</string>
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"أكبر"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"أكبر مستوى"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 1adaa46..8b128e5 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -238,7 +238,7 @@
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="5347862512596240506">"Трансляция: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="3700456559305263922">"Жеке DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="9221994415765826811">"Жеке DNS режимін таңдаңыз"</string>
- <string name="private_dns_mode_off" msgid="8236575187318721684">"Өшіру"</string>
+ <string name="private_dns_mode_off" msgid="8236575187318721684">"Өшірулі"</string>
<string name="private_dns_mode_opportunistic" msgid="8314986739896927399">"Автоматты"</string>
<string name="private_dns_mode_provider" msgid="8354935160639360804">"Жеке DNS провайдерінің хост атауы"</string>
<string name="private_dns_mode_provider_hostname_hint" msgid="2487492386970928143">"DNS провайдерінің хост атауын енгізіңіз"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index cf04db9..095d80f 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -462,6 +462,6 @@
<string name="zen_mode_duration_settings_title" msgid="229547412251222757">"Trajanje"</string>
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"Vedno vprašaj"</string>
<string name="zen_mode_forever" msgid="2704305038191592967">"Dokler ne izklopite"</string>
- <string name="time_unit_just_now" msgid="6363336622778342422">"Pravkar"</string>
+ <string name="time_unit_just_now" msgid="6363336622778342422">"pravkar"</string>
<string name="media_transfer_this_device_name" msgid="1636276898262571213">"Ta naprava"</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
index ae8e1e2..786139f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
@@ -45,7 +45,7 @@
Settings.Global.getLong(
resolver, Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME, -1))
return if (Duration.between(lastUpdateTime,
- Instant.now()).compareTo(Duration.ofMinutes(2)) > 0) {
+ Instant.now()).compareTo(Duration.ofMinutes(1)) > 0) {
null
} else Estimate(
Settings.Global.getLong(resolver,
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
index a6b5755..4bd1bbb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java
@@ -203,8 +203,11 @@
}
public void setColors(int background, int foreground) {
+ int colorBackground = mPaint.getColor();
+ int colorForeground = mForegroundPaint.getColor();
mPaint.setColor(background);
mForegroundPaint.setColor(foreground);
+ if (colorBackground != background || colorForeground != foreground) invalidateSelf();
}
public void setDarkIntensity(float darkIntensity) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index cd97ce8..29cb6f3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -20,12 +20,7 @@
import static android.os.Process.ROOT_UID;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
import android.Manifest;
import android.annotation.NonNull;
@@ -41,7 +36,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
-import android.content.om.OverlayInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -4321,50 +4315,19 @@
if (currentVersion == 176) {
// Version 176: Migrate the existing swipe up setting into the resource overlay
- // for the navigation bar interaction mode.
+ // for the navigation bar interaction mode. We do so only if the
+ // setting is set.
- final IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
- ServiceManager.getService(Context.OVERLAY_SERVICE));
- int navBarMode = -1;
-
- // Migrate the swipe up setting only if it is set
final SettingsState secureSettings = getSecureSettingsLocked(userId);
final Setting swipeUpSetting = secureSettings.getSettingLocked(
"swipe_up_to_switch_apps_enabled");
- if (swipeUpSetting != null && !swipeUpSetting.isNull()) {
- navBarMode = swipeUpSetting.getValue().equals("1")
- ? NAV_BAR_MODE_2BUTTON
- : NAV_BAR_MODE_3BUTTON;
- }
-
- // Temporary: Only for migration for dogfooders, to be removed
- try {
- final OverlayInfo info = overlayManager.getOverlayInfo(
- "com.android.internal.experiment.navbar.type.inset",
- UserHandle.USER_CURRENT);
- if (info != null && info.isEnabled()) {
- navBarMode = NAV_BAR_MODE_GESTURAL;
- }
- } catch (RemoteException e) {
- // Ingore, fall through
- }
-
- if (navBarMode != -1) {
- String overlayPackage = "";
+ if (swipeUpSetting != null && !swipeUpSetting.isNull()
+ && swipeUpSetting.getValue().equals("1")) {
+ final IOverlayManager overlayManager = IOverlayManager.Stub.asInterface(
+ ServiceManager.getService(Context.OVERLAY_SERVICE));
try {
- switch (navBarMode) {
- case NAV_BAR_MODE_3BUTTON:
- overlayPackage = NAV_BAR_MODE_3BUTTON_OVERLAY;
- break;
- case NAV_BAR_MODE_2BUTTON:
- overlayPackage = NAV_BAR_MODE_2BUTTON_OVERLAY;
- break;
- case NAV_BAR_MODE_GESTURAL:
- overlayPackage = NAV_BAR_MODE_GESTURAL_OVERLAY;
- break;
- }
- overlayManager.setEnabledExclusiveInCategory(overlayPackage,
- UserHandle.USER_CURRENT);
+ overlayManager.setEnabledExclusiveInCategory(
+ NAV_BAR_MODE_2BUTTON_OVERLAY, UserHandle.USER_CURRENT);
} catch (RemoteException e) {
throw new IllegalStateException(
"Failed to set nav bar interaction mode overlay");
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid.xml b/packages/SystemUI/res/layout-land/global_actions_grid.xml
index c51e71b..511910e 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid.xml
@@ -8,7 +8,7 @@
android:clipToPadding="false"
android:theme="@style/qs_theme"
android:paddingLeft="@dimen/global_actions_top_padding"
- android:gravity="top|left"
+ android:gravity="right"
android:clipChildren="false"
>
<LinearLayout
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
index de853c7..ff2a7d8 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
@@ -7,7 +7,7 @@
android:orientation="horizontal"
android:clipToPadding="false"
android:theme="@style/qs_theme"
- android:gravity="top|right"
+ android:gravity="left"
android:paddingRight="@dimen/global_actions_top_padding"
android:clipChildren="false"
>
diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml
index 8651e5a..3f10b38 100644
--- a/packages/SystemUI/res/layout/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid.xml
@@ -6,9 +6,8 @@
android:layout_height="match_parent"
android:orientation="horizontal"
android:clipToPadding="false"
- android:paddingTop="@dimen/global_actions_top_padding"
android:theme="@style/qs_theme"
- android:gravity="top|center"
+ android:gravity="bottom"
android:clipChildren="false"
>
<LinearLayout
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 83fad66..7f69cf4 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -28,7 +28,8 @@
android:clipToPadding="false"
android:minHeight="20dp"
android:clickable="false"
- android:focusable="true">
+ android:focusable="true"
+ android:theme="@style/QSHeaderTheme">
<com.android.systemui.statusbar.policy.DateView
android:id="@+id/date"
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 5a33f82..d0783a0 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -20,7 +20,8 @@
android:layout_height="@dimen/qs_header_tooltip_height"
android:layout_below="@id/quick_status_bar_system_icons"
android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end">
+ android:paddingEnd="@dimen/status_bar_padding_end"
+ android:theme="@style/QSHeaderTheme">
<LinearLayout
android:layout_width="wrap_content"
@@ -50,7 +51,6 @@
android:layout_width="@dimen/qs_header_alarm_icon_size"
android:layout_height="@dimen/qs_header_alarm_icon_size"
android:src="@drawable/ic_alarm"
- android:tint="?android:attr/textColorPrimary"
android:contentDescription="@string/accessibility_quick_settings_alarm_set"
android:visibility="gone"/>
@@ -85,7 +85,6 @@
android:id="@+id/ringer_mode_icon"
android:layout_width="@dimen/qs_header_alarm_icon_size"
android:layout_height="@dimen/qs_header_alarm_icon_size"
- android:tint="?android:attr/textColorPrimary"
android:visibility="gone"/>
<TextView
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 3ab6b56..4fdeb6f 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -24,4 +24,9 @@
<item name="android:windowIsFloating">true</item>
</style>
+ <style name="TextAppearance.QS.Status" parent="TextAppearance.QS.TileLabel.Secondary">
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d2a005f..4e1a7d0 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -118,6 +118,11 @@
<color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
<color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
+ <color name="dark_mode_qs_icon_color_single_tone">#B3000000</color><!-- 70% black -->
+ <color name="dark_mode_qs_icon_color_dual_tone_background">#3d000000</color>
+ <!-- Chosen so fill over background matches single tone -->
+ <color name="dark_mode_qs_icon_color_dual_tone_fill">#99000000</color>
+
<color name="docked_divider_background">#ff000000</color>
<color name="docked_divider_handle">#ffffff</color>
<drawable name="forced_resizable_background">#59000000</drawable>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9b471c9..4b64347 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -224,6 +224,7 @@
<style name="TextAppearance.QS.Status" parent="TextAppearance.QS.TileLabel.Secondary">
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:textColor">@color/dark_mode_qs_icon_color_single_tone</item>
</style>
<style name="TextAppearance.AppOpsDialog" />
@@ -371,6 +372,17 @@
<item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
<item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
</style>
+ <style name="QSHeaderDarkTheme">
+ <item name="backgroundColor">@color/dark_mode_qs_icon_color_dual_tone_background</item>
+ <item name="fillColor">@color/dark_mode_qs_icon_color_dual_tone_fill</item>
+ <item name="singleToneColor">@color/dark_mode_qs_icon_color_single_tone</item>
+ </style>
+
+ <style name="QSHeaderTheme" parent="@style/Theme.SystemUI">
+ <item name="lightIconTheme">@style/DualToneLightTheme</item>
+ <item name="darkIconTheme">@style/QSHeaderDarkTheme</item>
+ </style>
+
<style name="QSIconTheme">
<item name="backgroundColor">?android:attr/textColorHint</item>
<item name="fillColor">?android:attr/textColorPrimary</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 3e70bad..b89b9ef 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -21,7 +21,6 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import android.annotation.IntDef;
-import android.content.Context;
import android.content.res.Resources;
import android.view.WindowManagerPolicyConstants;
@@ -95,13 +94,6 @@
}
/**
- * @return whether the current nav bar mode is gestural
- */
- public static boolean isGesturalMode(Context context) {
- return isGesturalMode(getCurrentInteractionMode(context));
- }
-
- /**
* @return whether this nav bar mode is swipe up
*/
public static boolean isSwipeUpMode(int mode) {
@@ -109,13 +101,6 @@
}
/**
- * @return whether the current nav bar mode is swipe up
- */
- public static boolean isSwipeUpMode(Context context) {
- return isSwipeUpMode(getCurrentInteractionMode(context));
- }
-
- /**
* @return whether this nav bar mode is 3 button
*/
public static boolean isLegacyMode(int mode) {
@@ -123,37 +108,6 @@
}
/**
- * @return whether this nav bar mode is 3 button
- */
- public static boolean isLegacyMode(Context context) {
- return isLegacyMode(getCurrentInteractionMode(context));
- }
-
- /**
- * @return the current nav bar interaction mode
- */
- public static int getCurrentInteractionMode(Context context) {
- return context.getResources().getInteger(
- com.android.internal.R.integer.config_navBarInteractionMode);
- }
-
- /**
- * @return {@code true} if the navbar can be clicked through
- */
- public static boolean isNavBarClickThrough(Context context) {
- return context.getResources().getBoolean(
- com.android.internal.R.bool.config_navBarTapThrough);
- }
-
- /**
- * @return the edge sensitivity width in px
- */
- public static int getEdgeSensitivityWidth(Context context) {
- return context.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.config_backGestureInset);
- }
-
- /**
* Corner radius that should be used on windows in order to cover the display.
* These values are expressed in pixels because they should not respect display or font
* scaling, this means that we don't have to reload them on config changes.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 9dd5bb4..bd7b3d5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -105,7 +105,8 @@
}
t.setEarlyWakeup();
t.apply();
- mApplyHandler.sendEmptyMessage(toApplySeqNo);
+ Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
+ .sendToTarget();
}
});
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 135b351..07c2f10 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -289,12 +289,19 @@
public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
addClockPlugin(plugin);
reload();
+ if (plugin == mCurrentClock) {
+ ClockManager.this.reload();
+ }
}
@Override
public void onPluginDisconnected(ClockPlugin plugin) {
+ boolean isCurrentClock = plugin == mCurrentClock;
removeClockPlugin(plugin);
reload();
+ if (isCurrentClock) {
+ ClockManager.this.reload();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 6c1d1f9..de4c798 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -23,7 +23,6 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.animation.ArgbEvaluator;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.annotation.IntDef;
@@ -36,10 +35,10 @@
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.TypedValue;
-import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -99,13 +98,7 @@
private boolean mIsSubscribedForTunerUpdates;
private boolean mCharging;
- private int mDarkModeSingleToneColor;
- private int mDarkModeBackgroundColor;
- private int mDarkModeFillColor;
-
- private int mLightModeSingleToneColor;
- private int mLightModeBackgroundColor;
- private int mLightModeFillColor;
+ private DualToneHandler mDualToneHandler;
private int mUser;
/**
@@ -161,7 +154,7 @@
addView(mBatteryIconView, mlp);
updateShowPercent();
- setColorsFromContext(context);
+ mDualToneHandler = new DualToneHandler(context);
// Init to not dark at all.
onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
@@ -282,21 +275,7 @@
return;
}
- Context dualToneDarkTheme = new ContextThemeWrapper(context,
- Utils.getThemeAttr(context, R.attr.darkIconTheme));
- Context dualToneLightTheme = new ContextThemeWrapper(context,
- Utils.getThemeAttr(context, R.attr.lightIconTheme));
- mDarkModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
- R.attr.singleToneColor);
- mDarkModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
- R.attr.backgroundColor);
- mDarkModeFillColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
- R.attr.fillColor);
- mLightModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
- R.attr.singleToneColor);
- mLightModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
- R.attr.backgroundColor);
- mLightModeFillColor = Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor);
+ mDualToneHandler.setColorsFromContext(context);
}
@Override
@@ -319,6 +298,9 @@
mUser = ActivityManager.getCurrentUser();
getContext().getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
+ getContext().getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME),
+ false, mSettingObserver);
updateShowPercent();
subscribeForTunerUpdates();
mUserTracker.startTracking();
@@ -448,12 +430,9 @@
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
- mNonAdaptedSingleToneColor = getColorForDarkIntensity(
- intensity, mLightModeSingleToneColor, mDarkModeSingleToneColor);
- mNonAdaptedForegroundColor = getColorForDarkIntensity(
- intensity, mLightModeFillColor, mDarkModeFillColor);
- mNonAdaptedBackgroundColor = getColorForDarkIntensity(
- intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor);
+ mNonAdaptedSingleToneColor = mDualToneHandler.getSingleColor(intensity);
+ mNonAdaptedForegroundColor = mDualToneHandler.getFillColor(intensity);
+ mNonAdaptedBackgroundColor = mDualToneHandler.getBackgroundColor(intensity);
if (!mUseWallpaperTextColors) {
updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
@@ -469,10 +448,6 @@
}
}
- private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
- return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
String powerSave = mDrawable == null ? null : mDrawable.getPowerSaveEnabled() + "";
CharSequence percent = mBatteryPercentView == null ? null : mBatteryPercentView.getText();
@@ -493,6 +468,11 @@
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
updateShowPercent();
+ if (TextUtils.equals(uri.getLastPathSegment(),
+ Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) {
+ // update the text for sure if the estimate in the cache was updated
+ updatePercentText();
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 4b338f7..1feb63d 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -74,6 +74,7 @@
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ManagedProfileController;
+import com.android.systemui.statusbar.phone.NavigationModeController;
import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -244,6 +245,7 @@
@Inject Lazy<LightBarController> mLightBarController;
@Inject Lazy<IWindowManager> mIWindowManager;
@Inject Lazy<OverviewProxyService> mOverviewProxyService;
+ @Inject Lazy<NavigationModeController> mNavBarModeController;
@Inject Lazy<EnhancedEstimates> mEnhancedEstimates;
@Inject Lazy<VibratorHelper> mVibratorHelper;
@Inject Lazy<IStatusBarService> mIStatusBarService;
@@ -407,6 +409,8 @@
mProviders.put(OverviewProxyService.class, mOverviewProxyService::get);
+ mProviders.put(NavigationModeController.class, mNavBarModeController::get);
+
mProviders.put(EnhancedEstimates.class, mEnhancedEstimates::get);
mProviders.put(VibratorHelper.class, mVibratorHelper::get);
diff --git a/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt b/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt
new file mode 100644
index 0000000..fdc3229
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt
@@ -0,0 +1,99 @@
+/*
+ * 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
+
+import android.animation.ArgbEvaluator
+import android.content.Context
+import android.view.ContextThemeWrapper
+import com.android.settingslib.Utils
+
+/**
+ * A color blender for `Theme.SystemUI` and other themes.
+ *
+ * This class is used to handle colors from themes in [Context] in the following fashion:
+ * * The theme associated has a `darkIconTheme` and a `lightIconTheme`
+ * * Each of these themes define colors for the items `singleToneColor`, `backgroundColor`,
+ * and `fillColor`.
+ *
+ * In particular, `Theme.SystemUI` is a valid [Context]. If the provided [Context] does not have
+ * the correct themes, the colors that are not found will default to black.
+ *
+ * It provides a way to obtain these colors and blends for a given background intensity.
+ */
+class DualToneHandler(context: Context) {
+ private lateinit var darkColor: Color
+ private lateinit var lightColor: Color
+
+ init {
+ setColorsFromContext(context)
+ }
+
+ /**
+ * Sets the colors in this object from the given [Context]
+ *
+ * @param[context] A context with the appropriate themes to extract the colors from.
+ */
+ fun setColorsFromContext(context: Context) {
+ val dualToneDarkTheme = ContextThemeWrapper(context,
+ Utils.getThemeAttr(context, R.attr.darkIconTheme))
+ val dualToneLightTheme = ContextThemeWrapper(context,
+ Utils.getThemeAttr(context, R.attr.lightIconTheme))
+ darkColor = Color(
+ Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.singleToneColor),
+ Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.backgroundColor),
+ Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.fillColor))
+ lightColor = Color(
+ Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.singleToneColor),
+ Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.backgroundColor),
+ Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor))
+ }
+
+ private fun getColorForDarkIntensity(darkIntensity: Float, lightColor: Int, darkColor: Int) =
+ ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor) as Int
+
+ /**
+ * Blends the single color associated with the light and dark theme
+ *
+ * @param[intensity] Intensity of the background. Correspond with the "percentage" of color
+ * from `darkIconTheme` to use
+ * @return The blended color
+ */
+ fun getSingleColor(intensity: Float) =
+ getColorForDarkIntensity(intensity, lightColor.single, darkColor.single)
+
+ /**
+ * Blends the background color associated with the light and dark theme
+ *
+ * @param[intensity] Intensity of the background. Correspond with the "percentage" of color
+ * from `darkIconTheme` to use
+ * @return The blended color
+ */
+ fun getBackgroundColor(intensity: Float) =
+ getColorForDarkIntensity(intensity, lightColor.background, darkColor.background)
+
+ /**
+ * Blends the fill color associated with the light and dark theme
+ *
+ * @param[intensity] Intensity of the background. Correspond with the "percentage" of color
+ * from `darkIconTheme` to use
+ * @return The blended color
+ */
+ fun getFillColor(intensity: Float) =
+ getColorForDarkIntensity(intensity, lightColor.fill, darkColor.fill)
+
+ private data class Color(val single: Int, val background: Int, val fill: Int)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 822538b..802903d 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -32,13 +32,10 @@
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
-import com.android.systemui.globalactions.GlobalActionsDialog;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
import com.android.systemui.util.leak.RotationUtils;
-import java.util.ArrayList;
-
/**
* Layout for placing two containers at a specific physical position on the device, relative to the
* device's hardware, regardless of screen rotation.
@@ -258,24 +255,16 @@
@Override
public void onUpdateList() {
super.onUpdateList();
- ArrayList<GlobalActionsDialog.Action> separatedActions =
- mAdapter.getSeparatedItems();
- ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems();
for (int i = 0; i < mAdapter.getCount(); i++) {
- Object action = mAdapter.getItem(i);
- int separatedIndex = separatedActions.indexOf(action);
ViewGroup parent;
- if (separatedIndex != -1) {
+ boolean separated = mAdapter.shouldBeSeparated(i);
+ if (separated) {
parent = getSeparatedView();
} else {
- int listIndex = listActions.indexOf(action);
parent = getListView();
}
View v = mAdapter.getView(i, null, parent);
- final int pos = i;
- v.setOnClickListener(view -> mAdapter.onClickItem(pos));
- v.setOnLongClickListener(view -> mAdapter.onLongClickItem(pos));
parent.addView(v);
}
}
@@ -421,7 +410,9 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
+
post(() -> updatePosition());
+
}
private void animateChild(int oldHeight, int newHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
index a30b681..f8287a4 100644
--- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -26,16 +26,12 @@
import com.android.systemui.util.leak.RotationUtils;
-import java.util.ArrayList;
-
/**
* Layout class representing the Global Actions menu which appears when the power button is held.
*/
public abstract class MultiListLayout extends LinearLayout {
protected boolean mHasOutsideTouch;
protected MultiListAdapter mAdapter;
- protected boolean mSnapToEdge;
-
protected int mRotation;
protected RotationListener mRotationListener;
@@ -51,7 +47,7 @@
/**
* Removes all child items from the separated and list views, if they exist.
*/
- public abstract void removeAllItems();
+ protected abstract void removeAllItems();
/**
* Sets the divided view, which may have a differently-colored background.
@@ -70,13 +66,6 @@
}
/**
- * Sets whether the GlobalActions view should snap to the edge of the screen.
- */
- public void setSnapToEdge(boolean snap) {
- mSnapToEdge = snap;
- }
-
- /**
* Sets the adapter used to inflate items.
*/
public void setAdapter(MultiListAdapter adapter) {
@@ -122,6 +111,7 @@
}
protected void onUpdateList() {
+ removeAllItems();
setSeparatedViewVisibility(mAdapter.hasSeparatedItems());
}
@@ -163,16 +153,14 @@
*/
public abstract static class MultiListAdapter extends BaseAdapter {
/**
- * Creates an ArrayList of items which should be rendered in the separated view.
- * @param useSeparatedView is true if the separated view will be used, false otherwise.
+ * Counts the number of items to be rendered in the separated view.
*/
- public abstract ArrayList getSeparatedItems();
+ public abstract int countSeparatedItems();
/**
- * Creates an ArrayList of items which should be rendered in the list view.
- * @param useSeparatedView True if the separated view will be used, false otherwise.
+ * Counts the number of items be rendered in the list view.
*/
- public abstract ArrayList getListItems();
+ public abstract int countListItems();
/**
* Callback to run when an individual item is clicked or pressed.
@@ -192,7 +180,13 @@
* or not to hide the separated list from view.
*/
public boolean hasSeparatedItems() {
- return getSeparatedItems().size() > 0;
+ return countSeparatedItems() > 0;
}
+
+ /**
+ * Determines whether the item at the given index should be rendered in the separarted view.
+ * @param position The index of the item.
+ */
+ public abstract boolean shouldBeSeparated(int position);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 47ad0c1..ffb5e81 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -22,12 +22,15 @@
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.ViewGroup;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.util.function.TriConsumer;
import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.classifier.FalsingManager;
@@ -125,7 +128,8 @@
DismissCallbackRegistry dismissCallbackRegistry,
KeyguardBouncer.BouncerExpansionCallback expansionCallback) {
return new KeyguardBouncer(context, callback, lockPatternUtils, container,
- dismissCallbackRegistry, FalsingManager.getInstance(context), expansionCallback);
+ dismissCallbackRegistry, FalsingManager.getInstance(context), expansionCallback,
+ KeyguardUpdateMonitor.getInstance(context), new Handler(Looper.getMainLooper()));
}
public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 63db361..346660d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -25,6 +25,7 @@
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
+import android.app.ActivityOptions;
import android.app.ActivityView;
import android.app.INotificationManager;
import android.app.Notification;
@@ -121,7 +122,11 @@
public void onActivityViewReady(ActivityView view) {
if (!mActivityViewReady) {
mActivityViewReady = true;
- mActivityView.startActivity(mBubbleIntent);
+ // Custom options so there is no activity transition animation
+ ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
+ 0 /* enterResId */, 0 /* exitResId */);
+ // Post to keep the lifecycle normal
+ post(() -> mActivityView.startActivity(mBubbleIntent, options));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index e128531..64511a0 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -919,73 +919,59 @@
* via {@link com.android.systemui.globalactions.GlobalActionsDialog#mDeviceProvisioned}.
*/
public class MyAdapter extends MultiListAdapter {
- @Override
- public int getCount() {
+ private int countItems(boolean separated) {
int count = 0;
for (int i = 0; i < mItems.size(); i++) {
final Action action = mItems.get(i);
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
+ if (shouldBeShown(action) && action.shouldBeSeparated() == separated) {
+ count++;
}
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
- continue;
- }
- count++;
}
return count;
}
+ private boolean shouldBeShown(Action action) {
+ if (mKeyguardShowing && !action.showDuringKeyguard()) {
+ return false;
+ }
+ if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int countSeparatedItems() {
+ return countItems(true);
+ }
+
+ @Override
+ public int countListItems() {
+ return countItems(false);
+ }
+
+ @Override
+ public int getCount() {
+ return countSeparatedItems() + countListItems();
+ }
+
@Override
public boolean isEnabled(int position) {
return getItem(position).isEnabled();
}
@Override
- public ArrayList<Action> getSeparatedItems() {
- ArrayList<Action> separatedActions = new ArrayList<Action>();
- if (!shouldUseSeparatedView()) {
- return separatedActions;
- }
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
- if (action.shouldBeSeparated()) {
- separatedActions.add(action);
- }
- }
- return separatedActions;
- }
-
- @Override
- public ArrayList<Action> getListItems() {
- if (!shouldUseSeparatedView()) {
- return new ArrayList<Action>(mItems);
- }
- ArrayList<Action> listActions = new ArrayList<Action>();
- for (int i = 0; i < mItems.size(); i++) {
- final Action action = mItems.get(i);
- if (!action.shouldBeSeparated()) {
- listActions.add(action);
- }
- }
- return listActions;
- }
-
- @Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public Action getItem(int position) {
-
int filteredPos = 0;
for (int i = 0; i < mItems.size(); i++) {
final Action action = mItems.get(i);
- if (mKeyguardShowing && !action.showDuringKeyguard()) {
- continue;
- }
- if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
+ if (!shouldBeShown(action)) {
continue;
}
if (filteredPos == position) {
@@ -1010,10 +996,8 @@
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
- // Everything but screenshot, the last item, gets white background.
- if (position == getCount() - 1) {
- MultiListLayout.get(parent).setDivisionView(view);
- }
+ view.setOnClickListener(v -> onClickItem(position));
+ view.setOnLongClickListener(v -> onLongClickItem(position));
return view;
}
@@ -1035,6 +1019,11 @@
}
item.onPress();
}
+
+ @Override
+ public boolean shouldBeSeparated(int position) {
+ return getItem(position).shouldBeSeparated();
+ }
}
// note: the scheme below made more sense when we were planning on having
@@ -1590,7 +1579,6 @@
mScrimAlpha = 1f;
initializePanel();
}
- mGlobalActionsLayout.setSnapToEdge(true);
getWindow().setBackgroundDrawable(mBackgroundDrawable);
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index 669348e..554ed73 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -21,19 +21,16 @@
import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
import android.content.Context;
-import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.Gravity;
+import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.HardwareBgDrawable;
import com.android.systemui.MultiListLayout;
import com.android.systemui.util.leak.RotationUtils;
-import java.util.ArrayList;
-import java.util.Locale;
-
/**
* Grid-based implementation of the button layout created by the global actions dialog.
*/
@@ -69,67 +66,65 @@
}
}
- /**
- * Sets the number of items expected to be rendered in the list container. This allows the
- * layout to correctly determine which parent containers will be used for items before they have
- * beenadded to the layout.
- * @param count The number of items expected.
- */
- public void setExpectedListItemCount(int count) {
- getListView().setExpectedCount(count);
+ @VisibleForTesting
+ protected int getCurrentRotation() {
+ return RotationUtils.getRotation(mContext);
+ }
+
+ @VisibleForTesting
+ protected void setupListView(ListGridLayout listView, int itemCount) {
+ listView.setExpectedCount(itemCount);
+ listView.setReverseSublists(shouldReverseSublists());
+ listView.setReverseItems(shouldReverseListItems());
+ listView.setSwapRowsAndColumns(shouldSwapRowsAndColumns());
}
@Override
public void onUpdateList() {
super.onUpdateList();
- ArrayList<GlobalActionsDialog.Action> separatedActions =
- mAdapter.getSeparatedItems();
- ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems();
- setExpectedListItemCount(listActions.size());
- int rotation = RotationUtils.getRotation(mContext);
- boolean reverse = false; // should we add items to parents in the reverse order?
- if (rotation == ROTATION_NONE
- || rotation == ROTATION_SEASCAPE) {
- reverse = !reverse; // if we're in portrait or seascape, reverse items
- }
- if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
- == View.LAYOUT_DIRECTION_RTL) {
- reverse = !reverse; // if we're in an RTL language, reverse items (again)
- }
+ ViewGroup separatedView = getSeparatedView();
+ ListGridLayout listView = getListView();
+ setupListView(listView, mAdapter.countListItems());
for (int i = 0; i < mAdapter.getCount(); i++) {
- Object action = mAdapter.getItem(i);
- int separatedIndex = separatedActions.indexOf(action);
- ViewGroup parent;
- if (separatedIndex != -1) {
- parent = getParentView(true, separatedIndex, rotation);
+ // generate the view item
+ View v;
+ boolean separated = mAdapter.shouldBeSeparated(i);
+ if (separated) {
+ v = mAdapter.getView(i, null, separatedView);
} else {
- int listIndex = listActions.indexOf(action);
- parent = getParentView(false, listIndex, rotation);
+ v = mAdapter.getView(i, null, listView);
}
- View v = mAdapter.getView(i, null, parent);
- final int pos = i;
- v.setOnClickListener(view -> mAdapter.onClickItem(pos));
- v.setOnLongClickListener(view -> mAdapter.onLongClickItem(pos));
- if (reverse) {
- parent.addView(v, 0); // reverse order of items
+ Log.d("GlobalActionsGridLayout", "View: " + v);
+
+ if (separated) {
+ separatedView.addView(v);
} else {
- parent.addView(v);
+ listView.addItem(v);
}
- parent.setVisibility(View.VISIBLE);
}
- updateSnapPosition();
- updateSeparatedButtonSize();
+ updateSeparatedItemSize();
}
- private void updateSeparatedButtonSize() {
+ /**
+ * If the separated view contains only one item, expand the bounds of that item to take up the
+ * entire view, so that the whole thing is touch-able.
+ */
+ private void updateSeparatedItemSize() {
ViewGroup separated = getSeparatedView();
+ if (separated.getChildCount() == 0) {
+ return;
+ }
+ View firstChild = separated.getChildAt(0);
+ ViewGroup.LayoutParams childParams = firstChild.getLayoutParams();
+
if (separated.getChildCount() == 1) {
- View onlyChild = separated.getChildAt(0);
- ViewGroup.LayoutParams childParams = onlyChild.getLayoutParams();
childParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
childParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ } else {
+ childParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
+ childParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
}
}
@@ -138,19 +133,6 @@
return findViewById(com.android.systemui.R.id.separated_button);
}
- private void updateSnapPosition() {
- if (mSnapToEdge) {
- setPadding(0, 0, 0, 0);
- if (mRotation == ROTATION_LANDSCAPE) {
- setGravity(Gravity.RIGHT);
- } else if (mRotation == ROTATION_SEASCAPE) {
- setGravity(Gravity.LEFT);
- } else {
- setGravity(Gravity.BOTTOM);
- }
- }
- }
-
@Override
protected ListGridLayout getListView() {
return findViewById(android.R.id.list);
@@ -168,19 +150,47 @@
}
}
- public ViewGroup getParentView(boolean separated, int index, int rotation) {
- if (separated) {
- return getSeparatedView();
- } else {
- switch (rotation) {
- case ROTATION_LANDSCAPE:
- return getListView().getParentView(index, false, true);
- case ROTATION_SEASCAPE:
- return getListView().getParentView(index, true, true);
- default:
- return getListView().getParentView(index, false, false);
- }
+ /**
+ * Determines whether the ListGridLayout should fill sublists in the reverse order.
+ * Used to account for sublist ordering changing between landscape and seascape views.
+ */
+ @VisibleForTesting
+ protected boolean shouldReverseSublists() {
+ if (getCurrentRotation() == ROTATION_SEASCAPE) {
+ return true;
}
+ return false;
+ }
+
+ /**
+ * Determines whether the ListGridLayout should fill rows first instead of columns.
+ * Used to account for vertical/horizontal changes due to landscape or seascape rotations.
+ */
+ @VisibleForTesting
+ protected boolean shouldSwapRowsAndColumns() {
+ if (getCurrentRotation() == ROTATION_NONE) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Determines whether the ListGridLayout should reverse the ordering of items within sublists.
+ * Used for RTL languages to ensure that items appear in the same positions, without having to
+ * override layoutDirection, which breaks Talkback ordering.
+ */
+ @VisibleForTesting
+ protected boolean shouldReverseListItems() {
+ int rotation = getCurrentRotation();
+ boolean reverse = false; // should we add items to parents in the reverse order?
+ if (rotation == ROTATION_NONE
+ || rotation == ROTATION_SEASCAPE) {
+ reverse = !reverse; // if we're in portrait or seascape, reverse items
+ }
+ if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ reverse = !reverse; // if we're in an RTL language, reverse items (again)
+ }
+ return reverse;
}
/**
@@ -191,7 +201,7 @@
// do nothing
}
- private float getAnimationDistance() {
+ protected float getAnimationDistance() {
int rows = getListView().getRowCount();
float gridItemSize = getContext().getResources().getDimension(
com.android.systemui.R.dimen.global_actions_grid_item_height);
@@ -200,7 +210,7 @@
@Override
public float getAnimationOffsetX() {
- switch (RotationUtils.getRotation(getContext())) {
+ switch (getCurrentRotation()) {
case ROTATION_LANDSCAPE:
return getAnimationDistance();
case ROTATION_SEASCAPE:
@@ -212,7 +222,7 @@
@Override
public float getAnimationOffsetY() {
- if (RotationUtils.getRotation(mContext) == ROTATION_NONE) {
+ if (getCurrentRotation() == ROTATION_NONE) {
return getAnimationDistance();
}
return 0;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
index 6bc975a..8c93b13 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
@@ -22,6 +22,8 @@
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Layout which uses nested LinearLayouts to create a grid with the following behavior:
*
@@ -40,6 +42,10 @@
public class ListGridLayout extends LinearLayout {
private static final String TAG = "ListGridLayout";
private int mExpectedCount;
+ private int mCurrentCount = 0;
+ private boolean mSwapRowsAndColumns;
+ private boolean mReverseSublists;
+ private boolean mReverseItems;
// number of rows and columns to use for different numbers of items
private final int[][] mConfigs = {
@@ -61,16 +67,60 @@
}
/**
+ * Sets whether this grid should prioritize filling rows or columns first.
+ */
+ public void setSwapRowsAndColumns(boolean swap) {
+ mSwapRowsAndColumns = swap;
+ }
+
+ /**
+ * Sets whether this grid should fill sublists in reverse order.
+ */
+ public void setReverseSublists(boolean reverse) {
+ mReverseSublists = reverse;
+ }
+
+ /**
+ * Sets whether this grid should add items to sublists in reverse order.
+ * @param reverse
+ */
+ public void setReverseItems(boolean reverse) {
+ mReverseItems = reverse;
+ }
+
+ /**
* Remove all items from this grid.
*/
public void removeAllItems() {
for (int i = 0; i < getChildCount(); i++) {
- ViewGroup subList = (ViewGroup) getChildAt(i);
+ ViewGroup subList = getSublist(i);
if (subList != null) {
subList.removeAllViews();
subList.setVisibility(View.GONE);
}
}
+ mCurrentCount = 0;
+ }
+
+ /**
+ * Adds a view item to this grid, placing it in the correct sublist and ensuring that the
+ * sublist is visible.
+ *
+ * This function is stateful, since it tracks how many items have been added thus far, to
+ * determine which sublist they should be added to. To ensure that this works correctly, call
+ * removeAllItems() instead of removing views individually with removeView() to ensure that the
+ * counter gets reset correctly.
+ * @param item
+ */
+ public void addItem(View item) {
+ ViewGroup parent = getParentView(mCurrentCount, mReverseSublists, mSwapRowsAndColumns);
+ if (mReverseItems) {
+ parent.addView(item, 0);
+ } else {
+ parent.addView(item);
+ }
+ parent.setVisibility(View.VISIBLE);
+ mCurrentCount++;
}
/**
@@ -83,13 +133,20 @@
* true will cause rows to fill first, adding one item to each column.
* @return
*/
- public ViewGroup getParentView(int index, boolean reverseSublists, boolean swapRowsAndColumns) {
+ @VisibleForTesting
+ protected ViewGroup getParentView(int index, boolean reverseSublists,
+ boolean swapRowsAndColumns) {
if (getRowCount() == 0 || index < 0) {
return null;
}
int targetIndex = Math.min(index, getMaxElementCount() - 1);
int row = getParentViewIndex(targetIndex, reverseSublists, swapRowsAndColumns);
- return (ViewGroup) getChildAt(row);
+ return getSublist(row);
+ }
+
+ @VisibleForTesting
+ protected ViewGroup getSublist(int index) {
+ return (ViewGroup) getChildAt(index);
}
private int reverseSublistIndex(int index) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
index a1a7566..fd7efc9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
@@ -27,6 +27,7 @@
import com.android.settingslib.Utils;
import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
public class QSCarrier extends LinearLayout {
@@ -35,6 +36,7 @@
private QSCarrierText mCarrierText;
private ImageView mMobileSignal;
private ImageView mMobileRoaming;
+ private DualToneHandler mDualToneHandler;
private ColorStateList mColorForegroundStateList;
private float mColorForegroundIntensity;
@@ -57,6 +59,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mDualToneHandler = new DualToneHandler(getContext());
mMobileGroup = findViewById(R.id.mobile_combo);
mMobileSignal = findViewById(R.id.mobile_signal);
mMobileRoaming = findViewById(R.id.mobile_roaming);
@@ -66,16 +69,17 @@
android.R.attr.colorForeground);
mColorForegroundStateList = ColorStateList.valueOf(colorForeground);
mColorForegroundIntensity = QuickStatusBarHeader.getColorIntensity(colorForeground);
-
}
public void updateState(QSCarrierGroup.CellSignalState state) {
mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
if (state.visible) {
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
- mMobileRoaming.setImageTintList(mColorForegroundStateList);
+ mMobileRoaming.setImageTintList(ColorStateList.valueOf(
+ mDualToneHandler.getSingleColor(mColorForegroundIntensity)));
SignalDrawable d = new SignalDrawable(mContext);
- d.setDarkIntensity(mColorForegroundIntensity);
+ d.setColors(mDualToneHandler.getBackgroundColor(mColorForegroundIntensity),
+ mDualToneHandler.getFillColor(mColorForegroundIntensity));
mMobileSignal.setImageDrawable(d);
mMobileSignal.setImageLevel(state.mobileSignalIconId);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 346ffa2..6adce83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
@@ -39,6 +40,7 @@
import android.util.AttributeSet;
import android.util.Pair;
import android.util.StatsLog;
+import android.view.ContextThemeWrapper;
import android.view.DisplayCutout;
import android.view.View;
import android.view.WindowInsets;
@@ -53,6 +55,7 @@
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
+import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -115,6 +118,7 @@
private TouchAnimator mStatusIconsAlphaAnimator;
private TouchAnimator mHeaderTextContainerAlphaAnimator;
private TouchAnimator mPrivacyChipAlphaAnimator;
+ private DualToneHandler mDualToneHandler;
private View mSystemIconsView;
private View mQuickQsStatusIcons;
@@ -168,6 +172,8 @@
mStatusBarIconController = statusBarIconController;
mActivityStarter = activityStarter;
mPrivacyItemController = privacyItemController;
+ mDualToneHandler = new DualToneHandler(
+ new ContextThemeWrapper(context, R.style.QSHeaderTheme));
}
@Override
@@ -205,13 +211,15 @@
int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.colorForeground);
float intensity = getColorIntensity(colorForeground);
- int fillColor = fillColorForIntensity(intensity, getContext());
+ int fillColor = mDualToneHandler.getSingleColor(intensity);
// Set light text on the header icons because they will always be on a black background
applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
// Set the correct tint for the status icons so they contrast
mIconManager.setTint(fillColor);
+ mNextAlarmIcon.setImageTintList(ColorStateList.valueOf(fillColor));
+ mRingerModeIcon.setImageTintList(ColorStateList.valueOf(fillColor));
mClockView = findViewById(R.id.clock);
mClockView.setOnClickListener(this);
@@ -314,13 +322,6 @@
}
}
- private int fillColorForIntensity(float intensity, Context context) {
- if (intensity == 0) {
- return context.getColor(R.color.light_mode_icon_color_single_tone);
- }
- return context.getColor(R.color.dark_mode_icon_color_single_tone);
- }
-
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -519,9 +520,18 @@
@Override
public void onClick(View v) {
- if (v == mClockView || v == mNextAlarmContainer) {
+ if (v == mClockView) {
mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
- AlarmClock.ACTION_SHOW_ALARMS),0);
+ AlarmClock.ACTION_SHOW_ALARMS), 0);
+ } else if (v == mNextAlarmContainer) {
+ if (mNextAlarm.getShowIntent() != null
+ && mNextAlarm.getShowIntent().getIntent() != null) {
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ mNextAlarm.getShowIntent().getIntent(), 0);
+ } else {
+ mActivityStarter.postStartActivityDismissingKeyguard(new Intent(
+ AlarmClock.ACTION_SHOW_ALARMS), 0);
+ }
} else if (v == mPrivacyChip) {
// Makes sure that the builder is grabbed as soon as the chip is pressed
PrivacyDialogBuilder builder = mPrivacyChip.getBuilder();
@@ -576,8 +586,7 @@
int colorForeground = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.colorForeground);
float intensity = getColorIntensity(colorForeground);
- int fillColor = fillColorForIntensity(intensity, getContext());
- mBatteryRemainingIcon.setColorsFromContext(mHost.getContext());
+ int fillColor = mDualToneHandler.getSingleColor(intensity);
mBatteryRemainingIcon.onDarkChanged(tintArea, intensity, fillColor);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index ee72955..3ace705 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -20,6 +20,7 @@
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
@@ -70,6 +71,7 @@
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.phone.NavigationBarFragment;
+import com.android.systemui.statusbar.phone.NavigationModeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.CallbackController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -87,7 +89,8 @@
* Class to send information from overview to launcher with a binder.
*/
@Singleton
-public class OverviewProxyService implements CallbackController<OverviewProxyListener>, Dumpable {
+public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
+ NavigationModeController.ModeChangedListener, Dumpable {
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
@@ -124,6 +127,7 @@
private MotionEvent mStatusBarGestureDownEvent;
private float mWindowCornerRadius;
private boolean mSupportsRoundedCornersOnWindows;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -427,16 +431,6 @@
private final DeviceProvisionedListener mDeviceProvisionedCallback =
new DeviceProvisionedListener() {
-
- @Override
- public void onDeviceProvisionedChanged() {
- /*
- on initialize, keep track of the previous gestural state (nothing is enabled by default)
- restore to a non gestural state if device is not provisioned
- once the device is provisioned, restore to the original state
- */
- }
-
@Override
public void onUserSetupChanged() {
if (mDeviceProvisionedController.isCurrentUserSetup()) {
@@ -474,6 +468,8 @@
// Assumes device always starts with back button until launcher tells it that it does not
mBackButtonAlpha = 1.0f;
+ mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
+
// Listen for the package update changes.
if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
updateEnabledState();
@@ -483,6 +479,7 @@
filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
PatternMatcher.PATTERN_LITERAL);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ // TODO: Shouldn't this be per-user?
mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
}
}
@@ -678,7 +675,7 @@
private int getDefaultInteractionFlags() {
// If there is no settings available use device default or get it from settings
- return QuickStepContract.isLegacyMode(mContext)
+ return QuickStepContract.isLegacyMode(mNavBarMode)
? DEFAULT_DISABLE_SWIPE_UP_STATE
: 0;
}
@@ -736,6 +733,11 @@
}
@Override
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(TAG_OPS + " state:");
pw.print(" recentsComponentName="); pw.println(mRecentsComponentName);
@@ -747,8 +749,6 @@
pw.print(" quickStepIntent="); pw.println(mQuickStepIntent);
pw.print(" quickStepIntentResolved="); pw.println(isEnabled());
- pw.print(" navBarMode=");
- pw.println(QuickStepContract.getCurrentInteractionMode(mContext));
pw.print(" mSysUiStateFlags="); pw.println(mSysUiStateFlags);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 33a2acf..d0c4734 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.Prefs.Key.DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT;
import static com.android.systemui.Prefs.Key.HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE;
@@ -111,6 +112,7 @@
private final int mOnboardingToastColor;
private final int mOnboardingToastArrowRadius;
private int mNavBarHeight;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private boolean mOverviewProxyListenerRegistered;
private boolean mTaskListenerRegistered;
@@ -339,8 +341,12 @@
} catch (RemoteException e) {}
}
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
public void onConnectedToLauncher() {
- if (!ONBOARDING_ENABLED || QuickStepContract.isGesturalMode(mContext)) {
+ if (!ONBOARDING_ENABLED || QuickStepContract.isGesturalMode(mNavBarMode)) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index ed59f79..9490b14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -306,7 +306,8 @@
return false;
}
boolean exceedsPriorityThreshold;
- if (NotificationUtils.useNewInterruptionModel(mContext)) {
+ if (NotificationUtils.useNewInterruptionModel(mContext)
+ && hideSilentNotificationsOnLockscreen()) {
exceedsPriorityThreshold = getEntryManager().getNotificationData().isHighPriority(sbn);
} else {
exceedsPriorityThreshold =
@@ -315,6 +316,11 @@
return mShowLockscreenNotifications && exceedsPriorityThreshold;
}
+ private boolean hideSilentNotificationsOnLockscreen() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0) == 0;
+ }
+
private void setShowLockscreenNotifications(boolean show) {
mShowLockscreenNotifications = show;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 4db981d..9c6b3be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -36,6 +36,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.graph.SignalDrawable;
+import com.android.systemui.DualToneHandler;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
@@ -57,6 +58,7 @@
private ImageView mMobile, mMobileType, mMobileRoaming;
private View mMobileRoamingSpace;
private int mVisibleState = -1;
+ private DualToneHandler mDualToneHandler;
public static StatusBarMobileView fromContext(Context context, String slot) {
LayoutInflater inflater = LayoutInflater.from(context);
@@ -98,6 +100,7 @@
}
private void init() {
+ mDualToneHandler = new DualToneHandler(getContext());
mMobileGroup = findViewById(R.id.mobile_group);
mMobile = findViewById(R.id.mobile_signal);
mMobileType = findViewById(R.id.mobile_type);
@@ -208,7 +211,8 @@
if (!isInArea(area, this)) {
return;
}
- mMobileDrawable.setDarkIntensity(darkIntensity);
+ mMobileDrawable.setColors(mDualToneHandler.getBackgroundColor(darkIntensity),
+ mDualToneHandler.getFillColor(darkIntensity));
ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
mIn.setImageTintList(color);
mOut.setImageTintList(color);
@@ -231,8 +235,10 @@
public void setStaticDrawableColor(int color) {
ColorStateList list = ColorStateList.valueOf(color);
float intensity = color == Color.WHITE ? 0 : 1;
- mMobileDrawable.setDarkIntensity(intensity);
-
+ // We want the ability to change the theme from the one set by SignalDrawable in certain
+ // surfaces. In this way, we can pass a theme to the view.
+ mMobileDrawable.setColors(mDualToneHandler.getBackgroundColor(intensity),
+ mDualToneHandler.getFillColor(intensity));
mIn.setImageTintList(list);
mOut.setImageTintList(list);
mMobileType.setImageTintList(list);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 6b2efaab..1ef29c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2641,7 +2641,7 @@
private int getHeadsUpHeight() {
- return mPrivateLayout.getHeadsUpHeight();
+ return getShowingLayout().getHeadsUpHeight();
}
public boolean areGutsExposed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index a964849..9b3f05e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -156,7 +156,9 @@
mWm = context.getSystemService(WindowManager.class);
mOverviewProxyService = overviewProxyService;
- mEdgeWidth = QuickStepContract.getEdgeSensitivityWidth(context);
+ // TODO: Get this for the current user
+ mEdgeWidth = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.config_backGestureInset);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mSwipeThreshold = res.getDimension(R.dimen.navigation_edge_action_drag_threshold);
@@ -168,7 +170,7 @@
*/
public void onNavBarAttached() {
mIsAttached = true;
- onOverlaysChanged();
+ updateIsEnabled();
}
/**
@@ -179,11 +181,8 @@
updateIsEnabled();
}
- /**
- * Called when system overlays has changed
- */
- public void onOverlaysChanged() {
- mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mContext);
+ public void onNavigationModeChanged(int mode) {
+ mIsGesturalModeEnabled = QuickStepContract.isGesturalMode(mode);
updateIsEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index b00d874..3c2881d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -54,6 +54,7 @@
public class KeyguardBouncer {
private static final String TAG = "KeyguardBouncer";
+ static final long BOUNCER_FACE_DELAY = 800;
static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
static final float EXPANSION_HIDDEN = 1f;
static final float EXPANSION_VISIBLE = 0f;
@@ -66,6 +67,7 @@
private final DismissCallbackRegistry mDismissCallbackRegistry;
private final Handler mHandler;
private final BouncerExpansionCallback mExpansionCallback;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -93,16 +95,18 @@
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager,
- BouncerExpansionCallback expansionCallback) {
+ BouncerExpansionCallback expansionCallback,
+ KeyguardUpdateMonitor keyguardUpdateMonitor, Handler handler) {
mContext = context;
mCallback = callback;
mLockPatternUtils = lockPatternUtils;
mContainer = container;
- KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mFalsingManager = falsingManager;
mDismissCallbackRegistry = dismissCallbackRegistry;
mExpansionCallback = expansionCallback;
- mHandler = new Handler();
+ mHandler = handler;
+ mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
}
public void show(boolean resetSecuritySelection) {
@@ -164,7 +168,11 @@
// Split up the work over multiple frames.
DejankUtils.removeCallbacks(mResetRunnable);
- DejankUtils.postAfterTraversal(mShowRunnable);
+ if (mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
+ mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
+ } else {
+ DejankUtils.postAfterTraversal(mShowRunnable);
+ }
mCallback.onBouncerVisiblityChanged(true /* shown */);
mExpansionCallback.onStartingToShow();
@@ -266,6 +274,7 @@
private void cancelShowRunnable() {
DejankUtils.removeCallbacks(mShowRunnable);
+ mHandler.removeCallbacks(mShowRunnable);
mShowingSoon = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
index bf5b60a..2f245ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import android.content.Context;
import android.content.res.Resources;
@@ -43,6 +44,7 @@
private final Handler mHandler = new Handler();
private final NavigationBarView mNavigationBarView;
private final LightBarTransitionsController mLightBarController;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private final CompositionSamplingListener mSamplingListener;
private final Runnable mUpdateSamplingListener = this::updateSamplingListener;
@@ -91,7 +93,7 @@
}
void start() {
- if (!isEnabled(mNavigationBarView.getContext())) {
+ if (!isEnabled(mNavigationBarView.getContext(), mNavBarMode)) {
return;
}
mSamplingEnabled = true;
@@ -178,6 +180,10 @@
}
}
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
void dump(PrintWriter pw) {
pw.println("NavBarTintController:");
pw.println(" navBar isAttached: " + mNavigationBarView.isAttachedToWindow());
@@ -190,8 +196,8 @@
pw.println(" mCurrentMedianLuma: " + mCurrentMedianLuma);
}
- public static boolean isEnabled(Context context) {
+ public static boolean isEnabled(Context context, int navBarMode) {
return context.getDisplayId() == DEFAULT_DISPLAY
- && QuickStepContract.isGesturalMode(context);
+ && QuickStepContract.isGesturalMode(navBarMode);
}
}
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 c96c6d7..de57066 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -21,6 +21,7 @@
import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
@@ -119,7 +120,8 @@
* Fragment containing the NavigationBarFragment. Contains logic for what happens
* on clicks and view states of the nav bar.
*/
-public class NavigationBarFragment extends LifecycleFragment implements Callbacks {
+public class NavigationBarFragment extends LifecycleFragment implements Callbacks,
+ NavigationModeController.ModeChangedListener {
public static final String TAG = "NavigationBar";
private static final boolean DEBUG = false;
@@ -160,6 +162,7 @@
private int mLayoutDirection;
private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private LightBarController mLightBarController;
private AutoHideController mAutoHideController;
@@ -209,7 +212,7 @@
final ButtonDispatcher backButton = mNavigationBarView.getBackButton();
final boolean useAltBack =
(mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
- if (QuickStepContract.isGesturalMode(getContext()) && !useAltBack) {
+ if (QuickStepContract.isGesturalMode(mNavBarMode) && !useAltBack) {
// If property was changed to hide/show back button, going home will trigger
// launcher to to change the back button alpha to reflect property change
backButton.setVisibility(View.GONE);
@@ -246,13 +249,15 @@
@Inject
public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper,
DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger,
- AssistManager assistManager, OverviewProxyService overviewProxyService) {
+ AssistManager assistManager, OverviewProxyService overviewProxyService,
+ NavigationModeController navigationModeController) {
mAccessibilityManagerWrapper = accessibilityManagerWrapper;
mDeviceProvisionedController = deviceProvisionedController;
mMetricsLogger = metricsLogger;
mAssistManager = assistManager;
mAssistantAvailable = mAssistManager.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
mOverviewProxyService = overviewProxyService;
+ mNavBarMode = navigationModeController.addListener(this);
}
// ----- Fragment Lifecycle Callbacks -----
@@ -928,7 +933,7 @@
if (mOverviewProxyService.getProxy() != null) {
try {
mOverviewProxyService.getProxy().onAssistantAvailable(available
- && QuickStepContract.isGesturalMode(getContext()));
+ && QuickStepContract.isGesturalMode(mNavBarMode));
} catch (RemoteException e) {
Log.w(TAG, "Unable to send assistant availability data to launcher");
}
@@ -984,6 +989,11 @@
mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim);
}
+ @Override
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
+
public void disableAnimationsDuringHide(long delay) {
mNavigationBarView.setLayoutTransitionsEnabled(false);
mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
@@ -1040,7 +1050,7 @@
if (Intent.ACTION_SCREEN_ON.equals(action)) {
// Enabled and screen is on, start it again if enabled
- if (NavBarTintController.isEnabled(getContext())) {
+ if (NavBarTintController.isEnabled(getContext(), mNavBarMode)) {
mNavigationBarView.getTintController().start();
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index a522ed1c..404c07b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -15,6 +15,7 @@
package com.android.systemui.statusbar.phone;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import android.annotation.Nullable;
import android.content.Context;
@@ -49,7 +50,8 @@
import java.util.Objects;
public class NavigationBarInflaterView extends FrameLayout
- implements Tunable, PluginListener<NavBarButtonProvider> {
+ implements Tunable, PluginListener<NavBarButtonProvider>,
+ NavigationModeController.ModeChangedListener {
private static final String TAG = "NavBarInflater";
@@ -102,11 +104,13 @@
private boolean mUsingCustomLayout;
private OverviewProxyService mOverviewProxyService;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
public NavigationBarInflaterView(Context context, AttributeSet attrs) {
super(context, attrs);
createInflaters();
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+ mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
}
@VisibleForTesting
@@ -138,7 +142,7 @@
}
protected String getDefaultLayout() {
- final int defaultResource = QuickStepContract.isGesturalMode(getContext())
+ final int defaultResource = QuickStepContract.isGesturalMode(mNavBarMode)
? R.string.config_navBarLayoutHandle
: mOverviewProxyService.shouldShowSwipeUpUI()
? R.string.config_navBarLayoutQuickstep
@@ -147,6 +151,12 @@
}
@Override
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ onLikelyDefaultLayoutChange();
+ }
+
+ @Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(TunerService.class).addTunable(this, NAV_BAR_VIEWS, NAV_BAR_LEFT,
@@ -159,6 +169,7 @@
protected void onDetachedFromWindow() {
Dependency.get(TunerService.class).removeTunable(this);
Dependency.get(PluginManager.class).removePluginListener(this);
+ Dependency.get(NavigationModeController.class).removeListener(this);
super.onDetachedFromWindow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 8ff6cc9..4e4a6aec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+
import static com.android.systemui.statusbar.phone.NavBarTintController.DEFAULT_COLOR_ADAPT_TRANSITION_TIME;
import static com.android.systemui.statusbar.phone.NavBarTintController.MIN_COLOR_ADAPT_TRANSITION_TIME;
@@ -46,6 +48,7 @@
private boolean mLightsOut;
private boolean mAutoDim;
private View mNavButtons;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private final Handler mHandler = Handler.getMain();
private final IWallpaperVisibilityListener mWallpaperVisibilityListener =
@@ -176,9 +179,13 @@
@Override
public int getTintAnimationDuration() {
- if (NavBarTintController.isEnabled(mView.getContext())) {
+ if (NavBarTintController.isEnabled(mView.getContext(), mNavBarMode)) {
return Math.max(DEFAULT_COLOR_ADAPT_TRANSITION_TIME, MIN_COLOR_ADAPT_TRANSITION_TIME);
}
return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION;
}
+
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 411378f..6f1e161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -16,8 +16,8 @@
package com.android.systemui.statusbar.phone;
-import static android.content.Intent.ACTION_OVERLAY_CHANGED;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
@@ -31,10 +31,7 @@
import android.animation.ValueAnimator;
import android.annotation.DrawableRes;
import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -84,7 +81,8 @@
import java.io.PrintWriter;
import java.util.function.Consumer;
-public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
+public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture>,
+ NavigationModeController.ModeChangedListener {
final static boolean DEBUG = false;
final static String TAG = "StatusBar/NavBarView";
@@ -104,6 +102,7 @@
boolean mLongClickableAccessibilityButton;
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
+ private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private Rect mHomeButtonBounds = new Rect();
private Rect mBackButtonBounds = new Rect();
@@ -234,13 +233,6 @@
}
};
- private BroadcastReceiver mOverlaysChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onOverlaysChanged();
- }
- };
-
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -287,7 +279,6 @@
mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService);
mTintController = new NavBarTintController(this, getLightTransitionsController());
-
}
public NavBarTintController getTintController() {
@@ -470,7 +461,7 @@
return;
}
- if (QuickStepContract.isGesturalMode(getContext())) {
+ if (QuickStepContract.isGesturalMode(mNavBarMode)) {
drawable.setRotation(degrees);
return;
}
@@ -578,7 +569,7 @@
mBarTransitions.reapplyDarkIntensity();
- boolean disableHome = QuickStepContract.isGesturalMode(getContext())
+ boolean disableHome = QuickStepContract.isGesturalMode(mNavBarMode)
|| ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
// TODO(b/113914868): investigation log for disappearing home button
@@ -588,7 +579,7 @@
// Always disable recents when alternate car mode UI is active and for secondary displays.
boolean disableRecent = isRecentsButtonDisabled();
- boolean disableBack = !useAltBack && (QuickStepContract.isGesturalMode(getContext())
+ boolean disableBack = !useAltBack && (QuickStepContract.isGesturalMode(mNavBarMode)
|| ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
// When screen pinning, don't hide back and home when connected service or back and
@@ -724,7 +715,7 @@
}
public void updateWindowTouchable() {
- boolean touchable = mImeVisible || !QuickStepContract.isGesturalMode(getContext());
+ boolean touchable = mImeVisible || !QuickStepContract.isGesturalMode(mNavBarMode);
setWindowFlag(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, !touchable);
}
@@ -746,16 +737,21 @@
wm.updateViewLayout(navbarView, lp);
}
- private void onOverlaysChanged() {
- mNavigationInflaterView.setNavigationBarLayout(null);
+ @Override
+ public void onNavigationModeChanged(int mode) {
+ mNavBarMode = mode;
+ mBarTransitions.onNavigationModeChanged(mNavBarMode);
+ mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
+ mRecentsOnboarding.onNavigationModeChanged(mNavBarMode);
// Color adaption is tied with showing home handle, only avaliable if visible
- if (QuickStepContract.isGesturalMode(getContext())) {
+ mTintController.onNavigationModeChanged(mNavBarMode);
+ if (QuickStepContract.isGesturalMode(mNavBarMode)) {
mTintController.start();
} else {
mTintController.stop();
}
- mEdgeBackGestureHandler.onOverlaysChanged();
+ updateWindowTouchable();
}
public void setMenuVisibility(final boolean show) {
@@ -938,7 +934,7 @@
"onMeasure: (%dx%d) old: (%dx%d)", w, h, getMeasuredWidth(), getMeasuredHeight()));
final boolean newVertical = w > 0 && h > w
- && !QuickStepContract.isGesturalMode(getContext());
+ && !QuickStepContract.isGesturalMode(mNavBarMode);
if (newVertical != mIsVertical) {
mIsVertical = newVertical;
if (DEBUG) {
@@ -949,7 +945,7 @@
notifyVerticalChangedListener(newVertical);
}
- if (QuickStepContract.isGesturalMode(getContext())) {
+ if (QuickStepContract.isGesturalMode(mNavBarMode)) {
// Update the nav bar background to match the height of the visible nav bar
int height = mIsVertical
? getResources().getDimensionPixelSize(
@@ -1048,11 +1044,10 @@
onPluginDisconnected(null); // Create default gesture helper
Dependency.get(PluginManager.class).addPluginListener(this,
NavGesture.class, false /* Only one */);
+ int navBarMode = Dependency.get(NavigationModeController.class).addListener(this);
+ onNavigationModeChanged(navBarMode);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
- IntentFilter filter = new IntentFilter(ACTION_OVERLAY_CHANGED);
- filter.addDataScheme("package");
- getContext().registerReceiver(mOverlaysChangedReceiver, filter);
mEdgeBackGestureHandler.onNavBarAttached();
updateWindowTouchable();
}
@@ -1061,6 +1056,7 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(PluginManager.class).removePluginListener(this);
+ Dependency.get(NavigationModeController.class).removeListener(this);
if (mGestureHelper != null) {
mGestureHelper.destroy();
}
@@ -1068,8 +1064,6 @@
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).onDestroy();
}
-
- getContext().unregisterReceiver(mOverlaysChangedReceiver);
mEdgeBackGestureHandler.onNavBarDetached();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
new file mode 100644
index 0000000..a00feeb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -0,0 +1,146 @@
+/*
+ * 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 static android.content.Intent.ACTION_OVERLAY_CHANGED;
+import static android.content.Intent.ACTION_USER_SWITCHED;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.om.IOverlayManager;
+import android.content.pm.PackageManager;
+import android.content.res.ApkAssets;
+import android.os.PatternMatcher;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Controller for tracking the current navigation bar mode.
+ */
+@Singleton
+public class NavigationModeController implements Dumpable {
+
+ private static final String TAG = NavigationModeController.class.getName();
+ private static final boolean DEBUG = true;
+
+ public interface ModeChangedListener {
+ void onNavigationModeChanged(int mode);
+ }
+
+ private final Context mContext;
+ private final IOverlayManager mOverlayManager;
+
+ private int mMode = NAV_BAR_MODE_3BUTTON;
+ private ArrayList<ModeChangedListener> mListeners = new ArrayList<>();
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ context = getCurrentUserContext();
+ int mode = getCurrentInteractionMode(context);
+ mMode = mode;
+ if (DEBUG) {
+ Log.e(TAG, "ACTION_OVERLAY_CHANGED: mode=" + mMode
+ + " contextUser=" + context.getUserId());
+ dumpAssetPaths(context);
+ }
+
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).onNavigationModeChanged(mode);
+ }
+ }
+ };
+
+ @Inject
+ public NavigationModeController(Context context) {
+ mContext = context;
+ mOverlayManager = IOverlayManager.Stub.asInterface(
+ ServiceManager.getService(Context.OVERLAY_SERVICE));
+
+ IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+ overlayFilter.addDataScheme("package");
+ overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
+
+ IntentFilter userFilter = new IntentFilter(ACTION_USER_SWITCHED);
+ mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, userFilter, null, null);
+
+ mMode = getCurrentInteractionMode(getCurrentUserContext());
+ }
+
+ public int addListener(ModeChangedListener listener) {
+ mListeners.add(listener);
+ return getCurrentInteractionMode(mContext);
+ }
+
+ public void removeListener(ModeChangedListener listener) {
+ mListeners.remove(listener);
+ }
+
+ private int getCurrentInteractionMode(Context context) {
+ int mode = context.getResources().getInteger(
+ com.android.internal.R.integer.config_navBarInteractionMode);
+ return mode;
+ }
+
+ private Context getCurrentUserContext() {
+ int userId = ActivityManagerWrapper.getInstance().getCurrentUserId();
+ if (DEBUG) {
+ Log.d(TAG, "getCurrentUserContext: contextUser=" + mContext.getUserId()
+ + " currentUser=" + userId);
+ }
+ if (mContext.getUserId() == userId) {
+ return mContext;
+ }
+ try {
+ return mContext.createPackageContextAsUser(mContext.getPackageName(),
+ 0 /* flags */, UserHandle.of(userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ // Never happens for the sysui package
+ return null;
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("NavigationModeController:");
+ pw.println(" mode=" + mMode);
+ dumpAssetPaths(getCurrentUserContext());
+ }
+
+ private void dumpAssetPaths(Context context) {
+ Log.d(TAG, "assetPaths=");
+ ApkAssets[] assets = context.getResources().getAssets().getApkAssets();
+ for (ApkAssets a : assets) {
+ Log.d(TAG, " " + a.getAssetPath());
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index 47a1054..9988c85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+
import android.annotation.IntDef;
import android.content.ComponentCallbacks;
import android.content.Context;
@@ -119,7 +121,7 @@
mListener.onHomeButtonVisibilityChanged(!hideHomeButton());
} else if (path.endsWith(NAV_COLOR_ADAPT_ENABLE_SETTING)) {
mListener.onColorAdaptChanged(
- NavBarTintController.isEnabled(mContext));
+ NavBarTintController.isEnabled(mContext, NAV_BAR_MODE_GESTURAL));
} else if (path.endsWith(SHOW_HOME_HANDLE_SETTING)) {
mListener.onHomeHandleVisiblilityChanged(showHomeHandle());
} else if (path.endsWith(ENABLE_ASSISTANT_GESTURE)) {
@@ -132,7 +134,8 @@
* @return the width for edge swipe
*/
public int getEdgeSensitivityWidth() {
- return QuickStepContract.getEdgeSensitivityWidth(mContext);
+ return mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.config_backGestureInset);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index cc159b4..002313c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -71,7 +71,7 @@
*/
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
- NotificationPanelView.PanelExpansionListener {
+ NotificationPanelView.PanelExpansionListener, NavigationModeController.ModeChangedListener {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -192,10 +192,11 @@
mViewMediatorCallback = callback;
mLockPatternUtils = lockPatternUtils;
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
- mGesturalNav = QuickStepContract.isGesturalMode(context);
KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
mStatusBarStateController.addCallback(this);
Dependency.get(ConfigurationController.class).addCallback(this);
+ mLastGesturalNav = QuickStepContract.isGesturalMode(
+ Dependency.get(NavigationModeController.class).addListener(this));
mDockManager = SysUiServiceProvider.getComponent(context, DockManager.class);
if (mDockManager != null) {
mDockManager.addListener(mDockEventListener);
@@ -587,8 +588,8 @@
}
@Override
- public void onOverlayChanged() {
- boolean gesturalNav = QuickStepContract.isGesturalMode(mContext);
+ public void onNavigationModeChanged(int mode) {
+ boolean gesturalNav = QuickStepContract.isGesturalMode(mode);
if (gesturalNav != mGesturalNav) {
mGesturalNav = gesturalNav;
updateStates();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index fde1455..9c7a1e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -73,7 +73,6 @@
private boolean mTestmode = false;
private boolean mHasReceivedBattery = false;
private Estimate mEstimate;
- private long mLastEstimateTimestamp = -1;
private boolean mFetchingEstimate = false;
@Inject
@@ -203,13 +202,6 @@
@Override
public void getEstimatedTimeRemainingString(EstimateFetchCompletion completion) {
- if (mEstimate != null
- && mLastEstimateTimestamp > System.currentTimeMillis() - UPDATE_GRANULARITY_MSEC) {
- String percentage = generateTimeRemainingString();
- completion.onBatteryRemainingEstimateRetrieved(percentage);
- return;
- }
-
// Need to fetch or refresh the estimate, but it may involve binder calls so offload the
// work
synchronized (mFetchCallbacks) {
@@ -238,8 +230,10 @@
mFetchingEstimate = true;
Dependency.get(Dependency.BG_HANDLER).post(() -> {
// Only fetch the estimate if they are enabled
- mEstimate = mEstimates.isHybridNotificationEnabled() ? mEstimates.getEstimate() : null;
- mLastEstimateTimestamp = System.currentTimeMillis();
+ mEstimate = null;
+ if (mEstimates.isHybridNotificationEnabled()) {
+ updateEstimate();
+ }
mFetchingEstimate = false;
Dependency.get(Dependency.MAIN_HANDLER).post(this::notifyEstimateFetchCallbacks);
});
@@ -258,8 +252,15 @@
}
private void updateEstimate() {
- mEstimate = mEstimates.getEstimate();
- mLastEstimateTimestamp = System.currentTimeMillis();
+ // if the estimate has been cached we can just use that, otherwise get a new one and
+ // throw it in the cache.
+ mEstimate = Estimate.getCachedEstimateIfAvailable(mContext);
+ if (mEstimate == null) {
+ mEstimate = mEstimates.getEstimate();
+ if (mEstimate != null) {
+ Estimate.storeCachedEstimate(mContext, mEstimate);
+ }
+ }
}
private void updatePowerSave() {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index f318f8f..8380b19 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -24,6 +24,7 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
@@ -66,6 +67,7 @@
mUserManager = mContext.getSystemService(UserManager.class);
mThemeManager = new ThemeOverlayManager(
mContext.getSystemService(OverlayManager.class),
+ AsyncTask.THREAD_POOL_EXECUTOR,
mContext.getString(R.string.launcher_overlayable_package));
final Handler bgHandler = Dependency.get(Dependency.BG_HANDLER);
final IntentFilter filter = new IntentFilter();
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
index 51ae70b..27e3b2b 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayManager.java
@@ -31,6 +31,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.stream.Collectors;
class ThemeOverlayManager {
@@ -91,10 +92,13 @@
/* Target package for each overlay category. */
private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>();
private final OverlayManager mOverlayManager;
+ private final Executor mExecutor;
private final String mLauncherPackage;
- ThemeOverlayManager(OverlayManager overlayManager, String launcherPackage) {
+ ThemeOverlayManager(OverlayManager overlayManager, Executor executor,
+ String launcherPackage) {
mOverlayManager = overlayManager;
+ mExecutor = executor;
mLauncherPackage = launcherPackage;
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
OVERLAY_CATEGORY_COLOR, OVERLAY_CATEGORY_FONT,
@@ -149,19 +153,21 @@
private void setEnabled(
String packageName, String category, Set<UserHandle> handles, boolean enabled) {
for (UserHandle userHandle : handles) {
- setEnabled(packageName, userHandle, enabled);
+ setEnabledAsync(packageName, userHandle, enabled);
}
if (!handles.contains(UserHandle.SYSTEM) && SYSTEM_USER_CATEGORIES.contains(category)) {
- setEnabled(packageName, UserHandle.SYSTEM, enabled);
+ setEnabledAsync(packageName, UserHandle.SYSTEM, enabled);
}
}
- private void setEnabled(String pkg, UserHandle userHandle, boolean enabled) {
- if (DEBUG) Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled));
- if (enabled) {
- mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle);
- } else {
- mOverlayManager.setEnabled(pkg, false, userHandle);
- }
+ private void setEnabledAsync(String pkg, UserHandle userHandle, boolean enabled) {
+ mExecutor.execute(() -> {
+ if (DEBUG) Log.d(TAG, String.format("setEnabled: %s %s %b", pkg, userHandle, enabled));
+ if (enabled) {
+ mOverlayManager.setEnabledExclusiveInCategory(pkg, userHandle);
+ } else {
+ mOverlayManager.setEnabled(pkg, false, userHandle);
+ }
+ });
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
new file mode 100644
index 0000000..3c52e9d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsGridLayoutTest.java
@@ -0,0 +1,307 @@
+/*
+ * 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.globalactions;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.MultiListLayout;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.leak.RotationUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link ListGridLayout}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class GlobalActionsGridLayoutTest extends SysuiTestCase {
+
+ private GlobalActionsGridLayout mGridLayout;
+ private TestAdapter mAdapter;
+ private ListGridLayout mListGrid;
+
+ private class TestAdapter extends MultiListLayout.MultiListAdapter {
+ @Override
+ public void onClickItem(int index) { }
+
+ @Override
+ public boolean onLongClickItem(int index) {
+ return true;
+ }
+
+ @Override
+ public int countSeparatedItems() {
+ return -1;
+ }
+
+ @Override
+ public int countListItems() {
+ return -1;
+ }
+
+ @Override
+ public boolean shouldBeSeparated(int position) {
+ return false;
+ }
+
+ @Override
+ public int getCount() {
+ return countSeparatedItems() + countListItems();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return -1;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return null;
+ }
+ }
+
+
+ @Before
+ public void setUp() throws Exception {
+ mGridLayout = spy((GlobalActionsGridLayout)
+ LayoutInflater.from(mContext).inflate(R.layout.global_actions_grid, null));
+ mAdapter = spy(new TestAdapter());
+ mGridLayout.setAdapter(mAdapter);
+ mListGrid = spy(mGridLayout.getListView());
+ doReturn(mListGrid).when(mGridLayout).getListView();
+ }
+
+ @Test
+ public void testShouldSwapRowsAndColumns() {
+ doReturn(RotationUtils.ROTATION_NONE).when(mGridLayout).getCurrentRotation();
+ assertEquals(false, mGridLayout.shouldSwapRowsAndColumns());
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(true, mGridLayout.shouldSwapRowsAndColumns());
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(true, mGridLayout.shouldSwapRowsAndColumns());
+ }
+
+ @Test
+ public void testShouldReverseListItems() {
+ doReturn(View.LAYOUT_DIRECTION_LTR).when(mGridLayout).getLayoutDirection();
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(false, mGridLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mGridLayout).getCurrentRotation();
+ assertEquals(true, mGridLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(true, mGridLayout.shouldReverseListItems());
+
+ doReturn(View.LAYOUT_DIRECTION_RTL).when(mGridLayout).getLayoutDirection();
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(true, mGridLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mGridLayout).getCurrentRotation();
+ assertEquals(false, mGridLayout.shouldReverseListItems());
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(false, mGridLayout.shouldReverseListItems());
+ }
+
+ @Test
+ public void testShouldReverseSublists() {
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(false, mGridLayout.shouldReverseSublists());
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mGridLayout).getCurrentRotation();
+ assertEquals(false, mGridLayout.shouldReverseSublists());
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(true, mGridLayout.shouldReverseSublists());
+ }
+
+ @Test
+ public void testGetAnimationOffsetX() {
+ doReturn(50f).when(mGridLayout).getAnimationDistance();
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mGridLayout).getCurrentRotation();
+ assertEquals(0f, mGridLayout.getAnimationOffsetX(), .01);
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(50f, mGridLayout.getAnimationOffsetX(), .01);
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(-50f, mGridLayout.getAnimationOffsetX(), .01);
+ }
+
+ @Test
+ public void testGetAnimationOffsetY() {
+ doReturn(50f).when(mGridLayout).getAnimationDistance();
+
+ doReturn(RotationUtils.ROTATION_NONE).when(mGridLayout).getCurrentRotation();
+ assertEquals(50f, mGridLayout.getAnimationOffsetY(), .01);
+
+ doReturn(RotationUtils.ROTATION_LANDSCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(0f, mGridLayout.getAnimationOffsetY(), .01);
+
+ doReturn(RotationUtils.ROTATION_SEASCAPE).when(mGridLayout).getCurrentRotation();
+ assertEquals(0f, mGridLayout.getAnimationOffsetY(), .01);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testOnUpdateList_noAdapter() {
+ mGridLayout.setAdapter(null);
+ mGridLayout.updateList();
+ }
+
+ @Test
+ public void testOnUpdateList_noItems() {
+ doReturn(0).when(mAdapter).countSeparatedItems();
+ doReturn(0).when(mAdapter).countListItems();
+ mGridLayout.updateList();
+
+ ViewGroup separatedView = mGridLayout.getSeparatedView();
+ ListGridLayout listView = mGridLayout.getListView();
+
+ assertEquals(0, separatedView.getChildCount());
+ assertEquals(View.GONE, separatedView.getVisibility());
+
+ verify(mListGrid, times(0)).addItem(any());
+ }
+
+ @Test
+ public void testOnUpdateList_resizesFirstSeparatedItem() {
+ doReturn(1).when(mAdapter).countSeparatedItems();
+ doReturn(0).when(mAdapter).countListItems();
+ View firstView = new View(mContext, null);
+ View secondView = new View(mContext, null);
+
+ doReturn(firstView).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(0);
+
+ mGridLayout.updateList();
+
+ ViewGroup.LayoutParams childParams = firstView.getLayoutParams();
+ assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, childParams.width);
+ assertEquals(ViewGroup.LayoutParams.MATCH_PARENT, childParams.height);
+
+ doReturn(2).when(mAdapter).countSeparatedItems();
+ doReturn(secondView).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(1);
+
+ mGridLayout.updateList();
+
+ childParams = firstView.getLayoutParams();
+ assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, childParams.width);
+ assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, childParams.height);
+
+
+ }
+
+ @Test
+ public void testOnUpdateList_onlySeparatedItems() {
+ doReturn(1).when(mAdapter).countSeparatedItems();
+ doReturn(0).when(mAdapter).countListItems();
+ View testView = new View(mContext, null);
+ doReturn(testView).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(0);
+
+ mGridLayout.updateList();
+
+ verify(mListGrid, times(0)).addItem(any());
+ }
+
+ @Test
+ public void testOnUpdateList_oneSeparatedOneList() {
+ doReturn(1).when(mAdapter).countSeparatedItems();
+ doReturn(1).when(mAdapter).countListItems();
+ View view1 = new View(mContext, null);
+ View view2 = new View(mContext, null);
+
+ doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(true).when(mAdapter).shouldBeSeparated(0);
+
+ doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(1);
+
+ mGridLayout.updateList();
+
+ ViewGroup separatedView = mGridLayout.getSeparatedView();
+
+ assertEquals(1, separatedView.getChildCount());
+ assertEquals(View.VISIBLE, separatedView.getVisibility());
+ assertEquals(view1, separatedView.getChildAt(0));
+
+ verify(mListGrid, times(1)).addItem(view2);
+ }
+
+ @Test
+ public void testOnUpdateList_fourInList() {
+ doReturn(0).when(mAdapter).countSeparatedItems();
+ doReturn(4).when(mAdapter).countListItems();
+ View view1 = new View(mContext, null);
+ View view2 = new View(mContext, null);
+ View view3 = new View(mContext, null);
+ View view4 = new View(mContext, null);
+
+ doReturn(view1).when(mAdapter).getView(eq(0), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(0);
+
+ doReturn(view2).when(mAdapter).getView(eq(1), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(1);
+
+ doReturn(view3).when(mAdapter).getView(eq(2), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(2);
+
+ doReturn(view4).when(mAdapter).getView(eq(3), any(), any());
+ doReturn(false).when(mAdapter).shouldBeSeparated(3);
+
+ mGridLayout.updateList();
+
+ ViewGroup separatedView = mGridLayout.getSeparatedView();
+ assertEquals(0, separatedView.getChildCount());
+ assertEquals(View.GONE, separatedView.getVisibility());
+
+ verify(mListGrid, times(1)).addItem(view1);
+ verify(mListGrid, times(1)).addItem(view2);
+ verify(mListGrid, times(1)).addItem(view3);
+ verify(mListGrid, times(1)).addItem(view4);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
index 26f1de8..746140f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ListGridLayoutTest.java
@@ -125,27 +125,27 @@
assertEquals(null,
mListGridLayout.getParentView(-1, false, false));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(0, false, false));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(1, false, false));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(2, false, false));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(3, false, false));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(4, false, false));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(5, false, false));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(6, false, false));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(7, false, false));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(8, false, false));
// above valid range
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(9, false, false));
}
@@ -157,27 +157,27 @@
assertEquals(null,
mListGridLayout.getParentView(-1, true, false));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(0, true, false));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(1, true, false));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(2, true, false));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(3, true, false));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(4, true, false));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(5, true, false));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(6, true, false));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(7, true, false));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(8, true, false));
// above valid range
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(9, true, false));
}
@@ -189,27 +189,27 @@
assertEquals(null,
mListGridLayout.getParentView(-1, false, true));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(0, false, true));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(1, false, true));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(2, false, true));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(3, false, true));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(4, false, true));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(5, false, true));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(6, false, true));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(7, false, true));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(8, false, true));
// above valid range
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(9, false, true));
}
@@ -221,35 +221,38 @@
assertEquals(null,
mListGridLayout.getParentView(-1, true, true));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(0, true, true));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(1, true, true));
- assertEquals(mListGridLayout.getChildAt(2),
+ assertEquals(mListGridLayout.getSublist(2),
mListGridLayout.getParentView(2, true, true));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(3, true, true));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(4, true, true));
- assertEquals(mListGridLayout.getChildAt(1),
+ assertEquals(mListGridLayout.getSublist(1),
mListGridLayout.getParentView(5, true, true));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(6, true, true));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(7, true, true));
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(8, true, true));
// above valid range
- assertEquals(mListGridLayout.getChildAt(0),
+ assertEquals(mListGridLayout.getSublist(0),
mListGridLayout.getParentView(9, true, true));
}
@Test
public void testRemoveAllItems() {
- ViewGroup row1 = (ViewGroup) mListGridLayout.getChildAt(0);
- ViewGroup row2 = (ViewGroup) mListGridLayout.getChildAt(1);
- ViewGroup row3 = (ViewGroup) mListGridLayout.getChildAt(2);
+ ViewGroup row1 = mListGridLayout.getSublist(0);
+ row1.setVisibility(View.VISIBLE);
+ ViewGroup row2 = mListGridLayout.getSublist(1);
+ row2.setVisibility(View.VISIBLE);
+ ViewGroup row3 = mListGridLayout.getSublist(2);
+ row3.setVisibility(View.VISIBLE);
View item1 = new View(mContext, null);
View item2 = new View(mContext, null);
View item3 = new View(mContext, null);
@@ -265,7 +268,66 @@
mListGridLayout.removeAllItems();
assertEquals(0, row1.getChildCount());
+ assertEquals(View.GONE, row1.getVisibility());
assertEquals(0, row2.getChildCount());
- assertEquals(0, row2.getChildCount());
+ assertEquals(View.GONE, row2.getVisibility());
+ assertEquals(0, row3.getChildCount());
+ assertEquals(View.GONE, row3.getVisibility());
+ }
+
+ @Test
+ public void testAddItem() {
+ mListGridLayout.setExpectedCount(4);
+
+ View item1 = new View(mContext, null);
+ View item2 = new View(mContext, null);
+ View item3 = new View(mContext, null);
+ View item4 = new View(mContext, null);
+
+ mListGridLayout.addItem(item1);
+ mListGridLayout.addItem(item2);
+ mListGridLayout.addItem(item3);
+ mListGridLayout.addItem(item4);
+ assertEquals(2, mListGridLayout.getSublist(0).getChildCount());
+ assertEquals(2, mListGridLayout.getSublist(1).getChildCount());
+ assertEquals(0, mListGridLayout.getSublist(2).getChildCount());
+
+ mListGridLayout.removeAllItems();
+ mListGridLayout.addItem(item1);
+
+ assertEquals(1, mListGridLayout.getSublist(0).getChildCount());
+ assertEquals(0, mListGridLayout.getSublist(1).getChildCount());
+ assertEquals(0, mListGridLayout.getSublist(2).getChildCount());
+ }
+
+ @Test
+ public void testAddItem_reverseItems() {
+ mListGridLayout.setExpectedCount(3);
+
+ View item1 = new View(mContext, null);
+ View item2 = new View(mContext, null);
+ View item3 = new View(mContext, null);
+
+ mListGridLayout.addItem(item1);
+ mListGridLayout.addItem(item2);
+ mListGridLayout.addItem(item3);
+
+ ViewGroup sublist = mListGridLayout.getSublist(0);
+
+ assertEquals(item1, sublist.getChildAt(0));
+ assertEquals(item2, sublist.getChildAt(1));
+ assertEquals(item3, sublist.getChildAt(2));
+
+
+ mListGridLayout.removeAllItems();
+ mListGridLayout.setReverseItems(true);
+
+ mListGridLayout.addItem(item1);
+ mListGridLayout.addItem(item2);
+ mListGridLayout.addItem(item3);
+
+ assertEquals(item3, sublist.getChildAt(0));
+ assertEquals(item2, sublist.getChildAt(1));
+ assertEquals(item1, sublist.getChildAt(2));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 490b2ea..49a263a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -17,10 +17,13 @@
package com.android.systemui.statusbar;
import static android.content.Intent.ACTION_USER_SWITCHED;
+import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,6 +38,7 @@
import android.os.Looper;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -152,7 +156,34 @@
assertTrue(mLockscreenUserManager.isLockscreenPublicMode(mCurrentUserId));
}
- private class TestNotificationLockscreenUserManager extends NotificationLockscreenUserManagerImpl {
+ @Test
+ public void testShowSilentNotifications_settingSaysShow() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
+ when(mNotificationData.isHighPriority(any())).thenReturn(false);
+
+ assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+ }
+
+ @Test
+ public void testShowSilentNotifications_settingSaysHide() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
+ when(mNotificationData.isHighPriority(any())).thenReturn(false);
+
+ assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(mock(StatusBarNotification.class)));
+ }
+
+ private class TestNotificationLockscreenUserManager
+ extends NotificationLockscreenUserManagerImpl {
public TestNotificationLockscreenUserManager(Context context) {
super(context);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 575ff16..8fe0c70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -31,6 +32,7 @@
import android.content.res.ColorStateList;
import android.graphics.Color;
+import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.ViewGroup;
@@ -42,6 +44,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardSecurityModel;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
@@ -53,6 +56,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -75,6 +79,10 @@
private ViewTreeObserver mViewTreeObserver;
@Mock
private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private Handler mHandler;
private KeyguardBouncer mBouncer;
@@ -88,7 +96,7 @@
when(mKeyguardHostView.getHeight()).thenReturn(500);
mBouncer = new KeyguardBouncer(getContext(), mViewMediatorCallback,
mLockPatternUtils, container, mDismissCallbackRegistry, mFalsingManager,
- mExpansionCallback) {
+ mExpansionCallback, mKeyguardUpdateMonitor, mHandler) {
@Override
protected void inflateView() {
super.inflateView();
@@ -366,4 +374,22 @@
when(mKeyguardHostView.hasDismissActions()).thenReturn(true);
Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction());
}
+
+ @Test
+ public void testShow_delaysIfFaceAuthIsRunning() {
+ when(mKeyguardUpdateMonitor.isFaceDetectionRunning()).thenReturn(true);
+ mBouncer.show(true /* reset */);
+
+ ArgumentCaptor<Runnable> showRunnable = ArgumentCaptor.forClass(Runnable.class);
+ verify(mHandler).postDelayed(showRunnable.capture(),
+ eq(KeyguardBouncer.BOUNCER_FACE_DELAY));
+
+ mBouncer.hide(false /* destroyView */);
+ verify(mHandler).removeCallbacks(eq(showRunnable.getValue()));
+ }
+
+ @Test
+ public void testRegisterUpdateMonitorCallback() {
+ verify(mKeyguardUpdateMonitor).registerCallback(any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 3ae57e3..ad9c729 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -214,7 +214,8 @@
deviceProvisionedController,
new MetricsLogger(),
mock(AssistManager.class),
- mOverviewProxyService);
+ mOverviewProxyService,
+ mock(NavigationModeController.class));
}
private class HostCallbacksForExternalDisplay extends
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java
index a904704e3..4659afc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayManagerTest.java
@@ -47,13 +47,12 @@
import com.google.android.collect.Maps;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.InOrder;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.HashMap;
@@ -87,7 +86,8 @@
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- mManager = new ThemeOverlayManager(mOverlayManager, LAUNCHER_PACKAGE);
+ mManager = new ThemeOverlayManager(mOverlayManager, MoreExecutors.directExecutor(),
+ LAUNCHER_PACKAGE);
when(mOverlayManager.getOverlayInfosForTarget(ANDROID_PACKAGE, UserHandle.SYSTEM))
.thenReturn(Lists.newArrayList(
createOverlayInfo(TEST_DISABLED_PREFIX + OVERLAY_CATEGORY_COLOR,
@@ -136,17 +136,6 @@
}
@Test
- public void allCategoriesSpecified_enabledInOrder() {
- mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
-
- InOrder inOrder = Mockito.inOrder(mOverlayManager);
- for (String category : THEME_CATEGORIES) {
- inOrder.verify(mOverlayManager)
- .setEnabledExclusiveInCategory(ALL_CATEGORIES_MAP.get(category), TEST_USER);
- }
- }
-
- @Test
public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, TEST_USER_HANDLES);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index e885684..6573c3b 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1031,7 +1031,6 @@
mAppOps.checkPackage(uid, packageName);
} catch (SecurityException e) {
Slog.w(TAG, "checkPackage(): " + packageName + " does not belong to uid " + uid);
- android.util.EventLog.writeEvent(0x534e4554, "120574260", uid, "");
throw new SecurityException(e.getMessage());
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 313c0a8..f5710e3 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2862,7 +2862,7 @@
try {
nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
// With Private DNS bypass support, we can proceed to update the
@@ -3032,7 +3032,7 @@
try {
nai.networkMonitor().notifyNetworkDisconnected();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
mNetworkAgentInfos.remove(nai.messenger);
nai.clatd.update();
@@ -3421,7 +3421,7 @@
try {
nai.networkMonitor().setAcceptPartialConnectivity();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
}
}
@@ -3457,7 +3457,7 @@
try {
nai.networkMonitor().launchCaptivePortalApp();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
});
}
@@ -4085,7 +4085,7 @@
try {
nai.networkMonitor().forceReevaluation(uid);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
}
@@ -5458,7 +5458,7 @@
try {
networkMonitor.start();
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
NetworkInfo networkInfo = nai.networkInfo;
@@ -5515,7 +5515,7 @@
try {
networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
if (networkAgent.everConnected) {
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
@@ -6521,7 +6521,7 @@
networkAgent.networkMonitor().notifyNetworkConnected(
networkAgent.linkProperties, networkAgent.networkCapabilities);
} catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ e.rethrowAsRuntimeException();
}
scheduleUnvalidatedPrompt(networkAgent);
diff --git a/services/core/java/com/android/server/ExplicitHealthCheckController.java b/services/core/java/com/android/server/ExplicitHealthCheckController.java
index 19ab33e..f7c4aac 100644
--- a/services/core/java/com/android/server/ExplicitHealthCheckController.java
+++ b/services/core/java/com/android/server/ExplicitHealthCheckController.java
@@ -18,6 +18,7 @@
import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_HEALTH_CHECK_PASSED_PACKAGE;
import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_REQUESTED_PACKAGES;
import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_SUPPORTED_PACKAGES;
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
import android.Manifest;
import android.annotation.MainThread;
@@ -35,7 +36,6 @@
import android.os.UserHandle;
import android.service.watchdog.ExplicitHealthCheckService;
import android.service.watchdog.IExplicitHealthCheckService;
-import android.service.watchdog.PackageInfo;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
@@ -71,7 +71,7 @@
// To prevent deadlocks between the controller and watchdog threads, we have
// a lock invariant to ALWAYS acquire the PackageWatchdog#mLock before #mLock in this class.
// It's easier to just NOT hold #mLock when calling into watchdog code on this consumer.
- @GuardedBy("mLock") @Nullable private Consumer<List<PackageInfo>> mSupportedConsumer;
+ @GuardedBy("mLock") @Nullable private Consumer<List<PackageConfig>> mSupportedConsumer;
// Called everytime we need to notify the watchdog to sync requests between itself and the
// health check service. In practice, should never be null after it has been #setEnabled.
// To prevent deadlocks between the controller and watchdog threads, we have
@@ -106,7 +106,7 @@
* ensure a happens-before relationship of the set parameters and visibility on other threads.
*/
public void setCallbacks(Consumer<String> passedConsumer,
- Consumer<List<PackageInfo>> supportedConsumer, Runnable notifySyncRunnable) {
+ Consumer<List<PackageConfig>> supportedConsumer, Runnable notifySyncRunnable) {
synchronized (mLock) {
if (mPassedConsumer != null || mSupportedConsumer != null
|| mNotifySyncRunnable != null) {
@@ -146,17 +146,17 @@
return;
}
- getSupportedPackages(supportedPackageInfos -> {
+ getSupportedPackages(supportedPackageConfigs -> {
// Notify the watchdog without lock held
- mSupportedConsumer.accept(supportedPackageInfos);
+ mSupportedConsumer.accept(supportedPackageConfigs);
getRequestedPackages(previousRequestedPackages -> {
synchronized (mLock) {
// Hold lock so requests and cancellations are sent atomically.
// It is important we don't mix requests from multiple threads.
Set<String> supportedPackages = new ArraySet<>();
- for (PackageInfo info : supportedPackageInfos) {
- supportedPackages.add(info.getPackageName());
+ for (PackageConfig config : supportedPackageConfigs) {
+ supportedPackages.add(config.getPackageName());
}
// Note, this may modify newRequestedPackages
newRequestedPackages.retainAll(supportedPackages);
@@ -235,7 +235,7 @@
* Returns the packages that we can request explicit health checks for.
* The packages will be returned to the {@code consumer}.
*/
- private void getSupportedPackages(Consumer<List<PackageInfo>> consumer) {
+ private void getSupportedPackages(Consumer<List<PackageConfig>> consumer) {
synchronized (mLock) {
if (!prepareServiceLocked("get health check supported packages")) {
return;
@@ -244,7 +244,7 @@
Slog.d(TAG, "Getting health check supported packages");
try {
mRemoteService.getSupportedPackages(new RemoteCallback(result -> {
- List<PackageInfo> packages =
+ List<PackageConfig> packages =
result.getParcelableArrayList(EXTRA_SUPPORTED_PACKAGES);
Slog.i(TAG, "Explicit health check supported packages " + packages);
consumer.accept(packages);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index ae0047f..b1aaa82 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -2149,38 +2149,6 @@
}
}
- private int parsePermission(String permission) {
- if (permission.equals("NETWORK")) {
- return INetd.PERMISSION_NETWORK;
- }
- if (permission.equals("SYSTEM")) {
- return INetd.PERMISSION_SYSTEM;
- }
- return INetd.PERMISSION_NONE;
- }
-
- @Override
- public void setPermission(String permission, int[] uids) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.networkSetPermissionForUser(parsePermission(permission), uids);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void clearPermission(int[] uids) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
- try {
- mNetdService.networkClearPermissionForUser(uids);
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
@Override
public void allowProtect(int uid) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 7d0d834..b44009f 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
@@ -27,7 +29,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
-import android.service.watchdog.PackageInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -453,13 +454,13 @@
}
}
- private void onSupportedPackages(List<PackageInfo> supportedPackages) {
+ private void onSupportedPackages(List<PackageConfig> supportedPackages) {
boolean isStateChanged = false;
Map<String, Long> supportedPackageTimeouts = new ArrayMap<>();
- Iterator<PackageInfo> it = supportedPackages.iterator();
+ Iterator<PackageConfig> it = supportedPackages.iterator();
while (it.hasNext()) {
- PackageInfo info = it.next();
+ PackageConfig info = it.next();
supportedPackageTimeouts.put(info.getPackageName(), info.getHealthCheckTimeoutMillis());
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index ba56261..64bcaa0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -113,6 +113,7 @@
private final SparseArray<ScaleLevel> mScaleLevels;
private final LinkedList<VibrationInfo> mPreviousRingVibrations;
private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
+ private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
private final LinkedList<VibrationInfo> mPreviousVibrations;
private final int mPreviousVibrationsLimit;
private final boolean mAllowPriorityVibrationsInLowPowerMode;
@@ -259,6 +260,10 @@
return VibratorService.this.isRingtone(usageHint);
}
+ public boolean isAlarm() {
+ return VibratorService.this.isAlarm(usageHint);
+ }
+
public boolean isFromSystem() {
return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
}
@@ -359,6 +364,7 @@
mPreviousRingVibrations = new LinkedList<>();
mPreviousNotificationVibrations = new LinkedList<>();
+ mPreviousAlarmVibrations = new LinkedList<>();
mPreviousVibrations = new LinkedList<>();
IntentFilter filter = new IntentFilter();
@@ -601,7 +607,7 @@
Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
> ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
- && !vib.isNotification() && !vib.isRingtone()) {
+ && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
Slog.e(TAG, "Ignoring incoming vibration as process with"
+ " uid = " + uid + " is background,"
+ " usage = " + AudioAttributes.usageToString(vib.usageHint));
@@ -633,6 +639,8 @@
previousVibrations = mPreviousRingVibrations;
} else if (vib.isNotification()) {
previousVibrations = mPreviousNotificationVibrations;
+ } else if (vib.isAlarm()) {
+ previousVibrations = mPreviousAlarmVibrations;
} else {
previousVibrations = mPreviousVibrations;
}
@@ -797,6 +805,8 @@
return mNotificationIntensity;
} else if (vib.isHapticFeedback()) {
return mHapticFeedbackIntensity;
+ } else if (vib.isAlarm()) {
+ return Vibrator.VIBRATION_INTENSITY_HIGH;
} else {
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
}
@@ -821,6 +831,8 @@
defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
} else if (vib.isHapticFeedback()) {
defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
+ } else if (vib.isAlarm()) {
+ defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
} else {
// If we don't know what kind of vibration we're playing then just skip scaling for
// now.
@@ -1153,6 +1165,10 @@
return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
}
+ private static boolean isAlarm(int usageHint) {
+ return usageHint == AudioAttributes.USAGE_ALARM;
+ }
+
private void noteVibratorOnLocked(int uid, long millis) {
try {
mBatteryStatsService.noteVibratorOn(uid, millis);
@@ -1384,6 +1400,12 @@
pw.println(info.toString());
}
+ pw.println(" Previous alarm vibrations:");
+ for (VibrationInfo info : mPreviousAlarmVibrations) {
+ pw.print(" ");
+ pw.println(info.toString());
+ }
+
pw.println(" Previous vibrations:");
for (VibrationInfo info : mPreviousVibrations) {
pw.print(" ");
@@ -1449,6 +1471,9 @@
} else if (isHapticFeedback(usage)) {
defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
currentIntensity = mHapticFeedbackIntensity;
+ } else if (isAlarm(usage)) {
+ defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
+ currentIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
} else {
defaultIntensity = 0;
currentIntensity = 0;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d3af8f07..e38defd 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -409,16 +409,16 @@
private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
public void onError(int error) {
switch (error) {
- case AudioSystem.AUDIO_STATUS_SERVER_DIED:
- mRecordMonitor.clear();
+ case AudioSystem.AUDIO_STATUS_SERVER_DIED:
+ mRecordMonitor.onAudioServerDied();
- sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
- SENDMSG_NOOP, 0, 0, null, 0);
- sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
- SENDMSG_QUEUE, 0, 0, null, 0);
- break;
- default:
- break;
+ sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
+ SENDMSG_NOOP, 0, 0, null, 0);
+ sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
+ SENDMSG_QUEUE, 0, 0, null, 0);
+ break;
+ default:
+ break;
}
}
};
@@ -6943,6 +6943,23 @@
return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged);
}
+ //======================
+ // Audio recording state notification from clients
+ //======================
+ /**
+ * Track a recorder provided by the client
+ */
+ public int trackRecorder(IBinder recorder) {
+ return mRecordMonitor.trackRecorder(recorder);
+ }
+
+ /**
+ * Receive an event from the client about a tracked recorder
+ */
+ public void recorderEvent(int riid, int event) {
+ mRecordMonitor.recorderEvent(riid, event);
+ }
+
public void disableRingtoneSync(final int userId) {
final int callingUserId = UserHandle.getCallingUserId();
if (callingUserId != userId) {
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 87b272b..69d1ea7 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -33,7 +33,6 @@
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -50,50 +49,148 @@
// playback configurations that do not contain uid/package name information.
private boolean mHasPublicClients = false;
- private HashMap<Integer, AudioRecordingConfiguration> mRecordConfigs =
- new HashMap<Integer, AudioRecordingConfiguration>();
+ static final class RecordingState {
+ private final int mRiid;
+ private final RecorderDeathHandler mDeathHandler;
+ private boolean mIsActive;
+ private AudioRecordingConfiguration mConfig;
+
+ RecordingState(int riid, RecorderDeathHandler handler) {
+ mRiid = riid;
+ mDeathHandler = handler;
+ }
+
+ RecordingState(AudioRecordingConfiguration config) {
+ mRiid = AudioManager.RECORD_RIID_INVALID;
+ mDeathHandler = null;
+ mConfig = config;
+ }
+
+ int getRiid() {
+ return mRiid;
+ }
+
+ int getPortId() {
+ return mConfig != null ? mConfig.getClientPortId() : -1;
+ }
+
+ AudioRecordingConfiguration getConfig() {
+ return mConfig;
+ }
+
+ boolean hasDeathHandler() {
+ return mDeathHandler != null;
+ }
+
+ boolean isActiveConfiguration() {
+ return mIsActive && mConfig != null;
+ }
+
+ // returns true if status of an active recording has changed
+ boolean setActive(boolean active) {
+ if (mIsActive == active) return false;
+ mIsActive = active;
+ return mConfig != null;
+ }
+
+ // returns true if an active recording has been updated
+ boolean setConfig(AudioRecordingConfiguration config) {
+ if (config.equals(mConfig)) return false;
+ mConfig = config;
+ return mIsActive;
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println("riid " + mRiid + "; active? " + mIsActive);
+ if (mConfig != null) {
+ mConfig.dump(pw);
+ } else {
+ pw.println(" no config");
+ }
+ }
+ }
+ private List<RecordingState> mRecordStates = new ArrayList<RecordingState>();
private final PackageManager mPackMan;
RecordingActivityMonitor(Context ctxt) {
RecMonitorClient.sMonitor = this;
+ RecorderDeathHandler.sMonitor = this;
mPackMan = ctxt.getPackageManager();
}
/**
* Implementation of android.media.AudioSystem.AudioRecordingCallback
*/
- public void onRecordingConfigurationChanged(int event, int uid, int session, int source,
- int portId, boolean silenced, int[] recordingInfo,
+ public void onRecordingConfigurationChanged(int event, int riid, int uid, int session,
+ int source, int portId, boolean silenced,
+ int[] recordingInfo,
AudioEffect.Descriptor[] clientEffects,
AudioEffect.Descriptor[] effects,
int activeSource, String packName) {
+ final AudioRecordingConfiguration config = createRecordingConfiguration(
+ uid, session, source, recordingInfo,
+ portId, silenced, activeSource, clientEffects, effects);
if (MediaRecorder.isSystemOnlyAudioSource(source)) {
- // still want to log event, it just won't appear in recording configurations
- sEventLogger.log(new RecordingEvent(event, uid, session, source, packName)
- .printLog(TAG));
+ // still want to log event, it just won't appear in recording configurations;
+ sEventLogger.log(new RecordingEvent(event, riid, config).printLog(TAG));
return;
}
- String clientEffectName = clientEffects.length == 0 ? "None" : clientEffects[0].name;
- String effectName = effects.length == 0 ? "None" : effects[0].name;
-
- final List<AudioRecordingConfiguration> configsSystem =
- updateSnapshot(event, uid, session, source, recordingInfo,
- portId, silenced, activeSource, clientEffects, effects);
- if (configsSystem != null){
- dispatchCallbacks(configsSystem);
- }
+ dispatchCallbacks(updateSnapshot(event, riid, config));
}
+
+ /**
+ * Track a recorder provided by the client
+ */
+ public int trackRecorder(IBinder recorder) {
+ if (recorder == null) {
+ Log.e(TAG, "trackRecorder called with null token");
+ return AudioManager.RECORD_RIID_INVALID;
+ }
+ final int newRiid = AudioSystem.newAudioRecorderId();
+ RecorderDeathHandler handler = new RecorderDeathHandler(newRiid, recorder);
+ if (!handler.init()) {
+ // probably means that the AudioRecord has already died
+ return AudioManager.RECORD_RIID_INVALID;
+ }
+ synchronized (mRecordStates) {
+ mRecordStates.add(new RecordingState(newRiid, handler));
+ }
+ // a newly added record is inactive, no change in active configs is possible.
+ return newRiid;
+ }
+
+ /**
+ * Receive an event from the client about a tracked recorder
+ */
+ public void recorderEvent(int riid, int event) {
+ int configEvent = event == AudioManager.RECORDER_STATE_STARTED
+ ? AudioManager.RECORD_CONFIG_EVENT_START :
+ event == AudioManager.RECORDER_STATE_STOPPED
+ ? AudioManager.RECORD_CONFIG_EVENT_STOP : AudioManager.RECORD_CONFIG_EVENT_NONE;
+ if (riid == AudioManager.RECORD_RIID_INVALID
+ || configEvent == AudioManager.RECORD_CONFIG_EVENT_NONE) {
+ sEventLogger.log(new RecordingEvent(event, riid, null).printLog(TAG));
+ return;
+ }
+ dispatchCallbacks(updateSnapshot(configEvent, riid, null));
+ }
+
+ void unregisterRecorder(int riid) {
+ dispatchCallbacks(updateSnapshot(AudioManager.RECORD_CONFIG_EVENT_DEATH, riid, null));
+ }
+
private void dispatchCallbacks(List<AudioRecordingConfiguration> configs) {
+ if (configs == null) { // null means "no changes"
+ return;
+ }
synchronized (mClients) {
// list of recording configurations for "public consumption". It is only computed if
// there are non-system recording activity listeners.
final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients
? anonymizeForPublicConsumption(configs) :
new ArrayList<AudioRecordingConfiguration>();
- final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
- while (clientIterator.hasNext()) {
- final RecMonitorClient rmc = clientIterator.next();
+ for (RecMonitorClient rmc : mClients) {
try {
if (rmc.mIsPrivileged) {
rmc.mDispatcherCb.dispatchRecordingConfigChange(configs);
@@ -108,12 +205,12 @@
}
protected void dump(PrintWriter pw) {
- // players
+ // recorders
pw.println("\nRecordActivityMonitor dump time: "
+ DateFormat.getTimeInstance().format(new Date()));
- synchronized(mRecordConfigs) {
- for (AudioRecordingConfiguration conf : mRecordConfigs.values()) {
- conf.dump(pw);
+ synchronized (mRecordStates) {
+ for (RecordingState state : mRecordStates) {
+ state.dump(pw);
}
}
pw.println("\n");
@@ -121,7 +218,7 @@
sEventLogger.dump(pw);
}
- private ArrayList<AudioRecordingConfiguration> anonymizeForPublicConsumption(
+ private static ArrayList<AudioRecordingConfiguration> anonymizeForPublicConsumption(
List<AudioRecordingConfiguration> sysConfigs) {
ArrayList<AudioRecordingConfiguration> publicConfigs =
new ArrayList<AudioRecordingConfiguration>();
@@ -136,11 +233,30 @@
AudioSystem.setRecordingCallback(this);
}
- void clear() {
- synchronized (mRecordConfigs) {
- mRecordConfigs.clear();
+ void onAudioServerDied() {
+ // Remove all RecordingState entries that do not have a death handler (that means
+ // they are tracked by the Audio Server). If there were active entries among removed,
+ // dispatch active configuration changes.
+ List<AudioRecordingConfiguration> configs = null;
+ synchronized (mRecordStates) {
+ boolean configChanged = false;
+ for (Iterator<RecordingState> it = mRecordStates.iterator(); it.hasNext(); ) {
+ RecordingState state = it.next();
+ if (!state.hasDeathHandler()) {
+ if (state.isActiveConfiguration()) {
+ configChanged = true;
+ sEventLogger.log(new RecordingEvent(
+ AudioManager.RECORD_CONFIG_EVENT_DEATH,
+ state.getRiid(), state.getConfig()));
+ }
+ it.remove();
+ }
+ }
+ if (configChanged) {
+ configs = getActiveRecordingConfigurations(true /*isPrivileged*/);
+ }
}
- dispatchCallbacks(new ArrayList<AudioRecordingConfiguration>());
+ dispatchCallbacks(configs);
}
void registerRecordingCallback(IRecordingConfigDispatcher rcdb, boolean isPrivileged) {
@@ -181,21 +297,25 @@
}
List<AudioRecordingConfiguration> getActiveRecordingConfigurations(boolean isPrivileged) {
- synchronized(mRecordConfigs) {
- if (isPrivileged) {
- return new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values());
- } else {
- final List<AudioRecordingConfiguration> configsPublic =
- anonymizeForPublicConsumption(
- new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values()));
- return configsPublic;
+ List<AudioRecordingConfiguration> configs = new ArrayList<AudioRecordingConfiguration>();
+ synchronized (mRecordStates) {
+ for (RecordingState state : mRecordStates) {
+ if (state.isActiveConfiguration()) {
+ configs.add(state.getConfig());
+ }
}
}
+ // AudioRecordingConfiguration objects never get updated. If config changes,
+ // the reference to the config is set in RecordingState.
+ if (!isPrivileged) {
+ configs = anonymizeForPublicConsumption(configs);
+ }
+ return configs;
}
/**
- * Update the internal "view" of the active recording sessions
- * @param event
+ * Create a recording configuration from the provided parameters
+ * @param uid
* @param session
* @param source
* @param recordingFormat see
@@ -207,82 +327,133 @@
* @param activeSource
* @param clientEffects
* @param effects
+ * @return null a configuration object.
+ */
+ private AudioRecordingConfiguration createRecordingConfiguration(int uid,
+ int session, int source, int[] recordingInfo, int portId, boolean silenced,
+ int activeSource, AudioEffect.Descriptor[] clientEffects,
+ AudioEffect.Descriptor[] effects) {
+ final AudioFormat clientFormat = new AudioFormat.Builder()
+ .setEncoding(recordingInfo[0])
+ // FIXME this doesn't support index-based masks
+ .setChannelMask(recordingInfo[1])
+ .setSampleRate(recordingInfo[2])
+ .build();
+ final AudioFormat deviceFormat = new AudioFormat.Builder()
+ .setEncoding(recordingInfo[3])
+ // FIXME this doesn't support index-based masks
+ .setChannelMask(recordingInfo[4])
+ .setSampleRate(recordingInfo[5])
+ .build();
+ final int patchHandle = recordingInfo[6];
+ final String[] packages = mPackMan.getPackagesForUid(uid);
+ final String packageName;
+ if (packages != null && packages.length > 0) {
+ packageName = packages[0];
+ } else {
+ packageName = "";
+ }
+ return new AudioRecordingConfiguration(uid, session, source,
+ clientFormat, deviceFormat, patchHandle, packageName,
+ portId, silenced, activeSource, clientEffects, effects);
+ }
+
+ /**
+ * Update the internal "view" of the active recording sessions
+ * @param event RECORD_CONFIG_EVENT_...
+ * @param riid
+ * @param config
* @return null if the list of active recording sessions has not been modified, a list
* with the current active configurations otherwise.
*/
- private List<AudioRecordingConfiguration> updateSnapshot(int event, int uid, int session,
- int source, int[] recordingInfo, int portId, boolean silenced, int activeSource,
- AudioEffect.Descriptor[] clientEffects, AudioEffect.Descriptor[] effects) {
- final boolean configChanged;
- final ArrayList<AudioRecordingConfiguration> configs;
- synchronized(mRecordConfigs) {
- switch (event) {
- case AudioManager.RECORD_CONFIG_EVENT_STOP:
- // return failure if an unknown recording session stopped
- configChanged = (mRecordConfigs.remove(new Integer(portId)) != null);
- if (configChanged) {
- sEventLogger.log(new RecordingEvent(event, uid, session, source, null));
- }
- break;
- case AudioManager.RECORD_CONFIG_EVENT_START:
- final AudioFormat clientFormat = new AudioFormat.Builder()
- .setEncoding(recordingInfo[0])
- // FIXME this doesn't support index-based masks
- .setChannelMask(recordingInfo[1])
- .setSampleRate(recordingInfo[2])
- .build();
- final AudioFormat deviceFormat = new AudioFormat.Builder()
- .setEncoding(recordingInfo[3])
- // FIXME this doesn't support index-based masks
- .setChannelMask(recordingInfo[4])
- .setSampleRate(recordingInfo[5])
- .build();
- final int patchHandle = recordingInfo[6];
- final Integer portIdKey = new Integer(portId);
-
- final String[] packages = mPackMan.getPackagesForUid(uid);
- final String packageName;
- if (packages != null && packages.length > 0) {
- packageName = packages[0];
+ private List<AudioRecordingConfiguration> updateSnapshot(
+ int event, int riid, AudioRecordingConfiguration config) {
+ List<AudioRecordingConfiguration> configs = null;
+ synchronized (mRecordStates) {
+ int stateIndex = -1;
+ if (riid != AudioManager.RECORD_RIID_INVALID) {
+ stateIndex = findStateByRiid(riid);
+ } else if (config != null) {
+ stateIndex = findStateByPortId(config.getClientPortId());
+ }
+ if (stateIndex == -1) {
+ if (event == AudioManager.RECORD_CONFIG_EVENT_START && config != null) {
+ // First time registration for a recorder tracked by AudioServer.
+ mRecordStates.add(new RecordingState(config));
+ stateIndex = mRecordStates.size() - 1;
} else {
- packageName = "";
- }
- final AudioRecordingConfiguration updatedConfig =
- new AudioRecordingConfiguration(uid, session, source,
- clientFormat, deviceFormat, patchHandle, packageName,
- portId, silenced, activeSource, clientEffects, effects);
-
- if (mRecordConfigs.containsKey(portIdKey)) {
- if (updatedConfig.equals(mRecordConfigs.get(portIdKey))) {
- configChanged = false;
- } else {
- // config exists but has been modified
- mRecordConfigs.remove(portIdKey);
- mRecordConfigs.put(portIdKey, updatedConfig);
- configChanged = true;
+ if (config == null) {
+ // Records tracked by clients must be registered first via trackRecorder.
+ Log.e(TAG, String.format(
+ "Unexpected event %d for riid %d", event, riid));
}
- } else {
- mRecordConfigs.put(portIdKey, updatedConfig);
- configChanged = true;
+ return configs;
}
- if (configChanged) {
- sEventLogger.log(new RecordingEvent(event, uid, session, source, packageName));
- }
- break;
- default:
- Log.e(TAG, String.format("Unknown event %d for session %d, source %d",
- event, session, source));
- configChanged = false;
+ }
+ final RecordingState state = mRecordStates.get(stateIndex);
+
+ boolean configChanged;
+ switch (event) {
+ case AudioManager.RECORD_CONFIG_EVENT_START:
+ configChanged = state.setActive(true);
+ if (config != null) { // ??? Can remove ???
+ configChanged = state.setConfig(config) || configChanged;
+ }
+ break;
+ case AudioManager.RECORD_CONFIG_EVENT_UPDATE:
+ // For this event config != null
+ configChanged = state.setConfig(config);
+ break;
+ case AudioManager.RECORD_CONFIG_EVENT_STOP:
+ configChanged = state.setActive(false);
+ if (!state.hasDeathHandler()) {
+ // A recorder tracked by AudioServer has to be removed now so it
+ // does not leak. It will be re-registered if recording starts again.
+ mRecordStates.remove(stateIndex);
+ }
+ break;
+ case AudioManager.RECORD_CONFIG_EVENT_DEATH:
+ configChanged = state.isActiveConfiguration();
+ mRecordStates.remove(stateIndex);
+ break;
+ default:
+ Log.e(TAG, String.format("Unknown event %d for riid %d / portid %d",
+ event, riid, state.getPortId()));
+ configChanged = false;
}
if (configChanged) {
- configs = new ArrayList<AudioRecordingConfiguration>(mRecordConfigs.values());
- } else {
- configs = null;
+ sEventLogger.log(new RecordingEvent(event, riid, state.getConfig()));
+ configs = getActiveRecordingConfigurations(true /*isPrivileged*/);
}
}
return configs;
}
+ // riid is assumed to be valid
+ private int findStateByRiid(int riid) {
+ synchronized (mRecordStates) {
+ for (int i = 0; i < mRecordStates.size(); i++) {
+ if (mRecordStates.get(i).getRiid() == riid) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ private int findStateByPortId(int portId) {
+ // Lookup by portId is unambiguous only for recordings managed by the Audio Server.
+ synchronized (mRecordStates) {
+ for (int i = 0; i < mRecordStates.size(); i++) {
+ if (!mRecordStates.get(i).hasDeathHandler()
+ && mRecordStates.get(i).getPortId() == portId) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
/**
* Inner class to track clients that want to be notified of recording updates
*/
@@ -319,28 +490,80 @@
}
}
+ private static final class RecorderDeathHandler implements IBinder.DeathRecipient {
+
+ // can afford to be static because only one RecordingActivityMonitor ever instantiated
+ static RecordingActivityMonitor sMonitor;
+
+ final int mRiid;
+ private final IBinder mRecorderToken;
+
+ RecorderDeathHandler(int riid, IBinder recorderToken) {
+ mRiid = riid;
+ mRecorderToken = recorderToken;
+ }
+
+ public void binderDied() {
+ sMonitor.unregisterRecorder(mRiid);
+ }
+
+ boolean init() {
+ try {
+ mRecorderToken.linkToDeath(this, 0);
+ return true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not link to recorder death", e);
+ return false;
+ }
+ }
+ }
+
/**
* Inner class for recording event logging
*/
private static final class RecordingEvent extends AudioEventLogger.Event {
private final int mRecEvent;
+ private final int mRIId;
private final int mClientUid;
private final int mSession;
private final int mSource;
private final String mPackName;
- RecordingEvent(int event, int uid, int session, int source, String packName) {
+ RecordingEvent(int event, int riid, AudioRecordingConfiguration config) {
mRecEvent = event;
- mClientUid = uid;
- mSession = session;
- mSource = source;
- mPackName = packName;
+ mRIId = riid;
+ if (config != null) {
+ mClientUid = config.getClientUid();
+ mSession = config.getClientAudioSessionId();
+ mSource = config.getClientAudioSource();
+ mPackName = config.getClientPackageName();
+ } else {
+ mClientUid = -1;
+ mSession = -1;
+ mSource = -1;
+ mPackName = null;
+ }
+ }
+
+ private static String recordEventToString(int recEvent) {
+ switch (recEvent) {
+ case AudioManager.RECORD_CONFIG_EVENT_START:
+ return "start";
+ case AudioManager.RECORD_CONFIG_EVENT_UPDATE:
+ return "update";
+ case AudioManager.RECORD_CONFIG_EVENT_STOP:
+ return "stop";
+ case AudioManager.RECORD_CONFIG_EVENT_DEATH:
+ return "death";
+ default:
+ return "unknown (" + recEvent + ")";
+ }
}
@Override
public String eventToString() {
- return new StringBuilder("rec ").append(
- mRecEvent == AudioManager.RECORD_CONFIG_EVENT_START ? "start" : "stop ")
+ return new StringBuilder("rec ").append(recordEventToString(mRecEvent))
+ .append(" riid:").append(mRIId)
.append(" uid:").append(mClientUid)
.append(" session:").append(mSession)
.append(" src:").append(MediaRecorder.toLogFriendlyAudioSource(mSource))
@@ -349,5 +572,5 @@
}
private static final AudioEventLogger sEventLogger = new AudioEventLogger(50,
- "recording activity as reported through AudioSystem.AudioRecordingCallback");
+ "recording activity received by AudioService");
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 1c18771..c54bfc0 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -400,10 +400,7 @@
* @throws IOException if there was an issue with local database update.
*/
private void setGenerationId(int userId, int generationId) throws IOException {
- long updatedRows = mDatabase.setPlatformKeyGenerationId(userId, generationId);
- if (updatedRows < 0) {
- throw new IOException("Failed to set the platform key in the local DB.");
- }
+ mDatabase.setPlatformKeyGenerationId(userId, generationId);
}
/**
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index 3f5ac8e..c739650 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -322,19 +322,18 @@
/**
* Sets the {@code generationId} of the platform key for user {@code userId}.
*
- * @return The primary key ID of the relation.
+ * @return The number of updated rows.
*/
public long setPlatformKeyGenerationId(int userId, int generationId) {
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, userId);
values.put(UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID, generationId);
- long result = db.replace(
- UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values);
- if (result != -1) {
- invalidateKeysWithOldGenerationId(userId, generationId);
- }
- return result;
+ String selection = UserMetadataEntry.COLUMN_NAME_USER_ID + " = ?";
+ String[] selectionArguments = new String[] {String.valueOf(userId)};
+
+ ensureUserMetadataEntryExists(userId);
+ return db.update(UserMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
}
/**
@@ -377,16 +376,19 @@
/**
* Sets the {@code serialNumber} for the user {@code userId}.
*
- * @return The primary key of the inserted row, or -1 if failed.
+ * @return The number of updated rows.
*/
public long setUserSerialNumber(int userId, long serialNumber) {
SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, userId);
values.put(UserMetadataEntry.COLUMN_NAME_USER_SERIAL_NUMBER, serialNumber);
- long result = db.replace(
- UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values);
- return result;
+ String selection = UserMetadataEntry.COLUMN_NAME_USER_ID + " = ?";
+ String[] selectionArguments = new String[] {String.valueOf(userId)};
+
+ ensureUserMetadataEntryExists(userId);
+ return db.update(UserMetadataEntry.TABLE_NAME, values, selection, selectionArguments);
+
}
/**
@@ -1326,6 +1328,18 @@
}
/**
+ * Creates an empty row in the user metadata table if such a row doesn't exist for
+ * the given userId, so db.update will succeed.
+ */
+ private void ensureUserMetadataEntryExists(int userId) {
+ SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, userId);
+ db.insertWithOnConflict(UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null,
+ values, SQLiteDatabase.CONFLICT_IGNORE);
+ }
+
+ /**
* Closes all open connections to the database.
*/
public void close() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a25f8c0..e08af6f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2470,6 +2470,7 @@
mProtectedPackages = new ProtectedPackages(mContext);
+ mApexManager = new ApexManager(context);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
@@ -3295,7 +3296,6 @@
}
}
- mApexManager = new ApexManager(context);
mInstallerService = new PackageInstallerService(context, this, mApexManager);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
@@ -11702,6 +11702,11 @@
"Code and resource paths haven't been set correctly");
}
+ if (mApexManager.isApexPackage(pkg.packageName)) {
+ throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ pkg.packageName + " is an APEX package and can't be installed as an APK.");
+ }
+
// Make sure we're not adding any bogus keyset info
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 9d6efb4..637ad03 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -1323,14 +1323,17 @@
}
}
- /** Returns true if the focus activity was adjusted to the home stack top activity. */
- boolean moveHomeActivityToTop(String reason) {
+ /**
+ * Moves the focusable home activity to top. If there is no such activity, the home stack will
+ * still move to top.
+ */
+ void moveHomeActivityToTop(String reason) {
final ActivityRecord top = getHomeActivity();
if (top == null) {
- return false;
+ moveHomeStackToFront(reason);
+ return;
}
top.moveFocusableActivityToTop(reason);
- return true;
}
@Nullable
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5a910f49..4278860 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -418,6 +418,9 @@
private final Configuration mTmpConfig = new Configuration();
private final Rect mTmpBounds = new Rect();
+ // Token for targeting this activity for assist purposes.
+ final Binder assistToken = new Binder();
+
private static String startingWindowStateToString(int state) {
switch (state) {
case STARTING_WINDOW_NOT_SHOWN:
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 9c97674..c992a69 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -837,7 +837,8 @@
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
- dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded()));
+ dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
+ r.assistToken));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 48aee20..ed56501 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -34,6 +34,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.voice.IVoiceInteractionSession;
+import android.util.Pair;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
@@ -89,6 +90,16 @@
AppProtoEnums.APP_TRANSITION_RECENTS_ANIM; // 5
/**
+ * The id of the task source of assist state.
+ */
+ public static final String ASSIST_TASK_ID = "taskId";
+
+ /**
+ * The id of the activity source of assist state.
+ */
+ public static final String ASSIST_ACTIVITY_ID = "activityId";
+
+ /**
* The bundle key to extract the assist data.
*/
public static final String ASSIST_KEY_DATA = "data";
@@ -328,6 +339,40 @@
public abstract CompatibilityInfo compatibilityInfoForPackage(ApplicationInfo ai);
+ public final class ActivityTokens {
+ private final @NonNull IBinder mActivityToken;
+ private final @NonNull IBinder mAssistToken;
+ private final @NonNull IApplicationThread mAppThread;
+
+ public ActivityTokens(@NonNull IBinder activityToken,
+ @NonNull IBinder assistToken, @NonNull IApplicationThread appThread) {
+ mActivityToken = activityToken;
+ mAssistToken = assistToken;
+ mAppThread = appThread;
+ }
+
+ /**
+ * @return The activity token.
+ */
+ public @NonNull IBinder getActivityToken() {
+ return mActivityToken;
+ }
+
+ /**
+ * @return The assist token.
+ */
+ public @NonNull IBinder getAssistToken() {
+ return mAssistToken;
+ }
+
+ /**
+ * @return The assist token.
+ */
+ public @NonNull IApplicationThread getApplicationThread() {
+ return mAppThread;
+ }
+ }
+
/**
* Set the corresponding display information for the process global configuration. To be called
* when we need to show IME on a different display.
@@ -341,6 +386,14 @@
String resultWho, int requestCode, int resultCode, Intent data);
public abstract void clearPendingResultForActivity(
IBinder activityToken, WeakReference<PendingIntentRecord> pir);
+
+ /**
+ * @return the activity token and IApplicationThread for the top activity in the task or null
+ * if there isn't a top activity with a valid process.
+ */
+ @Nullable
+ public abstract ActivityTokens getTopActivityForTask(int taskId);
+
public abstract IIntentSender getIntentSender(int type, String packageName,
int callingUid, int userId, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0820b0d..7bc9600 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -108,10 +108,12 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_ACTIVITY_ID;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_TASK_ID;
import static com.android.server.wm.ActivityTaskManagerService.H.REPORT_TIME_TRACKER_MSG;
import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
@@ -214,6 +216,7 @@
import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -3000,6 +3003,10 @@
if ((sendReceiver = pae.receiver) != null) {
// Caller wants result sent back to them.
sendBundle = new Bundle();
+ sendBundle.putInt(ActivityTaskManagerInternal.ASSIST_TASK_ID,
+ pae.activity.getTaskRecord().taskId);
+ sendBundle.putBinder(ActivityTaskManagerInternal.ASSIST_ACTIVITY_ID,
+ pae.activity.assistToken);
sendBundle.putBundle(ASSIST_KEY_DATA, pae.extras);
sendBundle.putParcelable(ASSIST_KEY_STRUCTURE, pae.structure);
sendBundle.putParcelable(ASSIST_KEY_CONTENT, pae.content);
@@ -6547,6 +6554,31 @@
}
@Override
+ public ActivityTokens getTopActivityForTask(int taskId) {
+ synchronized (mGlobalLock) {
+ final TaskRecord taskRecord = mRootActivityContainer.anyTaskForId(taskId);
+ if (taskRecord == null) {
+ Slog.w(TAG, "getApplicationThreadForTopActivity failed:"
+ + " Requested task not found");
+ return null;
+ }
+ final ActivityRecord activity = taskRecord.getTopActivity();
+ if (activity == null) {
+ Slog.w(TAG, "getApplicationThreadForTopActivity failed:"
+ + " Requested activity not found");
+ return null;
+ }
+ if (!activity.attachedToProcess()) {
+ Slog.w(TAG, "getApplicationThreadForTopActivity failed: No process for "
+ + activity);
+ return null;
+ }
+ return new ActivityTokens(activity.appToken, activity.assistToken,
+ activity.app.getThread());
+ }
+ }
+
+ @Override
public IIntentSender getIntentSender(int type, String packageName,
int callingUid, int userId, IBinder token, String resultWho,
int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index aeff99d..df93195 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -142,7 +142,7 @@
/**
* Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k.
*/
- private static final int Z_BOOST_BASE = 800570000;
+ @VisibleForTesting static final int Z_BOOST_BASE = 800570000;
// Non-null only for application tokens.
final IApplicationToken appToken;
@@ -291,7 +291,7 @@
private boolean mFreezingScreen;
/** Whether this token should be boosted at the top of all app window tokens. */
- private boolean mNeedsZBoost;
+ @VisibleForTesting boolean mNeedsZBoost;
private Letterbox mLetterbox;
private final Point mTmpPoint = new Point();
@@ -2693,7 +2693,9 @@
if (mNeedsZBoost) {
layer += Z_BOOST_BASE;
}
- leash.setLayer(layer);
+ if (!mNeedsAnimationBoundsLayer) {
+ leash.setLayer(layer);
+ }
final DisplayContent dc = getDisplayContent();
dc.assignStackOrdering();
@@ -2730,6 +2732,7 @@
// Crop to stack bounds.
t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
+ t.setLayer(mAnimationBoundsLayer, layer);
// Reparent leash to animation bounds layer.
t.reparent(leash, mAnimationBoundsLayer);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 363db54..df36b09 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -264,7 +264,8 @@
// Keyguard.
return dismissKeyguard && canDismissKeyguard() && !mAodShowing
&& (mDismissalRequested
- || getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r);
+ || (r.canShowWhenLocked()
+ && getDisplay(r.getDisplayId()).mDismissingKeyguardActivity != r));
}
/**
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 23911e6..e0ab722 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -884,7 +884,7 @@
if (isVisibleRecentTask(tr)) {
numVisibleTasks++;
- if (isInVisibleRange(tr, numVisibleTasks, withExcluded)) {
+ if (isInVisibleRange(tr, i, numVisibleTasks, withExcluded)) {
// Fall through
} else {
// Not in visible range
@@ -989,7 +989,7 @@
final TaskRecord tr = mTasks.get(i);
if (isVisibleRecentTask(tr)) {
numVisibleTasks++;
- if (isInVisibleRange(tr, numVisibleTasks, false /* skipExcludedCheck */)) {
+ if (isInVisibleRange(tr, i, numVisibleTasks, false /* skipExcludedCheck */)) {
res.put(tr.taskId, true);
}
}
@@ -1210,7 +1210,7 @@
continue;
} else {
numVisibleTasks++;
- if (isInVisibleRange(task, numVisibleTasks, false /* skipExcludedCheck */)
+ if (isInVisibleRange(task, i, numVisibleTasks, false /* skipExcludedCheck */)
|| !isTrimmable(task)) {
// Keep visible tasks in range
i++;
@@ -1325,7 +1325,7 @@
/**
* @return whether the given visible task is within the policy range.
*/
- private boolean isInVisibleRange(TaskRecord task, int numVisibleTasks,
+ private boolean isInVisibleRange(TaskRecord task, int taskIndex, int numVisibleTasks,
boolean skipExcludedCheck) {
if (!skipExcludedCheck) {
// Keep the most recent task even if it is excluded from recents
@@ -1334,7 +1334,7 @@
== FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
if (isExcludeFromRecents) {
if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\texcludeFromRecents=true");
- return numVisibleTasks == 1;
+ return taskIndex == 0;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d46aa7b..dae29b2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7550,20 +7550,24 @@
}
if (shouldWaitForAnimToComplete) {
- waitForAnimationsToComplete();
-
- synchronized (mGlobalLock) {
- mWindowPlacerLocked.performSurfacePlacementIfScheduled();
- mRoot.forAllDisplays(displayContent ->
- displayContent.getInputMonitor().updateInputWindowsImmediately());
- }
-
- new SurfaceControl.Transaction().syncInputWindows().apply(true);
+ syncInputTransactions();
}
return LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode);
}
+ @Override
+ public void syncInputTransactions() {
+ waitForAnimationsToComplete();
+
+ synchronized (mGlobalLock) {
+ mWindowPlacerLocked.performSurfacePlacementIfScheduled();
+ mRoot.forAllDisplays(displayContent ->
+ displayContent.getInputMonitor().updateInputWindowsImmediately());
+ }
+ new SurfaceControl.Transaction().syncInputWindows().apply(true);
+ }
+
private void waitForAnimationsToComplete() {
synchronized (mGlobalLock) {
long timeoutRemaining = ANIMATION_COMPLETED_TIMEOUT_MS;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8f1709e..c5a2068 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -546,9 +546,7 @@
private DevicePolicyConstants mConstants;
- private static boolean ENABLE_LOCK_GUARD = Build.IS_ENG
- || true // STOPSHIP Remove it.
- || (SystemProperties.getInt("debug.dpm.lock_guard", 0) == 1);
+ private static final boolean ENABLE_LOCK_GUARD = true;
interface Stats {
int LOCK_GUARD_GUARD = 0;
@@ -1379,7 +1377,7 @@
}
}
- void readFromXml(XmlPullParser parser)
+ void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
@@ -1390,7 +1388,10 @@
}
String tag = parser.getName();
if (TAG_POLICIES.equals(tag)) {
- info.readPoliciesFromXml(parser);
+ if (shouldOverridePolicies) {
+ Log.d(LOG_TAG, "Overriding device admin policies from XML.");
+ info.readPoliciesFromXml(parser);
+ }
} else if (TAG_PASSWORD_QUALITY.equals(tag)) {
minimumPasswordMetrics.quality = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
@@ -1518,9 +1519,8 @@
}
} else if (TAG_PARENT_ADMIN.equals(tag)) {
Preconditions.checkState(!isParent);
-
parentAdmin = new ActiveAdmin(info, /* parent */ true);
- parentAdmin.readFromXml(parser);
+ parentAdmin.readFromXml(parser, shouldOverridePolicies);
} else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
organizationColor = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
@@ -3326,8 +3326,10 @@
+ userHandle);
}
if (dai != null) {
+ boolean shouldOverwritePolicies =
+ shouldOverwritePoliciesFromXml(dai.getComponent(), userHandle);
ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false);
- ap.readFromXml(parser);
+ ap.readFromXml(parser, shouldOverwritePolicies);
policy.mAdminMap.put(ap.info.getComponent(), ap);
}
} catch (RuntimeException e) {
@@ -3437,6 +3439,14 @@
}
}
+ private boolean shouldOverwritePoliciesFromXml(
+ ComponentName deviceAdminComponent, int userHandle) {
+ // http://b/123415062: If DA, overwrite with the stored policies that were agreed by the
+ // user to prevent apps from sneaking additional policies into updates.
+ return !isProfileOwner(deviceAdminComponent, userHandle)
+ && !isDeviceOwner(deviceAdminComponent, userHandle);
+ }
+
private void updateLockTaskPackagesLocked(List<String> packages, int userId) {
long ident = mInjector.binderClearCallingIdentity();
try {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index 932a769..bac8414 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -305,6 +305,32 @@
}
@Test
+ public void setUserSerialNumbers_keepsPlatformKeyGenerationId() {
+ int userId = 42;
+ int generationId = 110;
+ Long serialNumber = 10L;
+
+ mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
+ mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber);
+
+ assertEquals(generationId, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(userId));
+ }
+
+ @Test
+ public void setPlatformKeyGenerationId_keepsUserSerialNumber() {
+ int userId = 42;
+ int generationId = 110;
+ Long serialNumber = 10L;
+
+ mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId);
+ mRecoverableKeyStoreDb.setUserSerialNumber(userId, serialNumber);
+ mRecoverableKeyStoreDb.setPlatformKeyGenerationId(userId, generationId + 1);
+
+ assertEquals(serialNumber, mRecoverableKeyStoreDb.getUserSerialNumbers().get(userId));
+ }
+
+
+ @Test
public void removeUserFromAllTables_removesData() throws Exception {
int userId = 12;
int generationId = 24;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 1e00b30..757267e5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -930,6 +930,23 @@
}
@Test
+ public void testAdjustFocusedStackToHomeWhenNoActivity() {
+ final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
+ mStack.moveToFront("testAdjustFocusedStack");
+
+ final ActivityStack homeStask = mDefaultDisplay.getHomeStack();
+ final TaskRecord homeTask = homeStask.topTask();
+ // Simulate that home activity has not been started or is force-stopped.
+ homeStask.removeTask(homeTask, "testAdjustFocusedStack", REMOVE_TASK_MODE_DESTROYING);
+
+ // Finish the only activity.
+ mStack.finishActivityLocked(topActivity, 0 /* resultCode */, null /* resultData */,
+ "testAdjustFocusedStack", false /* oomAdj */);
+ // Although home stack is empty, it should still be the focused stack.
+ assertEquals(homeStask, mDefaultDisplay.getFocusedStack());
+ }
+
+ @Test
public void testWontFinishHomeStackImmediately() {
final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index db04f11..623559e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -25,6 +25,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.intThat;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
@@ -75,6 +76,16 @@
}
@Test
+ public void clipAfterAnim_boundsLayerZBoosted() {
+ mToken.mNeedsAnimationBoundsLayer = true;
+ mToken.mNeedsZBoost = true;
+
+ mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ verify(mTransaction).setLayer(eq(mToken.mAnimationBoundsLayer),
+ intThat(layer -> layer >= AppWindowToken.Z_BOOST_BASE));
+ }
+
+ @Test
public void clipAfterAnim_boundsLayerIsDestroyed() {
mToken.mNeedsAnimationBoundsLayer = true;
mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 4d7ae73..5903005 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
@@ -47,6 +48,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -712,6 +714,45 @@
}
@Override
+ public void requestDirectActions(@NonNull IBinder token, int taskId, IBinder assistToken,
+ @NonNull RemoteCallback callback) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "requestDirectActions without running voice interaction service");
+ callback.sendResult(null);
+ return;
+ }
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.requestDirectActionsLocked(token, taskId, assistToken, callback);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
+ public void performDirectAction(@NonNull IBinder token, @NonNull String actionId,
+ @NonNull Bundle arguments, int taskId, IBinder assistToken,
+ @Nullable RemoteCallback cancellationCallback,
+ @NonNull RemoteCallback resultCallback) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "performDirectAction without running voice interaction service");
+ resultCallback.sendResult(null);
+ return;
+ }
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.performDirectActionLocked(token, actionId, arguments, taskId,
+ assistToken, cancellationCallback, resultCallback);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
+ @Override
public void setKeepAwake(IBinder token, boolean keepAwake) {
synchronized (this) {
if (mImpl == null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index ea52377..0d80e60 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -22,11 +22,14 @@
import static android.app.ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
+import android.app.IApplicationThread;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -37,6 +40,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -44,6 +48,7 @@
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
+import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.view.IWindowManager;
@@ -53,6 +58,7 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.ActivityTokens;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -256,6 +262,55 @@
}
}
+ public void requestDirectActionsLocked(@NonNull IBinder token, int taskId,
+ IBinder assistToken, @NonNull RemoteCallback callback) {
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "requestDirectActionsLocked does not match active session");
+ callback.sendResult(null);
+ return;
+ }
+ final ActivityTokens tokens = LocalServices.getService(
+ ActivityTaskManagerInternal.class).getTopActivityForTask(taskId);
+ if (tokens == null || tokens.getAssistToken() != assistToken) {
+ Slog.w(TAG, "Unknown activity to query for direct actions");
+ callback.sendResult(null);
+ } else {
+ try {
+ tokens.getApplicationThread().requestDirectActions(tokens.getActivityToken(),
+ mActiveSession.mInteractor, callback);
+ } catch (RemoteException e) {
+ Slog.w("Unexpected remote error", e);
+ callback.sendResult(null);
+ }
+ }
+ }
+
+ void performDirectActionLocked(@NonNull IBinder token, @NonNull String actionId,
+ @Nullable Bundle arguments, int taskId, IBinder assistToken,
+ @Nullable RemoteCallback cancellationCallback,
+ @NonNull RemoteCallback resultCallback) {
+ if (mActiveSession == null || token != mActiveSession.mToken) {
+ Slog.w(TAG, "performDirectActionLocked does not match active session");
+ resultCallback.sendResult(null);
+ return;
+ }
+ final ActivityTokens tokens = LocalServices.getService(
+ ActivityTaskManagerInternal.class).getTopActivityForTask(taskId);
+ if (tokens == null || tokens.getAssistToken() != assistToken) {
+ Slog.w(TAG, "Unknown activity to perform a direct action");
+ resultCallback.sendResult(null);
+ } else {
+ try {
+ tokens.getApplicationThread().performDirectAction(tokens.getActivityToken(),
+ actionId, arguments, cancellationCallback,
+ resultCallback);
+ } catch (RemoteException e) {
+ Slog.w("Unexpected remote error", e);
+ resultCallback.sendResult(null);
+ }
+ }
+ }
+
public void setKeepAwakeLocked(IBinder token, boolean keepAwake) {
try {
if (mActiveSession == null || token != mActiveSession.mToken) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 24690f5..000a347 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -23,9 +23,11 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_ACTIVITY_ID;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_TASK_ID;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -251,11 +253,13 @@
if (data == null) {
try {
- mSession.handleAssist(null, null, null, 0, 0);
+ mSession.handleAssist(-1, null, null, null, null, -1, 0);
} catch (RemoteException e) {
// Ignore
}
} else {
+ final int taskId = data.getInt(ASSIST_TASK_ID);
+ final IBinder activityId = data.getBinder(ASSIST_ACTIVITY_ID);
final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
final AssistStructure structure = data.getParcelable(ASSIST_KEY_STRUCTURE);
final AssistContent content = data.getParcelable(ASSIST_KEY_CONTENT);
@@ -279,8 +283,8 @@
}
}
try {
- mSession.handleAssist(assistData, structure, content, activityIndex,
- activityCount);
+ mSession.handleAssist(taskId, activityId, assistData, structure,
+ content, activityIndex, activityCount);
} catch (RemoteException e) {
// Ignore
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 26745a7..2d8a280 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1202,7 +1202,7 @@
* Override the SPN Display Condition 2 integer bits (lsb). B2, B1 is the last two bits of the
* spn display condition coding.
*
- * The default value -1 mean this field is not config.
+ * The default value -1 mean this field is not set.
*
* B1 = 0: display of registered PLMN name not required when registered PLMN is either HPLMN
* or a PLMN in the service provider PLMN list (see EF_SPDI).
@@ -1241,7 +1241,7 @@
/**
* Override the PNN - a string array of comma-separated alpha long and short names:
- * "alpha_long1, alpha_short1".
+ * "alpha_long1,alpha_short1".
*
* Reference: 3GPP TS 31.102 v15.2.0 Section 4.2.58 EF_PNN.
* @hide
@@ -1259,6 +1259,8 @@
/**
* Allow ERI rules to select a carrier name display string when using 3gpp2 access technologies.
+ * If this bit is not set, the carrier name display string will be selected from the carrier
+ * display name resolver which doesn't apply the ERI rules.
*
* @hide
*/
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index fa7bf61..13e737e 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.service.watchdog.ExplicitHealthCheckService.PackageConfig;
+
import static com.android.server.PackageWatchdog.MonitoredPackage;
import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
@@ -28,7 +30,6 @@
import android.content.pm.VersionedPackage;
import android.os.Handler;
import android.os.test.TestLooper;
-import android.service.watchdog.PackageInfo;
import android.util.AtomicFile;
import androidx.test.InstrumentationRegistry;
@@ -741,7 +742,7 @@
private List<String> mSupportedPackages = new ArrayList<>();
private List<String> mRequestedPackages = new ArrayList<>();
private Consumer<String> mPassedConsumer;
- private Consumer<List<PackageInfo>> mSupportedConsumer;
+ private Consumer<List<PackageConfig>> mSupportedConsumer;
private Runnable mNotifySyncRunnable;
@Override
@@ -754,7 +755,7 @@
@Override
public void setCallbacks(Consumer<String> passedConsumer,
- Consumer<List<PackageInfo>> supportedConsumer, Runnable notifySyncRunnable) {
+ Consumer<List<PackageConfig>> supportedConsumer, Runnable notifySyncRunnable) {
mPassedConsumer = passedConsumer;
mSupportedConsumer = supportedConsumer;
mNotifySyncRunnable = notifySyncRunnable;
@@ -766,11 +767,11 @@
if (mIsEnabled) {
packages.retainAll(mSupportedPackages);
mRequestedPackages.addAll(packages);
- List<PackageInfo> packageInfos = new ArrayList<>();
+ List<PackageConfig> packageConfigs = new ArrayList<>();
for (String packageName: packages) {
- packageInfos.add(new PackageInfo(packageName, SHORT_DURATION));
+ packageConfigs.add(new PackageConfig(packageName, SHORT_DURATION));
}
- mSupportedConsumer.accept(packageInfos);
+ mSupportedConsumer.accept(packageConfigs);
} else {
mSupportedConsumer.accept(Collections.emptyList());
}
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 1773b5a..836e199 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -267,7 +267,8 @@
// A DECL will override a USE without error. Two DECLs must match in their format for there to be
// no error.
ResourceTable::CollisionResult ResourceTable::ResolveValueCollision(Value* existing,
- Value* incoming) {
+ Value* incoming,
+ bool overlay) {
Attribute* existing_attr = ValueCast<Attribute>(existing);
Attribute* incoming_attr = ValueCast<Attribute>(incoming);
if (!incoming_attr) {
@@ -281,7 +282,7 @@
}
// The existing and incoming values are strong, this is an error
// if the values are not both attributes.
- return CollisionResult::kConflict;
+ return overlay ? CollisionResult::kTakeNew : CollisionResult::kConflict;
}
if (!existing_attr) {
@@ -292,7 +293,7 @@
}
// The existing value is not an attribute and it is strong,
// so the incoming attribute value is an error.
- return CollisionResult::kConflict;
+ return overlay ? CollisionResult::kTakeNew : CollisionResult::kConflict;
}
CHECK(incoming_attr != nullptr && existing_attr != nullptr);
@@ -323,8 +324,9 @@
return CollisionResult::kConflict;
}
-ResourceTable::CollisionResult ResourceTable::IgnoreCollision(Value* /** existing **/,
- Value* /** incoming **/) {
+ResourceTable::CollisionResult ResourceTable::IgnoreCollision(Value* /* existing */,
+ Value* /* incoming */,
+ bool /* overlay */) {
return CollisionResult::kKeepBoth;
}
@@ -440,7 +442,7 @@
// Resource does not exist, add it now.
config_value->value = std::move(value);
} else {
- switch (conflict_resolver(config_value->value.get(), value.get())) {
+ switch (conflict_resolver(config_value->value.get(), value.get(), false /* overlay */)) {
case CollisionResult::kKeepBoth:
// Insert the value ignoring for duplicate configurations
entry->values.push_back(util::make_unique<ResourceConfigValue>(config, product));
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 30ba1ae..e879380 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -228,13 +228,13 @@
enum class CollisionResult { kKeepBoth, kKeepOriginal, kConflict, kTakeNew };
- using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*)>;
+ using CollisionResolverFunc = std::function<CollisionResult(Value*, Value*, bool)>;
// When a collision of resources occurs, this method decides which value to keep.
- static CollisionResult ResolveValueCollision(Value* existing, Value* incoming);
+ static CollisionResult ResolveValueCollision(Value* existing, Value* incoming, bool overlay);
// When a collision of resources occurs, this method keeps both values
- static CollisionResult IgnoreCollision(Value* existing, Value* incoming);
+ static CollisionResult IgnoreCollision(Value* existing, Value* incoming, bool overlay);
bool AddResource(const ResourceNameRef& name, const android::ConfigDescription& config,
const android::StringPiece& product, std::unique_ptr<Value> value,
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 34b46c5..6960127 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -574,6 +574,10 @@
}
bool Attribute::IsCompatibleWith(const Attribute& attr) const {
+ if (Equals(&attr)) {
+ return true;
+ }
+
// If the high bits are set on any of these attribute type masks, then they are incompatible.
// We don't check that flags and enums are identical.
if ((type_mask & ~android::ResTable_map::TYPE_ANY) != 0 ||
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index c0802e6..3f65e86 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -188,7 +188,7 @@
}
}
// Delegate to the default handler.
- return ResourceTable::ResolveValueCollision(existing, incoming);
+ return ResourceTable::ResolveValueCollision(existing, incoming, true /* overlay */);
}
static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
@@ -206,15 +206,11 @@
if (overlay) {
collision_result = ResolveMergeCollision(dst_value, src_value, pool);
} else {
- collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value);
+ collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value,
+ false /* overlay */);
}
if (collision_result == CollisionResult::kConflict) {
- if (overlay) {
- return CollisionResult::kTakeNew;
- }
-
- // Error!
context->GetDiagnostics()->Error(DiagMessage(src_value->GetSource())
<< "resource '" << res_name << "' has a conflicting value for "
<< "configuration (" << src_config_value->config << ")");
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 9dd31e6..be9c84b 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -352,6 +352,110 @@
ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
}
+TEST_F(TableMergerTest, OverrideAttributeSameFormatsWithOverlay) {
+ std::unique_ptr<ResourceTable> base =
+ test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_STRING)
+ .SetWeak(false)
+ .Build())
+ .Build();
+
+ std::unique_ptr<ResourceTable> overlay =
+ test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_STRING)
+ .SetWeak(false)
+ .Build())
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = false;
+ TableMerger merger(context_.get(), &final_table, options);
+
+ ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
+ ASSERT_TRUE(merger.Merge({}, overlay.get(), true /*overlay*/));
+}
+
+TEST_F(TableMergerTest, FailToOverrideConflictingAttributeFormatsWithOverlay) {
+ std::unique_ptr<ResourceTable> base =
+ test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_ANY)
+ .SetWeak(false)
+ .Build())
+ .Build();
+
+ std::unique_ptr<ResourceTable> overlay =
+ test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_STRING)
+ .SetWeak(false)
+ .Build())
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = false;
+ TableMerger merger(context_.get(), &final_table, options);
+
+ ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/));
+}
+
+TEST_F(TableMergerTest, FailToOverrideConflictingFlagsAndEnumsWithOverlay) {
+ std::unique_ptr<ResourceTable> base =
+ test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
+ .Build())
+ .Build();
+
+ std::unique_ptr<ResourceTable> overlay =
+ test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
+ .SetWeak(false)
+ .Build())
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = false;
+ TableMerger merger(context_.get(), &final_table, options);
+
+ ASSERT_TRUE(merger.Merge({}, base.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, overlay.get(), true /*overlay*/));
+
+ base = test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_ENUM)
+ .Build())
+ .Build();
+
+ overlay = test::ResourceTableBuilder()
+ .SetPackageId("", 0x7f)
+ .AddValue("attr/foo", test::AttributeBuilder()
+ .SetTypeMask(android::ResTable_map::TYPE_ENUM)
+ .SetWeak(false)
+ .Build())
+ .Build();
+
+ ResourceTable final_table2;
+ TableMerger merger2(context_.get(), &final_table2, options);
+
+ ASSERT_TRUE(merger2.Merge({}, base.get(), false /*overlay*/));
+ ASSERT_FALSE(merger2.Merge({}, overlay.get(), true /*overlay*/));
+}
+
TEST_F(TableMergerTest, FailToMergeNewResourceWithoutAutoAddOverlay) {
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder().SetPackageId("", 0x7f).Build();