diff options
248 files changed, 4217 insertions, 1746 deletions
diff --git a/Android.mk b/Android.mk index 4ca3e229d87b..2d5285438392 100644 --- a/Android.mk +++ b/Android.mk @@ -63,6 +63,7 @@ LOCAL_SRC_FILES += \ core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \ core/java/android/accounts/IAccountManager.aidl \ core/java/android/accounts/IAccountManagerResponse.aidl \ + core/java/android/accounts/IAccountAccessTracker.aidl \ core/java/android/accounts/IAccountAuthenticator.aidl \ core/java/android/accounts/IAccountAuthenticatorResponse.aidl \ core/java/android/app/IActivityContainer.aidl \ diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp index 4983b9ac4236..c546072e733a 100644 --- a/cmds/bootanimation/audioplay.cpp +++ b/cmds/bootanimation/audioplay.cpp @@ -141,13 +141,27 @@ bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) { // configure audio source SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1}; + // Determine channelMask from num_channels + SLuint32 channelMask; + switch (chunkFormat->num_channels) { + case 1: + channelMask = SL_SPEAKER_FRONT_CENTER; + break; + case 2: + channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; + break; + default: + // Default of 0 will derive mask from num_channels and log a warning. + channelMask = 0; + } + SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM, chunkFormat->num_channels, chunkFormat->sample_rate * 1000, // convert to milliHz chunkFormat->bits_per_sample, 16, - SL_SPEAKER_FRONT_CENTER, + channelMask, SL_BYTEORDER_LITTLEENDIAN }; SLDataSource audioSrc = {&loc_bufq, &format_pcm}; diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java index f7f7c887aeb0..383cd01ddcd6 100644 --- a/cmds/wm/src/com/android/commands/wm/Wm.java +++ b/cmds/wm/src/com/android/commands/wm/Wm.java @@ -23,6 +23,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.AndroidException; import android.util.DisplayMetrics; import android.view.Display; @@ -201,9 +202,11 @@ public class Wm extends BaseCommand { try { if (density > 0) { // TODO(multidisplay): For now Configuration only applies to main screen. - mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density); + mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density, + UserHandle.USER_CURRENT); } else { - mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY); + mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, + UserHandle.USER_CURRENT); } } catch (RemoteException e) { } diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index c4eaccc1b406..163e7d2661b9 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -53,7 +53,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.List; /** - * Accessibility services are intended to assist users with disabilities in using + * Accessibility services should only be used to assist users with disabilities in using * Android devices and apps. They run in the background and receive callbacks by the system * when {@link AccessibilityEvent}s are fired. Such events denote some state transition * in the user interface, for example, the focus has changed, a button has been clicked, diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java index 7b83a3076db3..6c16e322e978 100644 --- a/core/java/android/accounts/Account.java +++ b/core/java/android/accounts/Account.java @@ -16,9 +16,17 @@ package android.accounts; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcelable; import android.os.Parcel; +import android.os.RemoteException; import android.text.TextUtils; +import android.util.ArraySet; +import android.util.Log; +import com.android.internal.annotations.GuardedBy; + +import java.util.Set; /** * Value type that represents an Account in the {@link AccountManager}. This object is @@ -26,8 +34,14 @@ import android.text.TextUtils; * suitable for use as the key of a {@link java.util.Map} */ public class Account implements Parcelable { + private static final String TAG = "Account"; + + @GuardedBy("sAccessedAccounts") + private static final Set<Account> sAccessedAccounts = new ArraySet<>(); + public final String name; public final String type; + private final @Nullable IAccountAccessTracker mAccessTracker; public boolean equals(Object o) { if (o == this) return true; @@ -44,6 +58,20 @@ public class Account implements Parcelable { } public Account(String name, String type) { + this(name, type, null); + } + + /** + * @hide + */ + public Account(@NonNull Account other, @Nullable IAccountAccessTracker accessTracker) { + this(other.name, other.type, accessTracker); + } + + /** + * @hide + */ + public Account(String name, String type, IAccountAccessTracker accessTracker) { if (TextUtils.isEmpty(name)) { throw new IllegalArgumentException("the name must not be empty: " + name); } @@ -52,11 +80,29 @@ public class Account implements Parcelable { } this.name = name; this.type = type; + this.mAccessTracker = accessTracker; } public Account(Parcel in) { this.name = in.readString(); this.type = in.readString(); + this.mAccessTracker = IAccountAccessTracker.Stub.asInterface(in.readStrongBinder()); + if (mAccessTracker != null) { + synchronized (sAccessedAccounts) { + if (sAccessedAccounts.add(this)) { + try { + mAccessTracker.onAccountAccessed(); + } catch (RemoteException e) { + Log.e(TAG, "Error noting account access", e); + } + } + } + } + } + + /** @hide */ + public IAccountAccessTracker getAccessTracker() { + return mAccessTracker; } public int describeContents() { @@ -66,6 +112,7 @@ public class Account implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeString(type); + dest.writeStrongInterface(mAccessTracker); } public static final Creator<Account> CREATOR = new Creator<Account>() { diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index ed08a70bfd8d..632e4b943626 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -18,7 +18,6 @@ package android.accounts; import static android.Manifest.permission.GET_ACCOUNTS; -import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.Size; @@ -180,6 +179,14 @@ public class AccountManager { public static final String KEY_ACCOUNT_TYPE = "accountType"; /** + * Bundle key used for the {@link IAccountAccessTracker} account access tracker + * used for noting the account was accessed when unmarshalled from a parcel. + * + * @hide + */ + public static final String KEY_ACCOUNT_ACCESS_TRACKER = "accountAccessTracker"; + + /** * Bundle key used for the auth token value in results * from {@link #getAuthToken} and friends. */ @@ -268,13 +275,13 @@ public class AccountManager { public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator"; /** - * Token for the special case where a UID has access only to an account - * but no authenticator specific auth tokens. + * Token type for the special case where a UID has access only to an account + * but no authenticator specific auth token types. * * @hide */ - public static final String ACCOUNT_ACCESS_TOKEN = - "com.android.abbfd278-af8b-415d-af8b-7571d5dab133"; + public static final String ACCOUNT_ACCESS_TOKEN_TYPE = + "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE"; private final Context mContext; private final IAccountManager mService; @@ -814,7 +821,9 @@ public class AccountManager { public Account bundleToResult(Bundle bundle) throws AuthenticatorException { String name = bundle.getString(KEY_ACCOUNT_NAME); String type = bundle.getString(KEY_ACCOUNT_TYPE); - return new Account(name, type); + IAccountAccessTracker tracker = IAccountAccessTracker.Stub.asInterface( + bundle.getBinder(KEY_ACCOUNT_ACCESS_TRACKER)); + return new Account(name, type, tracker); } }.start(); } @@ -2270,6 +2279,7 @@ public class AccountManager { result.putString(KEY_ACCOUNT_NAME, null); result.putString(KEY_ACCOUNT_TYPE, null); result.putString(KEY_AUTHTOKEN, null); + result.putBinder(KEY_ACCOUNT_ACCESS_TRACKER, null); try { mResponse.onResult(result); } catch (RemoteException e) { @@ -2295,9 +2305,13 @@ public class AccountManager { public void onResult(Bundle value) throws RemoteException { Account account = new Account( value.getString(KEY_ACCOUNT_NAME), - value.getString(KEY_ACCOUNT_TYPE)); - mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions, - mActivity, mMyCallback, mHandler); + value.getString(KEY_ACCOUNT_TYPE), + IAccountAccessTracker.Stub.asInterface( + value.getBinder( + KEY_ACCOUNT_ACCESS_TRACKER))); + mFuture = getAuthToken(account, mAuthTokenType, + mLoginOptions, mActivity, mMyCallback, + mHandler); } @Override @@ -2344,7 +2358,9 @@ public class AccountManager { setException(new AuthenticatorException("account not in result")); return; } - final Account account = new Account(accountName, accountType); + final IAccountAccessTracker tracker = IAccountAccessTracker.Stub.asInterface( + result.getBinder(KEY_ACCOUNT_ACCESS_TRACKER)); + final Account account = new Account(accountName, accountType, tracker); mNumAccounts = 1; getAuthToken(account, mAuthTokenType, null /* options */, mActivity, mMyCallback, mHandler); diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java index d777643950e6..68c17c32fdc3 100644 --- a/core/java/android/accounts/AccountManagerInternal.java +++ b/core/java/android/accounts/AccountManagerInternal.java @@ -28,6 +28,21 @@ import android.os.RemoteCallback; public abstract class AccountManagerInternal { /** + * Listener for explicit UID account access grant changes. + */ + public interface OnAppPermissionChangeListener { + + /** + * Called when the explicit grant state for a given UID to + * access an account changes. + * + * @param account The account + * @param uid The UID for which the grant changed + */ + public void onAppPermissionChanged(Account account, int uid); + } + + /** * Requests that a given package is given access to an account. * The provided callback will be invoked with a {@link android.os.Bundle} * containing the result which will be a boolean value mapped to the @@ -38,7 +53,38 @@ public abstract class AccountManagerInternal { * @param userId Concrete user id for which to request. * @param callback A callback for receiving the result. */ - public abstract void requestAccountAccess(@NonNull Account account, + public abstract void requestAccountAccess(@NonNull Account account, @NonNull String packageName, @IntRange(from = 0) int userId, @NonNull RemoteCallback callback); + + /** + * Check whether the given UID has access to the account. + * + * @param account The account + * @param uid The UID + * @return Whether the UID can access the account + */ + public abstract boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid); + + /** + * Adds a listener for explicit UID account access grant changes. + * + * @param listener The listener + */ + public abstract void addOnAppPermissionChangeListener( + @NonNull OnAppPermissionChangeListener listener); + + /** + * Backups the account access permissions. + * @param userId The user for which to backup. + * @return The backup data. + */ + public abstract byte[] backupAccountAccessPermissions(int userId); + + /** + * Restores the account access permissions. + * @param data The restore data. + * @param userId The user for which to restore. + */ + public abstract void restoreAccountAccessPermissions(byte[] data, int userId); } diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java index 8d0ce58d3358..38eab2905022 100644 --- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java +++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java @@ -108,7 +108,7 @@ public class GrantCredentialsPermissionActivity extends Activity implements View } }; - if (!AccountManager.ACCOUNT_ACCESS_TOKEN.equals(mAuthTokenType)) { + if (!AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(mAuthTokenType)) { AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null); } diff --git a/core/java/android/accounts/IAccountAccessTracker.aidl b/core/java/android/accounts/IAccountAccessTracker.aidl new file mode 100644 index 000000000000..e12b3d1e21c7 --- /dev/null +++ b/core/java/android/accounts/IAccountAccessTracker.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 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.accounts; + +/** + * Interface to track which apps accessed an account + * + * @hide + */ +oneway interface IAccountAccessTracker { + void onAccountAccessed(); +} diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index aacd5da58640..50479c8e951b 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -3017,6 +3017,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + case CAN_BYPASS_WORK_CHALLENGE: { + data.enforceInterface(IActivityManager.descriptor); + final PendingIntent intent = PendingIntent.CREATOR.createFromParcel(data); + final boolean result = canBypassWorkChallenge(intent); + reply.writeNoException(); + reply.writeInt(result ? 1 : 0); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -7091,6 +7099,20 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return; } + @Override + public boolean canBypassWorkChallenge(PendingIntent intent) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + intent.writeToParcel(data, 0); + mRemote.transact(CAN_BYPASS_WORK_CHALLENGE, data, reply, 0); + reply.readException(); + final int result = reply.readInt(); + data.recycle(); + reply.recycle(); + return result != 0; + } private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2c5f881321c0..18677dda3b88 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -433,8 +433,10 @@ public final class ActivityThread { static final class NewIntentData { List<ReferrerIntent> intents; IBinder token; + boolean andPause; public String toString() { - return "NewIntentData{intents=" + intents + " token=" + token + "}"; + return "NewIntentData{intents=" + intents + " token=" + token + + " andPause=" + andPause +"}"; } } @@ -751,10 +753,12 @@ public final class ActivityThread { configChanges, notResumed, config, overrideConfig, true, preserveWindow); } - public final void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) { + public final void scheduleNewIntent( + List<ReferrerIntent> intents, IBinder token, boolean andPause) { NewIntentData data = new NewIntentData(); data.intents = intents; data.token = token; + data.andPause = andPause; sendMessage(H.NEW_INTENT, data); } @@ -2787,24 +2791,34 @@ public final class ActivityThread { } } - public final void performNewIntents(IBinder token, List<ReferrerIntent> intents) { - ActivityClientRecord r = mActivities.get(token); - if (r != null) { - final boolean resumed = !r.paused; - if (resumed) { - r.activity.mTemporaryPause = true; - mInstrumentation.callActivityOnPause(r.activity); - } - deliverNewIntents(r, intents); - if (resumed) { - r.activity.performResume(); - r.activity.mTemporaryPause = false; - } + void performNewIntents(IBinder token, List<ReferrerIntent> intents, boolean andPause) { + final ActivityClientRecord r = mActivities.get(token); + if (r == null) { + return; + } + + final boolean resumed = !r.paused; + if (resumed) { + r.activity.mTemporaryPause = true; + mInstrumentation.callActivityOnPause(r.activity); + } + deliverNewIntents(r, intents); + if (resumed) { + r.activity.performResume(); + r.activity.mTemporaryPause = false; + } + + if (r.paused && andPause) { + // In this case the activity was in the paused state when we delivered the intent, + // to guarantee onResume gets called after onNewIntent we temporarily resume the + // activity and pause again as the caller wanted. + performResumeActivity(token, false, "performNewIntents"); + performPauseActivityIfNeeded(r, "performNewIntents"); } } private void handleNewIntent(NewIntentData data) { - performNewIntents(data.token, data.intents); + performNewIntents(data.token, data.intents, data.andPause); } public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index d6da3f44f4a0..05d9d7e412f0 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -190,7 +190,8 @@ public abstract class ApplicationThreadNative extends Binder data.enforceInterface(IApplicationThread.descriptor); List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR); IBinder b = data.readStrongBinder(); - scheduleNewIntent(pi, b); + final boolean andPause = data.readInt() == 1; + scheduleNewIntent(pi, b, andPause); return true; } @@ -909,12 +910,13 @@ class ApplicationThreadProxy implements IApplicationThread { data.recycle(); } - public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token) + public void scheduleNewIntent(List<ReferrerIntent> intents, IBinder token, boolean andPause) throws RemoteException { Parcel data = Parcel.obtain(); data.writeInterfaceToken(IApplicationThread.descriptor); data.writeTypedList(intents); data.writeStrongBinder(token); + data.writeInt(andPause ? 1 : 0); mRemote.transact(SCHEDULE_NEW_INTENT_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index e411e03a8a94..5a4470b2ecdb 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -671,6 +671,18 @@ public interface IActivityManager extends IInterface { */ public void setHasTopUi(boolean hasTopUi) throws RemoteException; + /** + * Returns if the target of the PendingIntent can be fired directly, without triggering + * a work profile challenge. This can happen if the PendingIntent is to start direct-boot + * aware activities, and the target user is in RUNNING_LOCKED state, i.e. we should allow + * direct-boot aware activity to bypass work challenge when the user hasn't unlocked yet. + * @param intent the {@link PendingIntent} to be tested. + * @return {@code true} if the intent should not trigger a work challenge, {@code false} + * otherwise. + * @throws RemoteException + */ + public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -1062,4 +1074,5 @@ public interface IActivityManager extends IInterface { int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377; int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378; int SET_HAS_TOP_UI = IBinder.FIRST_CALL_TRANSACTION + 379; + int CAN_BYPASS_WORK_CHALLENGE = IBinder.FIRST_CALL_TRANSACTION + 380; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 559f69fc2aec..3fa88ae674a4 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -67,7 +67,8 @@ public interface IApplicationThread extends IInterface { List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed, Configuration config, Configuration overrideConfig, boolean preserveWindow) throws RemoteException; - void scheduleNewIntent(List<ReferrerIntent> intent, IBinder token) throws RemoteException; + void scheduleNewIntent( + List<ReferrerIntent> intent, IBinder token, boolean andPause) throws RemoteException; void scheduleDestroyActivity(IBinder token, boolean finished, int configChanges) throws RemoteException; void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 2a1e3c250a00..3b273bc1c4b6 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -314,7 +314,7 @@ public class LocalActivityManager { ArrayList<ReferrerIntent> intents = new ArrayList<>(1); intents.add(new ReferrerIntent(intent, mParent.getPackageName())); if (localLOGV) Log.v(TAG, r.id + ": new intent"); - mActivityThread.performNewIntents(r, intents); + mActivityThread.performNewIntents(r, intents, false /* andPause */); r.intent = intent; moveToState(r, mCurState); if (mSingleMode) { diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index b3320d6f6976..daa1b93889cc 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -1877,6 +1877,7 @@ public abstract class ContentResolver { if (extras != null) { String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT); if (!TextUtils.isEmpty(accountName)) { + // TODO: No references to Google in AOSP account = new Account(accountName, "com.google"); } extras.remove(SYNC_EXTRAS_ACCOUNT); diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index 22ab43bbb429..d07b54573547 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -265,6 +265,7 @@ public class IntentFilter implements Parcelable { public static final String SCHEME_HTTPS = "https"; private int mPriority; + private int mOrder; private final ArrayList<String> mActions; private ArrayList<String> mCategories = null; private ArrayList<String> mDataSchemes = null; @@ -425,6 +426,7 @@ public class IntentFilter implements Parcelable { */ public IntentFilter(IntentFilter o) { mPriority = o.mPriority; + mOrder = o.mOrder; mActions = new ArrayList<String>(o.mActions); if (o.mCategories != null) { mCategories = new ArrayList<String>(o.mCategories); @@ -477,6 +479,16 @@ public class IntentFilter implements Parcelable { return mPriority; } + /** @hide */ + public final void setOrder(int order) { + mOrder = order; + } + + /** @hide */ + public final int getOrder() { + return mOrder; + } + /** * Set whether this filter will needs to be automatically verified against its data URIs or not. * The default is false. diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index d208fe7c10ca..f5bcf64417a6 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -160,4 +160,12 @@ public abstract class PackageManagerInternal { * Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}. */ public abstract boolean isPackageDataProtected(int userId, String packageName); + + /** + * Gets whether the package was ever launched. + * @param packageName The package name. + * @param userId The user for which to check. + * @return Whether was launched. + */ + public abstract boolean wasPackageEverLaunched(String packageName, int userId); } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 6243f467016a..56eba4f0e3ef 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -182,8 +182,15 @@ public final class NetworkCapabilities implements Parcelable { */ public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; + /** + * Indicates that this network is available for use by apps, and not a network that is being + * kept up in the background to facilitate fast network switching. + * @hide + */ + public static final int NET_CAPABILITY_FOREGROUND = 18; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_CAPTIVE_PORTAL; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -194,7 +201,8 @@ public final class NetworkCapabilities implements Parcelable { // http://b/18206275 (1 << NET_CAPABILITY_TRUSTED) | (1 << NET_CAPABILITY_VALIDATED) | - (1 << NET_CAPABILITY_CAPTIVE_PORTAL); + (1 << NET_CAPABILITY_CAPTIVE_PORTAL) | + (1 << NET_CAPABILITY_FOREGROUND); /** * Network specifier for factories which want to match any network specifier @@ -217,8 +225,7 @@ public final class NetworkCapabilities implements Parcelable { * get immediately torn down because they do not have the requested capability. */ private static final long NON_REQUESTABLE_CAPABILITIES = - (1 << NET_CAPABILITY_VALIDATED) | - (1 << NET_CAPABILITY_CAPTIVE_PORTAL); + MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_TRUSTED); /** * Capabilities that are set by default when the object is constructed. @@ -325,6 +332,7 @@ public final class NetworkCapabilities implements Parcelable { public String describeFirstNonRequestableCapability() { if (hasCapability(NET_CAPABILITY_VALIDATED)) return "NET_CAPABILITY_VALIDATED"; if (hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return "NET_CAPABILITY_CAPTIVE_PORTAL"; + if (hasCapability(NET_CAPABILITY_FOREGROUND)) return "NET_CAPABILITY_FOREGROUND"; // This cannot happen unless the preceding checks are incomplete. if ((mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES) != 0) { return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities); @@ -352,6 +360,11 @@ public final class NetworkCapabilities implements Parcelable { (that.mNetworkCapabilities & ~MUTABLE_CAPABILITIES)); } + private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) { + return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) == + (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)); + } + /** * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are * typically provided by restricted networks. @@ -749,6 +762,19 @@ public final class NetworkCapabilities implements Parcelable { equalsSpecifier(nc)); } + /** + * Checks that our requestable capabilities are the same as those of the given + * {@code NetworkCapabilities}. + * + * @hide + */ + public boolean equalRequestableCapabilities(NetworkCapabilities nc) { + if (nc == null) return false; + return (equalsNetCapabilitiesRequestable(nc) && + equalsTransportTypes(nc) && + equalsSpecifier(nc)); + } + @Override public boolean equals(Object obj) { if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; @@ -833,6 +859,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_NOT_VPN: capabilities += "NOT_VPN"; break; case NET_CAPABILITY_VALIDATED: capabilities += "VALIDATED"; break; case NET_CAPABILITY_CAPTIVE_PORTAL: capabilities += "CAPTIVE_PORTAL"; break; + case NET_CAPABILITY_FOREGROUND: capabilities += "FOREGROUND"; break; } if (++i < types.length) capabilities += "&"; } diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 4501f7b089b9..ae724709c6c6 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -49,7 +49,7 @@ public class NetworkRequest implements Parcelable { public final int legacyType; /** - * A NetworkRequest as used by the system can be one of three types: + * A NetworkRequest as used by the system can be one of the following types: * * - LISTEN, for which the framework will issue callbacks about any * and all networks that match the specified NetworkCapabilities, @@ -64,7 +64,20 @@ public class NetworkRequest implements Parcelable { * current network (if any) that matches the capabilities of the * default Internet request (mDefaultRequest), but which cannot cause * the framework to either create or retain the existence of any - * specific network. + * specific network. Note that from the point of view of the request + * matching code, TRACK_DEFAULT is identical to REQUEST: its special + * behaviour is not due to different semantics, but to the fact that + * the system will only ever create a TRACK_DEFAULT with capabilities + * that are identical to the default request's capabilities, thus + * causing it to share fate in every way with the default request. + * + * - BACKGROUND_REQUEST, like REQUEST but does not cause any networks + * to retain the NET_CAPABILITY_FOREGROUND capability. A network with + * no foreground requests is in the background. A network that has + * one or more background requests and loses its last foreground + * request to a higher-scoring network will not go into the + * background immediately, but will linger and go into the background + * after the linger timeout. * * - The value NONE is used only by applications. When an application * creates a NetworkRequest, it does not have a type; the type is set @@ -77,7 +90,8 @@ public class NetworkRequest implements Parcelable { NONE, LISTEN, TRACK_DEFAULT, - REQUEST + REQUEST, + BACKGROUND_REQUEST, }; /** @@ -140,7 +154,7 @@ public class NetworkRequest implements Parcelable { * Add the given capability requirement to this builder. These represent * the requested network's required capabilities. Note that when searching * for a network to satisfy a request, all capabilities requested must be - * satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*} + * satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITY_*} * definitions. * * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add. @@ -284,7 +298,7 @@ public class NetworkRequest implements Parcelable { }; /** - * Returns true iff. the contained NetworkRequest is of type LISTEN. + * Returns true iff. this NetworkRequest is of type LISTEN. * * @hide */ @@ -298,8 +312,9 @@ public class NetworkRequest implements Parcelable { * - should be associated with at most one satisfying network * at a time; * - * - should cause a network to be kept up if it is the best network - * which can satisfy the NetworkRequest. + * - should cause a network to be kept up, but not necessarily in + * the foreground, if it is the best network which can satisfy the + * NetworkRequest. * * For full detail of how isRequest() is used for pairing Networks with * NetworkRequests read rematchNetworkAndRequests(). @@ -307,9 +322,36 @@ public class NetworkRequest implements Parcelable { * @hide */ public boolean isRequest() { + return isForegroundRequest() || isBackgroundRequest(); + } + + /** + * Returns true iff. the contained NetworkRequest is one that: + * + * - should be associated with at most one satisfying network + * at a time; + * + * - should cause a network to be kept up and in the foreground if + * it is the best network which can satisfy the NetworkRequest. + * + * For full detail of how isRequest() is used for pairing Networks with + * NetworkRequests read rematchNetworkAndRequests(). + * + * @hide + */ + public boolean isForegroundRequest() { return type == Type.TRACK_DEFAULT || type == Type.REQUEST; } + /** + * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST. + * + * @hide + */ + public boolean isBackgroundRequest() { + return type == Type.BACKGROUND_REQUEST; + } + public String toString() { return "NetworkRequest [ " + type + " id=" + requestId + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 426e78db34a7..79f11513e798 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6333,21 +6333,6 @@ public final class Settings { public static final String WEB_ACTION_ENABLED = "web_action_enabled"; /** - * The uptime when tasks were last persisted. This is used to adjust the previous task - * active times to be relative to the current boot time. - * @hide - */ - public static final String TASK_PERSISTER_LAST_WRITE_UPTIME = "task_persister_write_uptime"; - - /** - * Used by Overview to keep track of the last visible task's active time to determine what - * should tasks be visible. - * @hide - */ - public static final String OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME = - "overview_last_visible_task_active_uptime"; - - /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java new file mode 100644 index 000000000000..6531aef9a50c --- /dev/null +++ b/core/java/android/util/PackageUtils.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 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.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Helper functions applicable to packages. + * @hide + */ +public final class PackageUtils { + private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); + + private PackageUtils() { + /* hide constructor */ + } + + /** + * Computes the SHA256 digest of the signing cert for a package. + * @param packageManager The package manager. + * @param packageName The package for which to generate the digest. + * @param userId The user for which to generate the digest. + * @return The digest or null if the package does not exist for this user. + */ + public static @Nullable String computePackageCertSha256Digest( + @NonNull PackageManager packageManager, + @NonNull String packageName, int userId) { + final PackageInfo packageInfo; + try { + packageInfo = packageManager.getPackageInfoAsUser(packageName, + PackageManager.GET_SIGNATURES, userId); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + return computeCertSha256Digest(packageInfo.signatures[0]); + } + + /** + * Computes the SHA256 digest of a cert. + * @param signature The signature. + * @return The digest or null if an error occurs. + */ + public static @Nullable String computeCertSha256Digest(@NonNull Signature signature) { + return computeSha256Digest(signature.toByteArray()); + } + + /** + * Computes the SHA256 digest of some data. + * @param data The data. + * @return The digest or null if an error occurs. + */ + public static @Nullable String computeSha256Digest(@NonNull byte[] data) { + MessageDigest messageDigest; + try { + messageDigest = MessageDigest.getInstance("SHA256"); + } catch (NoSuchAlgorithmException e) { + /* can't happen */ + return null; + } + + messageDigest.update(data); + + final byte[] digest = messageDigest.digest(); + final int digestLength = digest.length; + final int charCount = 2 * digestLength; + + final char[] chars = new char[charCount]; + for (int i = 0; i < digestLength; i++) { + final int byteHex = digest[i] & 0xFF; + chars[i * 2] = HEX_ARRAY[byteHex >>> 4]; + chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F]; + } + return new String(chars); + } +} diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java index b0f15b5f2329..a394f351b7f3 100644 --- a/core/java/android/view/DragEvent.java +++ b/core/java/android/view/DragEvent.java @@ -377,6 +377,10 @@ public class DragEvent implements Parcelable { * The object is intended to provide local information about the drag and drop operation. For * example, it can indicate whether the drag and drop operation is a copy or a move. * <p> + * The local state is available only to views in the activity which has started the drag + * operation. In all other activities this method will return null + * </p> + * <p> * This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}. * </p> * @return The local state object sent to the system by startDrag(). diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 81469c86810c..83feb88fa55d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -73,8 +73,8 @@ interface IWindowManager void clearForcedDisplaySize(int displayId); int getInitialDisplayDensity(int displayId); int getBaseDisplayDensity(int displayId); - void setForcedDisplayDensity(int displayId, int density); - void clearForcedDisplayDensity(int displayId); + void setForcedDisplayDensityForUser(int displayId, int density, int userId); + void clearForcedDisplayDensityForUser(int displayId, int userId); void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable void setOverscan(int displayId, int left, int top, int right, int bottom); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 908658feb29c..a0afeba27fc5 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -20655,8 +20655,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the * drag shadow. * @param myLocalState An {@link java.lang.Object} containing local data about the drag and - * drop operation. This Object is put into every DragEvent object sent by the system during the - * current drag. + * drop operation. When dispatching drag events to views in the same activity this object + * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other + * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} + * will return null). * <p> * myLocalState is a lightweight mechanism for the sending information from the dragged View * to the target Views. For example, it can contain flags that differentiate between a diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java index c3ddec787bfa..25580fd2496e 100644 --- a/core/java/android/widget/NumberPicker.java +++ b/core/java/android/widget/NumberPicker.java @@ -16,6 +16,8 @@ package android.widget; +import com.android.internal.R; + import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.Widget; @@ -29,10 +31,12 @@ import android.graphics.Paint.Align; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.text.Editable; import android.text.InputFilter; import android.text.InputType; import android.text.Spanned; import android.text.TextUtils; +import android.text.TextWatcher; import android.text.method.NumberKeyListener; import android.util.AttributeSet; import android.util.SparseArray; @@ -52,9 +56,6 @@ import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import com.android.internal.R; -import libcore.icu.LocaleData; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -62,6 +63,8 @@ import java.util.Collections; import java.util.List; import java.util.Locale; +import libcore.icu.LocaleData; + /** * A widget that enables the user to select a number from a predefined range. * There are two flavors of this widget and which one is presented to the user @@ -1991,7 +1994,7 @@ public class NumberPicker extends LinearLayout { removeCallbacks(mChangeCurrentByOneFromLongPressCommand); } if (mSetSelectionCommand != null) { - removeCallbacks(mSetSelectionCommand); + mSetSelectionCommand.cancel(); } if (mBeginSoftInputOnLongPressCommand != null) { removeCallbacks(mBeginSoftInputOnLongPressCommand); @@ -2033,18 +2036,14 @@ public class NumberPicker extends LinearLayout { } /** - * Posts an {@link SetSelectionCommand} from the given <code>selectionStart - * </code> to <code>selectionEnd</code>. + * Posts a {@link SetSelectionCommand} from the given + * {@code selectionStart} to {@code selectionEnd}. */ private void postSetSelectionCommand(int selectionStart, int selectionEnd) { if (mSetSelectionCommand == null) { - mSetSelectionCommand = new SetSelectionCommand(); - } else { - removeCallbacks(mSetSelectionCommand); + mSetSelectionCommand = new SetSelectionCommand(mInputText); } - mSetSelectionCommand.mSelectionStart = selectionStart; - mSetSelectionCommand.mSelectionEnd = selectionEnd; - post(mSetSelectionCommand); + mSetSelectionCommand.post(selectionStart, selectionEnd); } /** @@ -2090,6 +2089,12 @@ public class NumberPicker extends LinearLayout { @Override public CharSequence filter( CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { + // We don't know what the output will be, so always cancel any + // pending set selection command. + if (mSetSelectionCommand != null) { + mSetSelectionCommand.cancel(); + } + if (mDisplayedValues == null) { CharSequence filtered = super.filter(source, start, end, dest, dstart, dend); if (filtered == null) { @@ -2237,12 +2242,39 @@ public class NumberPicker extends LinearLayout { /** * Command for setting the input text selection. */ - class SetSelectionCommand implements Runnable { - private int mSelectionStart; + private static class SetSelectionCommand implements Runnable { + private final EditText mInputText; + private int mSelectionStart; private int mSelectionEnd; + /** Whether this runnable is currently posted. */ + private boolean mPosted; + + public SetSelectionCommand(EditText inputText) { + mInputText = inputText; + } + + public void post(int selectionStart, int selectionEnd) { + mSelectionStart = selectionStart; + mSelectionEnd = selectionEnd; + + if (!mPosted) { + mInputText.post(this); + mPosted = true; + } + } + + public void cancel() { + if (mPosted) { + mInputText.removeCallbacks(this); + mPosted = false; + } + } + + @Override public void run() { + mPosted = false; mInputText.setSelection(mSelectionStart, mSelectionEnd); } } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index b12c03ca9c15..9b89491ce408 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1758,11 +1758,22 @@ public class PopupWindow { */ public int getMaxAvailableHeight( @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) { - final Rect displayFrame = new Rect(); + Rect displayFrame = null; + final Rect visibleDisplayFrame = new Rect(); + + anchor.getWindowVisibleDisplayFrame(visibleDisplayFrame); if (ignoreBottomDecorations) { + // In the ignore bottom decorations case we want to + // still respect all other decorations so we use the inset visible + // frame on the top right and left and take the bottom + // value from the full frame. + displayFrame = new Rect(); anchor.getWindowDisplayFrame(displayFrame); + displayFrame.top = visibleDisplayFrame.top; + displayFrame.right = visibleDisplayFrame.right; + displayFrame.left = visibleDisplayFrame.left; } else { - anchor.getWindowVisibleDisplayFrame(displayFrame); + displayFrame = visibleDisplayFrame; } final int[] anchorPos = mTmpDrawingLocation; diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 5878cad2f9a3..9139361eda7c 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -816,9 +816,11 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { switch (heightMode) { case MeasureSpec.AT_MOST: - case MeasureSpec.UNSPECIFIED: height = Math.min(getPreferredHeight(), height); break; + case MeasureSpec.UNSPECIFIED: + height = getPreferredHeight(); + break; } heightMode = MeasureSpec.EXACTLY; diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index eca10cb5e7fd..a400d90c64c5 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -460,7 +460,7 @@ public class Toast { // the view isn't yet added, so let's try not to crash. if (mView.getParent() != null) { if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this); - mWM.removeView(mView); + mWM.removeViewImmediate(mView); } mView = null; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 0a4ac0d44db4..1e26c92dd764 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1469,7 +1469,7 @@ public class ResolverActivity extends Activity { boolean found = false; // Only loop to the end of into as it was before we started; no dupes in from. for (int j = 0; j < intoCount; j++) { - final ResolvedComponentInfo rci = into.get(i); + final ResolvedComponentInfo rci = into.get(j); if (isSameResolvedComponent(newInfo, rci)) { found = true; rci.add(intent, newInfo); diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java index a4b5a8e6595c..cb2b0191b883 100644 --- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java +++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java @@ -145,7 +145,11 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable { if (itemType == TYPE_HEADER_SUGGESTED) { textView.setText(R.string.language_picker_section_suggested); } else { - textView.setText(R.string.language_picker_section_all); + if (mCountryMode) { + textView.setText(R.string.region_picker_section_all); + } else { + textView.setText(R.string.language_picker_section_all); + } } textView.setTextLocale(Locale.getDefault()); break; diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java index 7d222c74ac3b..46098c58108f 100644 --- a/core/java/com/android/internal/util/WakeupMessage.java +++ b/core/java/com/android/internal/util/WakeupMessage.java @@ -108,7 +108,7 @@ public class WakeupMessage implements AlarmManager.OnAlarmListener { } if (stillScheduled) { Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj); - mHandler.handleMessage(msg); + mHandler.dispatchMessage(msg); msg.recycle(); } } diff --git a/core/java/com/android/server/backup/AccountManagerBackupHelper.java b/core/java/com/android/server/backup/AccountManagerBackupHelper.java new file mode 100644 index 000000000000..39b18c0f2c16 --- /dev/null +++ b/core/java/com/android/server/backup/AccountManagerBackupHelper.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.backup; + +import android.accounts.AccountManagerInternal; +import android.app.backup.BlobBackupHelper; +import android.os.UserHandle; +import android.util.Slog; +import com.android.server.LocalServices; + +/** + * Helper for handling backup of account manager specific state. + */ +public class AccountManagerBackupHelper extends BlobBackupHelper { + private static final String TAG = "AccountsBackup"; + private static final boolean DEBUG = false; + + // current schema of the backup state blob + private static final int STATE_VERSION = 1; + + // key under which the account access grant state blob is committed to backup + private static final String KEY_ACCOUNT_ACCESS_GRANTS = "account_access_grants"; + + public AccountManagerBackupHelper() { + super(STATE_VERSION, KEY_ACCOUNT_ACCESS_GRANTS); + } + + @Override + protected byte[] getBackupPayload(String key) { + AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class); + if (DEBUG) { + Slog.d(TAG, "Handling backup of " + key); + } + try { + switch (key) { + case KEY_ACCOUNT_ACCESS_GRANTS: { + return am.backupAccountAccessPermissions(UserHandle.USER_SYSTEM); + } + + default: { + Slog.w(TAG, "Unexpected backup key " + key); + } + } + } catch (Exception e) { + Slog.e(TAG, "Unable to store payload " + key); + } + + return new byte[0]; + } + + @Override + protected void applyRestoredPayload(String key, byte[] payload) { + AccountManagerInternal am = LocalServices.getService(AccountManagerInternal.class); + if (DEBUG) { + Slog.d(TAG, "Handling restore of " + key); + } + try { + switch (key) { + case KEY_ACCOUNT_ACCESS_GRANTS: { + am.restoreAccountAccessPermissions(payload, UserHandle.USER_SYSTEM); + } break; + + default: { + Slog.w(TAG, "Unexpected restore key " + key); + } + } + } catch (Exception e) { + Slog.w(TAG, "Unable to restore key " + key); + } + } +} diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java index 9d296fa19400..537565185d9b 100644 --- a/core/java/com/android/server/backup/SystemBackupAgent.java +++ b/core/java/com/android/server/backup/SystemBackupAgent.java @@ -49,6 +49,7 @@ public class SystemBackupAgent extends BackupAgentHelper { private static final String PERMISSION_HELPER = "permissions"; private static final String USAGE_STATS_HELPER = "usage_stats"; private static final String SHORTCUT_MANAGER_HELPER = "shortcut_manager"; + private static final String ACCOUNT_MANAGER_HELPER = "account_manager"; // These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME // are also used in the full-backup file format, so must not change unless steps are @@ -82,6 +83,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper()); + addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper()); super.onBackup(oldState, data, newState); } @@ -111,6 +113,7 @@ public class SystemBackupAgent extends BackupAgentHelper { addHelper(PERMISSION_HELPER, new PermissionBackupHelper()); addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this)); addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper()); + addHelper(ACCOUNT_MANAGER_HELPER, new AccountManagerBackupHelper()); try { super.onRestore(data, appVersionCode, newState); diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index d7550a4d9695..72755ce105c8 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -151,12 +151,12 @@ Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, mPixelRef->unref(); } -Bitmap::Bitmap(void* address, int fd, +Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) : mPixelStorageType(PixelStorageType::Ashmem) { mPixelStorage.ashmem.address = address; mPixelStorage.ashmem.fd = fd; - mPixelStorage.ashmem.size = ashmem_get_size_region(fd); + mPixelStorage.ashmem.size = mappedSize; mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable)); // Note: this will trigger a call to onStrongRefDestroyed(), but // we want the pixel ref to have a ref count of 0 at this point @@ -1027,7 +1027,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { // Map the pixels in place and take ownership of the ashmem region. nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), - ctable, dupFd, const_cast<void*>(blob.data()), !isMutable); + ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable); SkSafeUnref(ctable); if (!nativeBitmap) { close(dupFd); diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h index eadba5c0e634..aaea178e7387 100644 --- a/core/jni/android/graphics/Bitmap.h +++ b/core/jni/android/graphics/Bitmap.h @@ -51,8 +51,8 @@ public: const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); - Bitmap(void* address, int fd, const SkImageInfo& info, size_t rowBytes, - SkColorTable* ctable); + Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, + size_t rowBytes, SkColorTable* ctable); const SkImageInfo& info() const; diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 528541dadfb8..889a3db81e6f 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -613,7 +613,7 @@ android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitm return nullptr; } - android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable); + android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable); wrapper->getSkBitmap(bitmap); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too @@ -623,7 +623,7 @@ android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitm } android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, - SkColorTable* ctable, int fd, void* addr, bool readOnly) { + SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly) { const SkImageInfo& info = bitmap->info(); if (info.colorType() == kUnknown_SkColorType) { doThrowIAE(env, "unknown bitmap configuration"); @@ -633,7 +633,8 @@ android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, if (!addr) { // Map existing ashmem region if not already mapped. int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE); - addr = mmap(NULL, ashmem_get_size_region(fd), flags, MAP_SHARED, fd, 0); + size = ashmem_get_size_region(fd); + addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { return nullptr; } @@ -643,7 +644,7 @@ android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, // attempting to compute our own. const size_t rowBytes = bitmap->rowBytes(); - android::Bitmap* wrapper = new android::Bitmap(addr, fd, info, rowBytes, ctable); + android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable); wrapper->getSkBitmap(bitmap); if (readOnly) { bitmap->pixelRef()->setImmutable(); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 5baa8f8740c2..a21570992850 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -101,7 +101,7 @@ public: SkColorTable* ctable); static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, - SkColorTable* ctable, int fd, void* addr, bool readOnly); + SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly); /** * Given a bitmap we natively allocate a memory block to store the contents diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 94592573e61a..b92627010059 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -350,9 +350,16 @@ void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, con postData(msgType, dataPtr, NULL); } -void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) { - // This is not needed at app layer. This should not be called because JNICameraContext cannot - // start video recording. +void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t* handle) { + // Video buffers are not needed at app layer so just return the video buffers here. + // This may be called when stagefright just releases camera but there are still outstanding + // video buffers. + if (mCamera != nullptr) { + mCamera->releaseRecordingFrameHandle(handle); + } else { + native_handle_close(handle); + native_handle_delete(handle); + } } void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata) diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp index a24aa3191dc1..8eb39e1aac58 100644 --- a/core/jni/android_hardware_location_ContextHubService.cpp +++ b/core/jni/android_hardware_location_ContextHubService.cpp @@ -337,11 +337,15 @@ static int set_dest_app(hub_message_t *msg, jint id) { return 0; } -static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) { +static void query_hub_for_apps(uint32_t hubHandle) { hub_message_t msg; query_apps_request_t queryMsg; - queryMsg.app_name.id = appId; + // TODO(b/30835598): When we're able to tell which request our + // response matches, then we should allow this to be more + // targetted, instead of always being every app in the + // system. + queryMsg.app_name.id = ALL_APPS; msg.message_type = CONTEXT_HUB_QUERY_APPS; msg.message_len = sizeof(queryMsg); @@ -354,9 +358,9 @@ static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) { } } -static void sendQueryForApps(uint64_t appId) { +static void sendQueryForApps() { for (int i = 0; i < db.hubInfo.numHubs; i++ ) { - query_hub_for_apps(appId, i); + query_hub_for_apps(i); } } @@ -386,9 +390,6 @@ static jint generate_id() { static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, jint appInstanceHandle, JNIEnv *env) { - - ALOGI("Loading App"); - // Not checking if the apps are indeed distinct app_instance_info_s entry; assert(appInfo); @@ -404,13 +405,14 @@ static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, db.appInstances[appInstanceHandle] = entry; - // Finally - let the service know of this app instance + // Finally - let the service know of this app instance, to populate + // the Java cache. env->CallIntMethod(db.jniInfo.jContextHubService, db.jniInfo.contextHubServiceAddAppInstance, hubHandle, entry.instanceId, entry.truncName, entry.appInfo.version); - ALOGW("%s App 0x%" PRIx64 " on hub Handle %" PRId32 + ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32 " as appInstance %" PRId32, action, entry.truncName, entry.hubHandle, appInstanceHandle); @@ -532,7 +534,7 @@ static void initContextHubService() { } } - sendQueryForApps(ALL_APPS); + sendQueryForApps(); } else { ALOGW("No Context Hub Module present"); } @@ -576,16 +578,63 @@ int handle_query_apps_response(const uint8_t *msg, int msgLen, return -1; } - int numApps = msgLen/sizeof(hub_app_info); - hub_app_info info; + int numApps = msgLen / sizeof(hub_app_info); const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg; - for (int i = 0; i < numApps; i++, unalignedInfoAddr++) { - memcpy(&info, unalignedInfoAddr, sizeof(info)); + // We use this information to sync our JNI and Java caches of nanoapp info. + // We want to accomplish two things here: + // 1) Remove entries from our caches which are stale, and pertained to + // apps no longer running on Context Hub. + // 2) Populate our caches with the latest information of all these apps. + + // We make a couple of assumptions here: + // A) The JNI and Java caches are in sync with each other (this isn't + // necessarily true; any failure of a single call into Java land to + // update its cache will leave that cache in a bad state. For NYC, + // we're willing to tolerate this for now). + // B) The total number of apps is relatively small, so horribly inefficent + // algorithms aren't too painful. + // C) We're going to call this relatively infrequently, so its inefficency + // isn't a big impact. + + + // (1). Looking for stale cache entries. Yes, this is O(N^2). See + // assumption (B). Per assumption (A), it is sufficient to iterate + // over just the JNI cache. + auto end = db.appInstances.end(); + for (auto current = db.appInstances.begin(); current != end; ) { + app_instance_info_s cache_entry = current->second; + // We perform our iteration here because if we call + // delete_app_instance() below, it will erase() this entry. + current++; + bool entryIsStale = true; + for (int i = 0; i < numApps; i++) { + // We use memcmp since this could be unaligned. + if (memcmp(&unalignedInfoAddr[i].app_name.id, + &cache_entry.appInfo.app_name.id, + sizeof(cache_entry.appInfo.app_name.id)) == 0) { + // We found a match; this entry is current. + entryIsStale = false; + break; + } + } + if (entryIsStale) { + delete_app_instance(cache_entry.instanceId, env); + } + } + + // (2). Update our caches with the latest. + for (int i = 0; i < numApps; i++) { + hub_app_info query_info; + memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info)); // We will only have one instance of the app // TODO : Change this logic once we support multiple instances of the same app - jint appInstance = get_app_instance_for_app_id(info.app_name.id); - add_app_instance(&info, hubHandle, appInstance, env); + jint appInstance = get_app_instance_for_app_id(query_info.app_name.id); + if (appInstance == -1) { + // This is a previously unknown app, let's allocate an "id" for it. + appInstance = generate_id(); + } + add_app_instance(&query_info, hubHandle, appInstance, env); } return 0; @@ -709,7 +758,12 @@ static bool closeLoadTxn(bool success, jint *appInstanceHandle) { ALOGW("Could not attach to JVM !"); success = false; } - sendQueryForApps(info->appInfo.app_name.id); + // While we just called add_app_instance above, our info->appInfo was + // incomplete (for example, the 'version' is hardcoded to -1). So we + // trigger an additional query to the CHRE, so we'll be able to get + // all the app "info", and have our JNI and Java caches with the + // full information. + sendQueryForApps(); } else { ALOGW("Could not load the app successfully ! Unexpected failure"); *appInstanceHandle = INVALID_APP_ID; @@ -739,24 +793,6 @@ static bool isValidOsStatus(const uint8_t *msg, size_t msgLen, return true; } -static void invalidateNanoApps(uint32_t hubHandle) { - JNIEnv *env; - - if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) { - ALOGW("Could not attach to JVM !"); - env = nullptr; - } - - auto end = db.appInstances.end(); - for (auto current = db.appInstances.begin(); current != end; ) { - app_instance_info_s info = current->second; - current++; - if (info.hubHandle == hubHandle) { - delete_app_instance(info.instanceId, env); - } - } -} - static int handle_os_message(uint32_t msgType, uint32_t hubHandle, const uint8_t *msg, int msgLen) { int retVal = -1; @@ -824,8 +860,7 @@ static int handle_os_message(uint32_t msgType, uint32_t hubHandle, ALOGW("Context Hub handle %d restarted", hubHandle); closeTxn(); passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0); - invalidateNanoApps(hubHandle); - query_hub_for_apps(ALL_APPS, hubHandle); + query_hub_for_apps(hubHandle); retVal = 0; } break; @@ -1157,7 +1192,8 @@ static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_, if (retVal != 0) { ALOGD("Send Message failure - %d", retVal); if (msgType == CONTEXT_HUB_LOAD_APP) { - closeLoadTxn(false, nullptr); + jint ignored; + closeLoadTxn(false, &ignored); } else if (msgType == CONTEXT_HUB_UNLOAD_APP) { closeUnloadTxn(false); } diff --git a/core/res/res/color/hint_foreground_material_dark.xml b/core/res/res/color/hint_foreground_material_dark.xml index 77883d975c75..5cc955952524 100644 --- a/core/res/res/color/hint_foreground_material_dark.xml +++ b/core/res/res/color/hint_foreground_material_dark.xml @@ -15,6 +15,10 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="true" + android:state_pressed="true" + android:alpha="@dimen/hint_pressed_alpha_material_dark" + android:color="@color/foreground_material_dark" /> <item android:alpha="@dimen/hint_alpha_material_dark" android:color="@color/foreground_material_dark" /> </selector> diff --git a/core/res/res/color/hint_foreground_material_light.xml b/core/res/res/color/hint_foreground_material_light.xml index 99168fdc2962..f7465e0e5139 100644 --- a/core/res/res/color/hint_foreground_material_light.xml +++ b/core/res/res/color/hint_foreground_material_light.xml @@ -15,6 +15,10 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="true" + android:state_pressed="true" + android:alpha="@dimen/hint_pressed_alpha_material_light" + android:color="@color/foreground_material_light" /> <item android:alpha="@dimen/hint_alpha_material_light" android:color="@color/foreground_material_light" /> </selector> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 677017d45a0b..aa3396a56b40 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om taal en uitleg te kies"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidate"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Berei tans <xliff:g id="NAME">%s</xliff:g> voor"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kyk tans vir foute"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuwe <xliff:g id="NAME">%s</xliff:g> bespeur"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Gekoppel aan <xliff:g id="SESSION">%s</xliff:g>. Tik om die netwerk te bestuur."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Altydaan-VPN koppel tans..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altydaan-VPN gekoppel"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Altydaan-VPN is ontkoppel"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN-fout"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om op te stel"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om op te stel"</string> <string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string> <string name="reset" msgid="2448168080964209908">"Stel terug"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Voer taalnaam in"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgestel"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Alle tale"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Soek"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is AF"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Stel werkprofiel in staat om te werk, insluitend programme, agtergrondsinkronisering en verwante kenmerke."</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 721f884d4412..81357942a2bd 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ን በማዘጋጀት ላይ"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ስህተቶች ካሉ በመፈተሽ ላይ"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"አዲስ <xliff:g id="NAME">%s</xliff:g> ተገኝቷል"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"ለ<xliff:g id="SESSION">%s</xliff:g> የተገናኘ። አውታረመረቡን ለማደራጀት ሁለቴ ንካ።"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ሁልጊዜ የበራ VPN በመገናኘት ላይ…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ሁልጊዜ የበራ VPN ተገናኝቷል"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ሁልጊዜ የበራ የVPN ግንኙነት ተቋርጧል"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"ሁልጊዜ የበራ VPN ስህተት"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"ለማዋቀር መታ ያድርጉ"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"ለማዋቀር መታ ያድርጉ"</string> <string name="upload_file" msgid="2897957172366730416">"ፋይል ምረጥ"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ምንም ፋይል አልተመረጠም"</string> <string name="reset" msgid="2448168080964209908">"ዳግም አስጀምር"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"የቋንቋ ስም ይተይቡ"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"የተጠቆሙ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ሁሉም ቋንቋዎች"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"ፈልግ"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"የሥራ ሁነታ ጠፍቷል"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"መተግበሪያዎችን፣ የበስተጀርባ ሥምረት እና ተዛማጅ ባሕሪዎችን ጨምሮ የሥራ መገለጫ እንዲሰራ ይፍቀዱ።"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 630c292fac2c..7308d54ba116 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1264,7 +1264,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"انقر لاختيار لغة وتنسيق"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"جارٍ تحضير <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"جارٍ التحقق من الأخطاء"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"تم اكتشاف <xliff:g id="NAME">%s</xliff:g> جديدة"</string> @@ -1343,8 +1342,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. انقر لإدارة الشبكة."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"جارٍ الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"تم الاتصال بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"تم فصل الشبكة الظاهرية الخاصة (VPN) دائمة التشغيل"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"خطأ بشبكة ظاهرية خاصة (VPN) دائمة التشغيل"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"انقر للتهيئة."</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"انقر للإعداد."</string> <string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string> <string name="no_file_chosen" msgid="6363648562170759465">"لم يتم اختيار أي ملف"</string> <string name="reset" msgid="2448168080964209908">"إعادة تعيين"</string> @@ -1791,6 +1791,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"اكتب اسم اللغة"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"المقترحة"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"جميع اللغات"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"كل المناطق"</string> <string name="locale_search_menu" msgid="2560710726687249178">"البحث"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"وضع العمل معطَّل"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"السماح باستخدام الملف الشخصي للعمل، بما في ذلك التطبيقات ومزامنة الخلفية والميزات ذات الصلة."</string> diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml index 502131ac0b09..94b7d271df32 100644 --- a/core/res/res/values-az-rAZ/strings.xml +++ b/core/res/res/values-az-rAZ/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dil və tərtibatı seçmək üçün tıklayın"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCÇDEƏFGĞHİIJKLMNOÖPQRSŞTUÜVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"namizədlər"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanır"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Səhvlər yoxlanılır"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> aşkarlandı"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> sessiyaya qoşulun. Şəbəkəni idarə etmək üçün tıklayın."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Həmişə aktiv VPN bağlanır..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN bağlantısı həmişə aktiv"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Həmişə aktiv VPN bağlantısı kəsildi"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Həmişə aktiv VPN xətası"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Konfiqurasiya üçün tıklayın"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Quraşdırmaq üçün tıklayın"</string> <string name="upload_file" msgid="2897957172366730416">"Fayl seçin"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Heç bir fayl seçilməyib"</string> <string name="reset" msgid="2448168080964209908">"Sıfırlayın"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Dil adını daxil edin"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Təklif edilmiş"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Bütün dillər"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Bütün bölgələr"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Axtarın"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"İş rejimi DEAKTİVDİR"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Tətbiq, arxa fon sinxronizasiyası və digər əlaqədar xüsusiyyətlər daxil olmaqla iş profilinin fəaliyyətinə icazə verin."</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index c8fc56f63508..c540c960e337 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1189,7 +1189,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste izabrali jezik i raspored"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> se priprema"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Proverava se da li postoje greške"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string> @@ -1268,8 +1267,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da biste upravljali mrežom."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje stalno uključenog VPN-a..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno uključeni VPN je povezan"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Veza sa stalno uključenim VPN-om je prekinuta"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška stalno uključenog VPN-a"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurisali"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite da biste podesili"</string> <string name="upload_file" msgid="2897957172366730416">"Odaberi datoteku"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabrana nijedna datoteka"</string> <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string> @@ -1683,6 +1683,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženi"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Režim za Work je ISKLJUČEN"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Dozvoljava profilu za Work da funkcioniše, uključujući aplikacije, sinhronizaciju u pozadini i srodne funkcije."</string> diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml index c98b1513e954..49033b435509 100644 --- a/core/res/res/values-be-rBY/strings.xml +++ b/core/res/res/values-be-rBY/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Дакраніцеся, каб выбраць мову і раскладку"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Падрыхтоўка <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Праверка на наяўнасць памылак"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Падлучаны да <xliff:g id="SESSION">%s</xliff:g>. Націсніце, каб кiраваць сеткай."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Падключэнне заўсёды ўключанага VPN..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Заўсёды ўключаны i падключаны VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Заўсёды ўключаны VPN адключаны"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Памылка заўсёды ўключанага VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Дакраніцеся, каб сканфігураваць"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Дакраніцеся, каб наладзіць"</string> <string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string> <string name="reset" msgid="2448168080964209908">"Скінуць"</string> @@ -1719,6 +1719,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Увядзіце назву мовы"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Прапанаваныя"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Усе мовы"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Усе рэгіёны"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Шукаць"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Рэжым працы АДКЛЮЧАНЫ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Дазволіць функцыянаванне працоўнага профілю, у тым ліку праграм, фонавай сінхранізацыі і звязаных з імі функцый."</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index cffc8509134b..9d77598ba58f 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Докоснете, за да изберете език и подредба"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>: Подготвя се"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверява се за грешки"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Открито е ново хранилище (<xliff:g id="NAME">%s</xliff:g>)"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Свързана с/ъс <xliff:g id="SESSION">%s</xliff:g>. Докоснете, за да управлявате мрежата."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Установява се връзка с винаги включената виртуална частна мрежа (VPN)…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Установена е връзка с винаги включената виртуална частна мрежа (VPN)"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Няма връзка с винаги включената виртуална частна мрежа (VPN)"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка във винаги включената виртуална частна мрежа (VPN)"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Докоснете, за да конфигурирате"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Докоснете, за да настроите"</string> <string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Няма избран файл"</string> <string name="reset" msgid="2448168080964209908">"Повторно задаване"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Въведете име на език"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Всички езици"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Всички региони"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Търсене"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Работният режим е ИЗКЛЮЧЕН"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Разрешаване на функционирането на служебния потребителски профил, включително приложенията, синхронизирането на заден план и свързаните функции."</string> diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml index aa2d5d545c7f..206aef83d59a 100644 --- a/core/res/res/values-bn-rBD/strings.xml +++ b/core/res/res/values-bn-rBD/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ভাষা এবং লেআউট নির্বাচন করুন আলতো চাপ দিন"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"প্রার্থীরা"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> প্রস্তুত করা হচ্ছে"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ত্রুটি রয়েছে কিনা পরীক্ষা করা হচ্ছে"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"নতুন <xliff:g id="NAME">%s</xliff:g> সনাক্ত করা হয়েছে"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> তে সংযুক্ত হয়েছে৷ নেটওয়ার্ক পরিচালনা করতে আলতো চাপুন৷"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"সর্বদা-চালু VPN সংযুক্ত হচ্ছে..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"সর্বদা-চালু VPN সংযুক্ত হয়েছে"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"সর্বদা-চালু VPN এর সংযোগ বিচ্ছিন্ন হয়েছে"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"সর্বদা-চালু VPN ত্রুটি"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"কনফিগার করতে আলতো চাপুন"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"সেট আপ করতে আলতো চাপুন"</string> <string name="upload_file" msgid="2897957172366730416">"ফাইল বেছে নিন"</string> <string name="no_file_chosen" msgid="6363648562170759465">"কোনো ফাইল নির্বাচন করা হয়নি"</string> <string name="reset" msgid="2448168080964209908">"পুনরায় সেট করুন"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"ভাষার নাম লিখুন"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"প্রস্তাবিত"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"সকল ভাষা"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"সমস্ত অঞ্চল"</string> <string name="locale_search_menu" msgid="2560710726687249178">"অনুসন্ধান করুন"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"কাজের মোড বন্ধ আছে"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"অ্যাপ্লিকেশান, পটভূমি সিঙ্ক এবং সম্পর্কিত বৈশিষ্ট্যগুলি সহ কর্মস্থলের প্রোফাইলটিকে কাজ করার অনুমতি দিন।"</string> diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml index d9bb9f0ec518..540348b0bbfd 100644 --- a/core/res/res/values-bs-rBA/strings.xml +++ b/core/res/res/values-bs-rBA/strings.xml @@ -1191,7 +1191,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite za odabir jezika i rasporeda"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema se <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Provjera grešaka"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string> @@ -1270,8 +1269,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da upravljate mrežom."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje na uvijek aktivni VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan na uvijek aktivni VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Uvijek aktivni VPN nije povezan"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška u povezivanju na uvijek aktivni VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite za konfiguriranje"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavke"</string> <string name="upload_file" msgid="2897957172366730416">"Odabir fajla"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabran nijedan fajl"</string> <string name="reset" msgid="2448168080964209908">"Ponovno pokretanje"</string> @@ -1685,6 +1685,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Ukucajte naziv jezika"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Pretraga"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Radni način rada je ISKLJUČEN"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Omogući radnom profilu da funkcionira, uključujući aplikacije, sinhronizaciju u pozadini i povezane funkcije."</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index b3a0cdeb256b..87832a7e2c29 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"S\'està preparant <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"S\'està comprovant si hi ha errors"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"S\'ha detectat <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Connectat a <xliff:g id="SESSION">%s</xliff:g>. Pica per gestionar la xarxa."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"T\'estàs connectant a la VPN sempre activada…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Estàs connectat a la VPN sempre activada"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"La VPN sempre activada està desconnectada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de la VPN sempre activada"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca per configurar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca per configurar"</string> <string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string> <string name="no_file_chosen" msgid="6363648562170759465">"No s\'ha escollit cap fitxer"</string> <string name="reset" msgid="2448168080964209908">"Restableix"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Nom de l\'idioma"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerits"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Tots els idiomes"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Totes les regions"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Mode de feina desactivat"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permet que el perfil professional funcioni, incloses les aplicacions, la sincronització en segon pla i les funcions relacionades."</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 59f83853d967..9be00bbb5ddc 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozvržení"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Probíhá příprava úložiště <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrola chyb"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zjištěno nové úložiště <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Připojeno k relaci <xliff:g id="SESSION">%s</xliff:g>. Klepnutím můžete síť spravovat."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Připojování k trvalé síti VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Je připojena trvalá síť VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Trvalá síť VPN je odpojena"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba trvalé sítě VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím zahájíte konfiguraci"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím přejděte do Nastavení"</string> <string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Není vybrán žádný soubor"</string> <string name="reset" msgid="2448168080964209908">"Resetovat"</string> @@ -1719,6 +1719,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Zadejte název jazyka"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Všechny jazyky"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Vyhledávání"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovní režim je VYPNUTÝ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Povolí fungování pracovního profilu, včetně aplikací, synchronizace na pozadí a souvisejících funkcí."</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 48b3b87c8918..b6539b188a7c 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryk for at vælge sprog og layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Kontrollerer for fejl"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Der blev registreret et nyt <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til altid aktiveret VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN er forbundet"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Forbindelsen til altid aktiveret VPN er afbrudt"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i altid aktiveret VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryk for at konfigurere"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryk for at konfigurere"</string> <string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string> <string name="reset" msgid="2448168080964209908">"Nulstil"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Angiv sprogets navn"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslået"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Alle sprog"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Søg"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Arbejdstilstand er slået FRA"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Tillad, at arbejdsprofilen aktiveres, bl.a. i forbindelse med apps, baggrundssynkronisering og relaterede funktioner."</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index cb61390d9452..4a58c3dfdd31 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Zum Auswählen von Sprache und Layout tippen"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> wird vorbereitet"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Nach Fehlern wird gesucht"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Neue <xliff:g id="NAME">%s</xliff:g> entdeckt"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Verbunden mit <xliff:g id="SESSION">%s</xliff:g>. Zum Verwalten des Netzwerks tippen"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Verbindung zu durchgehend aktivem VPN wird hergestellt…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Mit durchgehend aktivem VPN verbunden"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Verbindung zu durchgehend aktivem VPN getrennt"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Durchgehend aktives VPN – Verbindungsfehler"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Zum Konfigurieren tippen"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Zum Einrichten tippen"</string> <string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Keine ausgewählt"</string> <string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Sprache eingeben"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Vorschläge"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Alle Sprachen"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Alle Regionen"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Suche"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Arbeitsmodus ist AUS"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Arbeitsprofil aktivieren, einschließlich Apps, Synchronisierung im Hintergrund und verknüpfter Funktionen."</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 54f39ebd334c..ee7b8b6b3462 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Προετοιμασία <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Έλεγχος για σφάλματα"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Εντοπίστηκε νέο μέσο αποθήκευσης <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Συνδέθηκε με <xliff:g id="SESSION">%s</xliff:g>. Πατήστε για να διαχειριστείτε το δίκτυο."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Σύνδεση πάντα ενεργοποιημένου VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Έχει συνδεθεί πάντα ενεργοποιημένο VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Το πάντα ενεργοποιημένο VPN αποσυνδέθηκε"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Σφάλμα πάντα ενεργοποιημένου VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Πατήστε για διαμόρφωση"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Πατήστε για ρύθμιση"</string> <string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Δεν επιλέχθηκε κανένα αρχείο."</string> <string name="reset" msgid="2448168080964209908">"Επαναφορά"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Εισαγ. όνομα γλώσσας"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Προτεινόμενες"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Όλες οι γλώσσες"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Όλες οι περιοχές"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Αναζήτηση"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Λειτουργία εργασίας ΑΠΕΝΕΡΓ/ΝΗ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Να επιτρέπεται η λειτουργία του προφίλ εργασίας σας, συμπεριλαμβανομένων των εφαρμογών, του συγχρονισμού στο παρασκήνιο και των σχετικών λειτουργιών."</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index aeb9634eb480..5926a88af894 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string> <string name="upload_file" msgid="2897957172366730416">"Choose file"</string> <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string> <string name="reset" msgid="2448168080964209908">"Reset"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index aeb9634eb480..5926a88af894 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string> <string name="upload_file" msgid="2897957172366730416">"Choose file"</string> <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string> <string name="reset" msgid="2448168080964209908">"Reset"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index aeb9634eb480..5926a88af894 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tap to select language and layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidates"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparing <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Checking for errors"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"New <xliff:g id="NAME">%s</xliff:g> detected"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN connecting…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN connected"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN disconnected"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Always-on VPN error"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tap to configure"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tap to set up"</string> <string name="upload_file" msgid="2897957172366730416">"Choose file"</string> <string name="no_file_chosen" msgid="6363648562170759465">"No file chosen"</string> <string name="reset" msgid="2448168080964209908">"Reset"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggested"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"All languages"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"All regions"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Search"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Work mode is OFF"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Allow work profile to function, including apps, background sync and related features."</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 85fb97c0c8ed..45c3f7c1acd0 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Presiona para seleccionar el idioma y el diseño"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando el medio <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Verificando errores"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Se detectó un nuevo medio (<xliff:g id="NAME">%s</xliff:g>)."</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Pulsa para gestionar la red."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con la VPN siempre activada..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN siempre activada."</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Se desconectó la VPN siempre activada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN siempre activada."</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Presiona para configurar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Presiona para configurar"</string> <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string> <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string> <string name="reset" msgid="2448168080964209908">"Restablecer"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Nombre del idioma"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Búsqueda"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo DESACTIVADO"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se active el perfil de trabajo, incluidas las apps, la sincronización en segundo plano y las funciones relacionadas."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index df9251f86c56..0b32a7fc6414 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando errores"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nueva <xliff:g id="NAME">%s</xliff:g> detectada"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Conectando VPN siempre activada…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN siempre activada conectada"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN siempre activada desconectada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error de VPN siempre activada"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toca para configurar"</string> <string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Archivo no seleccionado"</string> <string name="reset" msgid="2448168080964209908">"Restablecer"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Nombre de idioma"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Todos los idiomas"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Todas las regiones"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabajo desactivado"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que se utilice el perfil de trabajo, incluidas las aplicaciones, la sincronización en segundo plano y las funciones relacionadas."</string> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index 44698fe64463..e1516b7f2435 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Puudutage keele ja paigutuse valimiseks"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSŠZŽTUVWÕÄÖÜXY"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaadid"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Üksuse <xliff:g id="NAME">%s</xliff:g> ettevalmistamine"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Vigade kontrollimine"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tuvastati uus üksus <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Koputage võrgu haldamiseks"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ühendamine alati sees VPN-iga …"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ühendatud alati sees VPN-iga"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alati sees VPN pole ühendatud"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati sees VPN-i viga"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Puudutage seadistamiseks"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Puudutage seadistamiseks"</string> <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string> <string name="reset" msgid="2448168080964209908">"Lähtesta"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Sisestage keele nimi"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Soovitatud"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Kõik keeled"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Kõik piirkonnad"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Otsing"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Töörežiim on VÄLJA LÜLITATUD"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Lubatakse tööprofiili toimingud, sh rakendused, taustal sünkroonimine ja seotud funktsioonid."</string> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index 6f33f312bf59..a90df61e7813 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"hautagaiak"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> prestatzen"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Errorerik dagoen egiaztatzen"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> berria hauteman da"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> saiora konektatuta. Sakatu sarea kudeatzeko."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Beti aktibatuta dagoen VPNa konektatzen…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Beti aktibatuta dagoen VPNa konektatu da"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Deskonektatu egin da beti aktibatuta dagoen VPN konexioa"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Beti aktibatuta dagoen VPN errorea"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sakatu konfiguratzeko"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Konfiguratzeko, sakatu hau"</string> <string name="upload_file" msgid="2897957172366730416">"Aukeratu fitxategia"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ez da fitxategirik aukeratu"</string> <string name="reset" msgid="2448168080964209908">"Berrezarri"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Hizkuntza guztiak"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Bilaketa"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Desaktibatuta dago laneko modua"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Baimendu laneko profilak funtzionatzea, besteak beste, aplikazioak, atzeko planoko sinkronizazioa eta erlazionatutako eginbideak."</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index e86b256454ab..5332a3303763 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -924,9 +924,9 @@ <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item> <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item> </plurals> - <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدیو"</string> - <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"متأسفیم، این ویدیو برای پخش جریانی با این دستگاه معتبر نیست."</string> - <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"پخش این ویدیو ممکن نیست."</string> + <string name="VideoView_error_title" msgid="3534509135438353077">"مشکل در ویدئو"</string> + <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">"تأیید"</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> @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"برای انتخاب زبان و چیدمان ضربه بزنید"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"در حال آمادهسازی <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"در حال بررسی برای خطاها"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> جدید شناسایی شد"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"به <xliff:g id="SESSION">%s</xliff:g> متصل شد. برای مدیریت شبکه ضربه بزنید."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"در حال اتصال VPN همیشه فعال…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN همیشه فعال متصل شد"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ارتباط VPN همیشه روشن قطع شد"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"خطای VPN همیشه فعال"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"جهت پیکربندی ضربه بزنید"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"برای راهاندازی ضربه بزنید"</string> <string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string> <string name="no_file_chosen" msgid="6363648562170759465">"هیچ فایلی انتخاب نشد"</string> <string name="reset" msgid="2448168080964209908">"بازنشانی"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"نام زبان را تایپ کنید"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"پیشنهادشده"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"همه زبانها"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"همه منطقهها"</string> <string name="locale_search_menu" msgid="2560710726687249178">"جستجو"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"حالت کاری خاموش است"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"به نمایه کاری اجازه فعالیت ( شامل استفاده از برنامهها، همگامسازی در پسزمینه و قابلیتهای مرتبط) داده شود."</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index e624e22da077..92de423e3b70 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Valitse kieli ja asettelu koskettamalla."</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Valmistellaan kohdetta <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tarkistetaan virheiden varalta."</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Uusi <xliff:g id="NAME">%s</xliff:g> on havaittu."</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Yhdistetty: <xliff:g id="SESSION">%s</xliff:g>. Hallinnoi verkkoa napauttamalla."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Yhdistetään aina käytössä olevaan VPN-verkkoon..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Yhdistetty aina käytössä olevaan VPN-verkkoon"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Aina käytössä olevan VPN:n yhteys on katkaistu"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Aina käytössä oleva VPN: virhe"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Määritä napauttamalla."</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Määritä koskettamalla."</string> <string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ei valittua tiedostoa"</string> <string name="reset" msgid="2448168080964209908">"Palauta"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Anna kielen nimi"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ehdotukset"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Kaikki kielet"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Kaikki alueet"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Haku"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Työtila on pois käytöstä"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Sallii työprofiiliin toiminnan, esimerkiksi sovellukset ja taustasynkronoinnin."</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index f6b2ab1758e6..c3f2e9a612b7 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Touchez pour sélectionner la langue et la configuration du clavier"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation de « <xliff:g id="NAME">%s</xliff:g> » en cours"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs en cours..."</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire « <xliff:g id="NAME">%s</xliff:g> » a été détectée"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"RPV permanent déconnecté"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Touchez pour configurer"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Touchez pour configurer"</string> <string name="upload_file" msgid="2897957172366730416">"Choisir un fichier"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string> <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggestions"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Le mode Travail est désactivé"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index d726c63baf29..bdb7196ea592 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Appuyer pour sélectionner la langue et la disposition"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Préparation mémoire \"<xliff:g id="NAME">%s</xliff:g>\" en cours"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Recherche d\'erreurs"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Une nouvelle mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\" a été détectée."</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN permanent en cours de connexion…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN permanent connecté"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN permanent déconnecté"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erreur du VPN permanent"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Appuyez ici pour configurer."</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Appuyer pour configurer"</string> <string name="upload_file" msgid="2897957172366730416">"Sélectionner un fichier"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Aucun fichier sélectionné"</string> <string name="reset" msgid="2448168080964209908">"Réinitialiser"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Saisissez la langue"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Recommandations"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Toutes les langues"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Rechercher"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Mode professionnel DÉSACTIVÉ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Autoriser le fonctionnement du profil professionnel, y compris les applications, la synchronisation en arrière-plan et les fonctionnalités associées."</string> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index 16a46f1adee5..ed8ad8c94a54 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar o idioma e o deseño"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNÑOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando a <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Comprobando se hai erros"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Detectouse unha <xliff:g id="NAME">%s</xliff:g> nova"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca aquí para xestionar a rede."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre activada conectándose..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre activada conectada"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Desconectouse a VPN sempre activada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre activada"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toca para configurar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string> <string name="upload_file" msgid="2897957172366730416">"Escoller un ficheiro"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Non se seleccionou ningún ficheiro"</string> <string name="reset" msgid="2448168080964209908">"Restablecer"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Nome do idioma"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suxeridos"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Buscar"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de traballo DESACTIVADO"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permite que funcione o perfil de traballo, incluídas as aplicacións, a sincronización en segundo plano e as funcións relacionadas."</string> diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml index 1f49bec1f8ed..c71391b5b171 100644 --- a/core/res/res/values-gu-rIN/strings.xml +++ b/core/res/res/values-gu-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ઉમેદવારો"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ને તૈયાર કરી રહ્યું છે"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ભૂલો માટે તપાસી રહ્યું છે"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"નવું <xliff:g id="NAME">%s</xliff:g> મળ્યું"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> થી કનેક્ટ થયાં. નેટવર્કને સંચાલિત કરવા માટે ટૅપ કરો."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"હંમેશા-ચાલુ VPN કનેક્ટ થઈ રહ્યું છે…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"હંમેશા-ચાલુ VPN કનેક્ટ થયું"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"હંમેશાં-ચાલુ VPN ડિસ્કનેક્ટ થયું"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"હંમેશાં ચાલુ VPN ભૂલ"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"ગોઠવવા માટે ટૅપ કરો"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"સેટ કરવા માટે ટૅપ કરો"</string> <string name="upload_file" msgid="2897957172366730416">"ફાઇલ પસંદ કરો"</string> <string name="no_file_chosen" msgid="6363648562170759465">"કોઈ ફાઇલ પસંદ કરેલી નથી"</string> <string name="reset" msgid="2448168080964209908">"ફરીથી સેટ કરો"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"ભાષાનું નામ ટાઇપ કરો"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"સૂચવેલા"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"બધી ભાષાઓ"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"તમામ પ્રદેશ"</string> <string name="locale_search_menu" msgid="2560710726687249178">"શોધ"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"કાર્ય મોડ બંધ છે"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"કાર્ય પ્રોફાઇલને ઍપ્લિકેશનો, પૃષ્ઠભૂમિ સમન્વયન અને સંબંધિત સુવિધાઓ સહિતનું કાર્ય કરવાની મંજૂરી આપો."</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 3fd6f9e7e4b1..98b17d7986ae 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा और लेआउट चुनने के लिए टैप करें"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"उम्मीदवार"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> को तैयार किया जा रहा है"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटियों की जांच कर रहा है"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नए <xliff:g id="NAME">%s</xliff:g> का पता लगा"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> से कनेक्ट किया गया. नेटवर्क प्रबंधित करने के लिए टैप करें."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"हमेशा-चालू VPN कनेक्ट हो रहा है…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"हमेशा-चालू VPN कनेक्ट है"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"हमेशा-चालू VPN डिस्कनेक्ट है"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"हमेशा-चालू VPN त्रुटि"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फ़िगर करने के लिए टैप करें"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करने के लिए टैप करें"</string> <string name="upload_file" msgid="2897957172366730416">"फ़ाइल चुनें"</string> <string name="no_file_chosen" msgid="6363648562170759465">"कोई फ़ाइल चुनी नहीं गई"</string> <string name="reset" msgid="2448168080964209908">"रीसेट करें"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"भाषा का नाम लिखें"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाए गए"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"सभी भाषाएं"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"सभी क्षेत्र"</string> <string name="locale_search_menu" msgid="2560710726687249178">"खोजें"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद है"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"ऐप्स, पृष्ठभूमि समन्वयन और संबंधित सुविधाओं सहित कार्य प्रोफ़ाइल को काम करने की अनुमति दें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 8b503c985307..115a97ea55e2 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1189,7 +1189,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dodirnite da biste odabrali jezik i raspored"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Priprema uređaja <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Traženje pogrešaka"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Otkriven je novi uređaj <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1268,8 +1267,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Povezan sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dotaknite za upravljanje mrežom."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje s uvijek uključenom VPN mrežom…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan s uvijek uključenom VPN mrežom"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Prekinuta je veza s uvijek uključenom VPN mrežom"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Pogreška uvijek uključene VPN mreže"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurirali"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavljanje"</string> <string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nema odabranih datoteka"</string> <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string> @@ -1683,6 +1683,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Svi jezici"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Sve regije"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Pretraži"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Radni je način ISKLJUČEN"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Omogućuje radnom profilu da funkcionira, uključujući aplikacije, sinkronizaciju u pozadini i povezane značajke."</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index ebdae0fe6756..54980618f998 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> előkészítése"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hibák keresése"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Új <xliff:g id="NAME">%s</xliff:g> észlelve"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Csatlakozva ide: <xliff:g id="SESSION">%s</xliff:g>. Érintse meg a hálózat kezeléséhez."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Csatlakozás a mindig bekapcsolt VPN-hez..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Csatlakozva a mindig bekapcsolt VPN-hez"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Kapcsolat bontva a mindig bekapcsolt VPN-nel"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Hiba a mindig bekapcsolt VPN-nel"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Koppintson a konfiguráláshoz"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Koppintson ide a beállításhoz"</string> <string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nincs fájl kiválasztva"</string> <string name="reset" msgid="2448168080964209908">"Alaphelyzet"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Adja meg a nyelvet"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Javasolt"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Minden nyelv"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Minden régió"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Keresés"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"A munka mód KI van kapcsolva"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Munkaprofil használatának engedélyezése, beleértve az alkalmazásokat, a háttérben való szinkronizálást és a kapcsolódó funkciókat."</string> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index 7178c5f11262..2b59f7e13210 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՈՒՓՔԵւՕՖ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"թեկնածուները"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ի նախապատրաստում"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Սխալների ստուգում"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Հայտնաբերվել է նոր <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Կապակացված է <xliff:g id="SESSION">%s</xliff:g>-ին: Սեղմեք` ցանցը կառավարելու համար:"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Միշտ-միացված VPN-ը կապվում է..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Միշտ-առցանց VPN-ը կապակցված է"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"«Միշտ միացված VPN»-ն անջատված է"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN սխալը միշտ միացված"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Հպեք՝ կազմաձևելու համար"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Հպեք՝ կարգավորելու համար"</string> <string name="upload_file" msgid="2897957172366730416">"Ընտրել ֆայլը"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ոչ մի ֆայլ չի ընտրված"</string> <string name="reset" msgid="2448168080964209908">"Վերակայել"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Մուտքագրեք լեզուն"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Առաջարկներ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Բոլոր լեզուները"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Բոլոր տարածաշրջանները"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Որոնում"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Աշխատանքային ռեժիմն ԱՆՋԱՏՎԱԾ Է"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Միացնել աշխատանքային պրոֆիլը՝ հավելվածները, ֆոնային համաժամեցումը և առնչվող գործառույթները"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 41902b54397c..a817b32a911a 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketuk untuk memilih bahasa dan tata letak"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyiapkan <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Memeriksa kesalahan"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baru terdeteksi"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Menyambungkan VPN selalu aktif..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN selalu aktif tersambung"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN selalu aktif terputus"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kesalahan VPN selalu aktif"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketuk untuk mengonfigurasi"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketuk untuk menyiapkan"</string> <string name="upload_file" msgid="2897957172366730416">"Pilih file"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Tidak ada file yang dipilih"</string> <string name="reset" msgid="2448168080964209908">"Setel ulang"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Ketik nama bahasa"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Disarankan"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Semua wilayah"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Telusuri"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Mode kerja NONAKTIF"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Izinkan profil kerja berfungsi, termasuk aplikasi, sinkronisasi latar belakang, dan fitur terkait."</string> diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml index 34165bafa8ce..339ee6aeba2d 100644 --- a/core/res/res/values-is-rIS/strings.xml +++ b/core/res/res/values-is-rIS/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ýttu til að velja tungumál og útlit"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCDÐEÉFGHIÍJKLMNOÓPQRSTUÚVWXYÝZÞÆÖ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"möguleikar"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Undirbýr <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Leitar að villum"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nýtt <xliff:g id="NAME">%s</xliff:g> fannst"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Tengt við <xliff:g id="SESSION">%s</xliff:g>. Ýttu til að hafa umsjón með netinu."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Sívirkt VPN tengist…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Sívirkt VPN tengt"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Sívirkt VPN aftengt"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Villa í sívirku VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ýttu til að stilla"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ýttu til að setja upp"</string> <string name="upload_file" msgid="2897957172366730416">"Velja skrá"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Engin skrá valin"</string> <string name="reset" msgid="2448168080964209908">"Endurstilla"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Sláðu inn heiti tungumáls"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Tillögur"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Öll tungumál"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Öll svæði"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Leita"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Slökkt á vinnusniði"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Leyfa virkni vinnusniðs, m.a. forrita, samstillingar í bakgrunni og tengdra eiginleika."</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 5668e6d264be..1c909b792d65 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tocca per selezionare la lingua e il layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidati"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparazione della <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ricerca errori"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nuova <xliff:g id="NAME">%s</xliff:g> rilevata"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Collegata a <xliff:g id="SESSION">%s</xliff:g>. Tocca per gestire la rete."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Connessione a VPN sempre attiva…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre attiva connessa"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre attiva disconnessa"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Errore VPN sempre attiva"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tocca per configurare"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocca per configurare"</string> <string name="upload_file" msgid="2897957172366730416">"Scegli file"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nessun file è stato scelto"</string> <string name="reset" msgid="2448168080964209908">"Reimposta"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Digita nome lingua"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Suggerite"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Tutte le lingue"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Tutte le aree geografiche"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Cerca"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modalità Lavoro DISATTIVATA"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Attiva il profilo di lavoro, incluse app, sincronizzazione in background e funzioni correlate."</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 19f39536c650..1f873ac0095a 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"הכנת <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"בודק אם יש שגיאות"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"זוהה <xliff:g id="NAME">%s</xliff:g> חדש"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"מחובר אל <xliff:g id="SESSION">%s</xliff:g>. הקש כדי לנהל את הרשת."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ה-VPN שמופעל תמיד, מתחבר..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ה-VPN שפועל תמיד, מחובר"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"חיבור תמידי ל-VPN מנותק"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"שגיאת VPN שמופעל תמיד"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"הקש כדי להגדיר"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"הקש כדי להגדיר"</string> <string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string> <string name="no_file_chosen" msgid="6363648562170759465">"לא נבחר קובץ"</string> <string name="reset" msgid="2448168080964209908">"איפוס"</string> @@ -1719,6 +1719,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"הקלד שם שפה"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"הצעות"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"כל השפות"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"כל האזורים"</string> <string name="locale_search_menu" msgid="2560710726687249178">"חיפוש"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"מצב העבודה כבוי"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"אפשר לפרופיל העבודה לפעול, כולל אפליקציות, סנכרון ברקע ותכונות קשורות."</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 13724a97f786..682766bfbf42 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"タップして言語とレイアウトを選択してください"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>を準備中"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"エラーを確認中"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"新しい<xliff:g id="NAME">%s</xliff:g>が検出されました"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>に接続しました。ネットワークを管理するにはタップしてください。"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPNに常時接続しています…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPNに常時接続しました"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"常時接続 VPN の接続を解除しました"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"常時接続VPNのエラー"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"タップして設定"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"設定するにはタップします"</string> <string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string> <string name="reset" msgid="2448168080964209908">"リセット"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"言語名を入力"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"言語の候補"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"すべての言語"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"すべての地域"</string> <string name="locale_search_menu" msgid="2560710726687249178">"検索"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Work モード OFF"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"仕事用プロファイルで、アプリ、バックグラウンド同期などの関連機能の使用を許可します。"</string> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index fbe1b0083b9d..5cbf001c5296 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"შეეხეთ ენისა და განლაგების ასარჩევად"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"კანდიდატები"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ის მომზადება"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"შეცდომების შემოწმება"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"აღმოჩენილია ახალი <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"მიერთებულია <xliff:g id="SESSION">%s</xliff:g>-ზე. შეეხეთ ქსელის სამართავად."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"მიმდინარეობს მუდმივად ჩართული VPN-ის მიერთება…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"მუდმივად ჩართული VPN-ის მიერთებულია"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"მუდმივად ჩართული VPN გათიშულია"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"შეცდომა მუდამ VPN-ზე"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"შეეხეთ პარამეტრების კონფიგურაციისთვის"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"შეეხეთ დასაყენებლად"</string> <string name="upload_file" msgid="2897957172366730416">"ფაილის არჩევა"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ფაილი არჩეული არ არის"</string> <string name="reset" msgid="2448168080964209908">"საწყისზე დაბრუნება"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"აკრიფეთ ენის სახელი"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"რეკომენდებული"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ყველა ენა"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"ყველა რეგიონი"</string> <string name="locale_search_menu" msgid="2560710726687249178">"ძიება"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"სამსახურის რეჟიმი გამორთულია"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"სამსახურის პროფილის მუშაობის დაშვება, მათ შორის, აპების, ფონური სინქრონიზაციის და დაკავშირებული ფუნქციების."</string> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index 11497b962ae0..c7c91afe19d1 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"үміткерлер"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> дайындалуда"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Қателер тексерілуде"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңа <xliff:g id="NAME">%s</xliff:g> анықталды"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> жүйесіне жалғанған. Желіні басқару үшін түріңіз."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Әрқашан қосылған ВЖЖ жалғануда…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Әрқашан қосылған ВЖЖ жалғанған"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Әрқашан қосулы VPN желісі ажыратылды"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Әрқашан қосылған ВЖЖ қателігі"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялау үшін түртіңіз"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Реттеу үшін түртіңіз"</string> <string name="upload_file" msgid="2897957172366730416">"Файлды таңдау"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ешқандай файл таңдалмаған"</string> <string name="reset" msgid="2448168080964209908">"Қайта реттеу"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Тіл атауын теріңіз"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ұсынылған"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Барлық тілдер"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Барлық аймақтар"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Іздеу"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Жұмыс режимі ӨШІРУЛІ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Жұмыс профиліне, соның ішінде, қолданбаларға, фондық синхрондауға және қатысты мүмкіндіктерге жұмыс істеуге рұқсат ету."</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 85fb30317281..54889fa8356e 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -1166,7 +1166,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"បេក្ខជន"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"កំពុងរៀបចំ <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"កំពុងពិនិត្យរកកំហុស"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"បានរកឃើញ <xliff:g id="NAME">%s</xliff:g> ថ្មី"</string> @@ -1245,8 +1244,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"បានភ្ជាប់ទៅ <xliff:g id="SESSION">%s</xliff:g> ។ ប៉ះ ដើម្បីគ្រប់គ្រងបណ្ដាញ។"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"បើកការតភ្ជាប់ VPN ជានិច្ច..។"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ភ្ជាប់ VPN ជានិច្ច"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"បានផ្តាច់ VPN ដែលបើកជានិច្ច"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"បើកកំហុស VPN ជានិច្ច"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"ប៉ះដើម្បីកំណត់រចនាសម្ព័ន្ធ"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"ប៉ះដើម្បីដំឡើង"</string> <string name="upload_file" msgid="2897957172366730416">"ជ្រើសឯកសារ"</string> <string name="no_file_chosen" msgid="6363648562170759465">"គ្មានឯកសារបានជ្រើស"</string> <string name="reset" msgid="2448168080964209908">"កំណត់ឡើងវិញ"</string> @@ -1649,6 +1649,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"វាយបញ្ចូលឈ្មោះភាសា"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"បានស្នើ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ភាសាទាំងអស់"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"ស្វែងរក"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"របៀបការងារបានបិទ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"អនុញ្ញាតឲ្យប្រវត្តិរូបការងារដំណើរការ ដោយរាប់បញ្ចូលទាំងកម្មវិធី ការធ្វើសមកាលកម្មផ្ទៃខាងក្រោយ និងលក្ខណៈពិសេសដែលពាក់ព័ន្ធ។"</string> diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml index ab3775101c15..60d42b2414d3 100644 --- a/core/res/res/values-kn-rIN/strings.xml +++ b/core/res/res/values-kn-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ಅಭ್ಯರ್ಥಿಗಳು"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ಅನ್ನು ಸಿದ್ಧಪಡಿಸಲಾಗುತ್ತಿದೆ"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ದೋಷಗಳನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ಹೊಸ <xliff:g id="NAME">%s</xliff:g> ಪತ್ತೆಯಾಗಿದೆ"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ. ನೆಟ್ವರ್ಕ್ ನಿರ್ವಹಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕಗೊಳ್ಳುತ್ತಿದೆ…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ಯಾವಾಗಲೂ-ಆನ್ VPN ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"ಯಾವಾಗಲೂ-ಆನ್ VPN ದೋಷ"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"ಕಾನ್ಫಿಗರ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="upload_file" msgid="2897957172366730416">"ಫೈಲ್ ಆಯ್ಕೆಮಾಡು"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ಯಾವುದೇ ಫೈಲ್ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ"</string> <string name="reset" msgid="2448168080964209908">"ಮರುಹೊಂದಿಸು"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"ಸೂಚಿತ ಭಾಷೆ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string> <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕು"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"ಅಪ್ಲಿಕೇಶನ್ಗಳು, ಹಿನ್ನೆಲೆ ಸಿಂಕ್ ಮತ್ತು ಇತರ ಸಂಬಂಧಿತ ವೈಶಿಷ್ಟ್ಯಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಅನುಮತಿಸಿ."</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 1df55c92d810..e661c65b6bf9 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"탭하여 언어와 레이아웃을 선택하세요."</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> 준비 중"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"오류 확인 중"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"새로운 <xliff:g id="NAME">%s</xliff:g> 감지됨"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>에 연결되어 있습니다. 네트워크를 관리하려면 누르세요."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"연결 유지 VPN에 연결하는 중…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"연결 유지 VPN에 연결됨"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"연결 유지 VPN 연결 해제됨"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"연결 유지 VPN 오류"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"설정하려면 탭하세요."</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"탭하여 설정"</string> <string name="upload_file" msgid="2897957172366730416">"파일 선택"</string> <string name="no_file_chosen" msgid="6363648562170759465">"파일을 선택하지 않았습니다."</string> <string name="reset" msgid="2448168080964209908">"초기화"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"언어 이름 입력"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"추천"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"모든 언어"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"검색"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"직장 모드가 사용 중지됨"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"앱, 백그라운드 동기화 및 관련 기능을 포함한 직장 프로필이 작동하도록 허용"</string> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index 9e0c6cf6675a..6a0089f57486 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Тил жана калып тандоо үчүн таптап коюңуз"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"талапкерлер"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> даярдалууда"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Каталар текшерилүүдө"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Жаңы <xliff:g id="NAME">%s</xliff:g> аныкталды"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> сеансына туташуу ишке ашты. Желенин параметрлерин өзгөртүү үчүн бул жерди басыңыз."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Дайым иштеген VPN туташууда…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Дайым иштеген VPN туташтырылды"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Дайым иштеген VPN ажыратылды"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Дайым иштеген VPN\'де ката кетти"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Конфигурациялоо үчүн таптап коюңуз"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Жөндөө үчүн таптаңыз"</string> <string name="upload_file" msgid="2897957172366730416">"Файл тандоо"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Эч файл тандалган жок"</string> <string name="reset" msgid="2448168080964209908">"Баштапкы абалга келтирүү"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Бардык тилдер"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Издөө"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Жумуш режими ӨЧҮРҮЛГӨН"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Жумуш профилин, ошондой эле колдонмолорду, фондо шайкештирүү жана ага байланыштуу функцияларды иштетиңиз."</string> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index dbf404497fe4..38b447498aa7 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ຕົວເລືອກ"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"ກຳລັງກຽມ <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ກຳລັງກວດຫາຂໍ້ຜິດພາດ"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ກວດພົບ <xliff:g id="NAME">%s</xliff:g> ໃໝ່ແລ້ວ"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"ເຊື່ອມຕໍ່ກັບ <xliff:g id="SESSION">%s</xliff:g> ແລ້ວ. ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ກຳລັງເຊື່ອມຕໍ່ Always-on VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ເຊື່ອມຕໍ່ VPN ແບບເປີດຕະຫຼອດເວລາແລ້ວ"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ຕັດການເຊື່ອມຕໍ່ VPN ແບບເປີດໃຊ້ຕະຫຼອດເວລາແລ້ວ"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN ແບບເປີດຕະຫຼອດເກີດຄວາມຜິດພາດ"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"ແຕະເພື່ອຕັ້ງຄ່າ"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"ແຕະເພື່ອຕັ້ງຄ່າ"</string> <string name="upload_file" msgid="2897957172366730416">"ເລືອກໄຟລ໌"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ບໍ່ໄດ້ເລືອກໄຟລ໌ເທື່ອ"</string> <string name="reset" msgid="2448168080964209908">"ຣີເຊັດ"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"ພິມຊື່ພາສາ"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"ແນະນຳ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ທຸກພາສາ"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"ຄົ້ນຫາ"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"ໂໝດບ່ອນເຮັດວຽກປິດຢູ່"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"ອະນຸຍາດໃຫ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກສາມາດນຳໃຊ້ໄດ້ ເຊິ່ງຮວມທັງແອັບ, ການຊິ້ງຂໍ້ມູນໃນພື້ນຫຼັງ ແລະ ຄຸນສົມບັດທີ່ກ່ຽວຂ້ອງ."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 7ab35aab50c1..0406ee1881cc 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ruošiama <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tikrinama, ar nėra klaidų"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Aptikta nauja <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Prisijungta prie <xliff:g id="SESSION">%s</xliff:g>. Jei norite valdyti tinklą, palieskite."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Prisijungiama prie visada įjungto VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Prisijungta prie visada įjungto VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Visada įjungtas VPN atjungtas"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Visada įjungto VPN klaida"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Palieskite, kad konfigūruotumėte"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Palieskite, kad nustatytumėte"</string> <string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nepasirinktas joks failas"</string> <string name="reset" msgid="2448168080964209908">"Atstatyti"</string> @@ -1719,6 +1719,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Visos kalbos"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Visi regionai"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Paieška"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Darbo režimas išjungtas"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Leisti veikti darbo profiliui, įskaitant programas, sinchronizavimą fone ir susijusias funkcijas."</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index e0c83c439227..44368fb4df12 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1189,7 +1189,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Notiek <xliff:g id="NAME">%s</xliff:g> sagatavošana"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Tiek meklētas kļūdas"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Tika atrasta jauna <xliff:g id="NAME">%s</xliff:g>."</string> @@ -1268,8 +1267,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Ir izveidots savienojums ar: <xliff:g id="SESSION">%s</xliff:g>. Pieskarieties, lai pārvaldītu tīklu."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Notiek savienojuma izveide ar vienmēr ieslēgtu VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Izveidots savienojums ar vienmēr ieslēgtu VPN."</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vienmēr ieslēgts VPN ir atvienots"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kļūda saistībā ar vienmēr ieslēgtu VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Pieskarieties, lai konfigurētu."</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Pieskarieties, lai iestatītu."</string> <string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Neviens fails nav izvēlēts"</string> <string name="reset" msgid="2448168080964209908">"Atiestatīt"</string> @@ -1683,6 +1683,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Ierakstiet valodas nosaukumu"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ieteiktās"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Visas valodas"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Visi reģioni"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Meklēt"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Darba režīms IZSLĒGTS"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Atļaujiet darboties darba profilam, tostarp lietotnēm, sinhronizācijai fonā un saistītajām funkcijām."</string> diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index 413fe0ab4794..102c7a007a88 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Допрете за избирање јазик и распоред"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Се подготвува <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Се проверува за грешки"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Откриена е нова <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Поврзани сте на <xliff:g id="SESSION">%s</xliff:g>. Допрете за да управувате со мрежата."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Поврзување со секогаш вклучена VPN..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Поврзани со секогаш вклучена VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Секогаш вклучената VPN е неповрзана"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка на секогаш вклучена VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Допрете за конфигурирање"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Допрете за да поставите"</string> <string name="upload_file" msgid="2897957172366730416">"Избери датотека"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Не е избрана датотека"</string> <string name="reset" msgid="2448168080964209908">"Ресетирај"</string> @@ -1649,6 +1649,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Внеси име на јазик"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Сите јазици"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Сите региони"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Пребарај"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Режимот на работа е ИСКЛУЧЕН"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Дозволете работниот профил да функционира, вклучувајќи ги апликациите, синхронизирањето во заднина и други поврзани функции."</string> diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml index 2d416ba2faa0..a4d3fabc6dbb 100644 --- a/core/res/res/values-ml-rIN/strings.xml +++ b/core/res/res/values-ml-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"കാൻഡിഡേറ്റുകൾ"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> തയ്യാറാകുന്നു"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"പിശകുകളുണ്ടോയെന്നു പരിശോധിക്കുന്നു"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"പുതിയ <xliff:g id="NAME">%s</xliff:g> എന്നതിനെ തിരിച്ചറിഞ്ഞു"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> എന്ന സെഷനിലേക്ക് കണക്റ്റുചെയ്തു. നെറ്റ്വർക്ക് മാനേജുചെയ്യാൻ ടാപ്പുചെയ്യുക."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"എല്ലായ്പ്പോഴും ഓണായിരിക്കുന്ന VPN കണക്റ്റുചെയ്യുന്നു…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"എല്ലായ്പ്പോഴും ഓണായിരിക്കുന്ന VPN കണക്റ്റുചെയ്തു"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"\'എല്ലായ്പ്പോഴും ഓണായിരിക്കുന്ന VPN\' വിച്ഛേദിച്ചു"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"എല്ലായ്പ്പോഴും ഓണായിരിക്കുന്ന VPN പിശക്"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"കോൺഫിഗർ ചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക"</string> <string name="upload_file" msgid="2897957172366730416">"ഫയല് തിരഞ്ഞെടുക്കുക"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ഫയലൊന്നും തിരഞ്ഞെടുത്തില്ല"</string> <string name="reset" msgid="2448168080964209908">"പുനഃസജ്ജമാക്കുക"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"ഭാഷയുടെ പേര് ടൈപ്പുചെയ്യുക"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"നിര്ദ്ദേശിച്ചത്"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"എല്ലാ ഭാഷകളും"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"തിരയുക"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"ഔദ്യോഗിക മോഡ് ഓഫാണ്"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"ആപ്സും, പശ്ചാത്തല സമന്വയവും ബന്ധപ്പെട്ട ഫീച്ചറുകളും ഉൾപ്പെടെ, ഔദ്യോഗിക പ്രൊഫൈലിനെ പ്രവർത്തിക്കാൻ അനുവദിക്കുക."</string> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index ac0d24117ddd..1e8c39ca002a 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"нэр дэвшигч"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>-ыг бэлдэж байна"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Алдааг шалгаж байна"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Шинэ <xliff:g id="NAME">%s</xliff:g> илэрлээ"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>-д холбогдов. Сүлжээг удирдах бол товшино уу."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Байнгын VPN-д холбогдож байна..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Байнга VPN холбоотой"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Тогтмол асаалттай VPN салсан"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Байнгын VPN алдаа"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Тохируулахын тулд товшино уу"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Тохируулахын тулд товшино уу"</string> <string name="upload_file" msgid="2897957172366730416">"Файл сонгох"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Сонгосон файл байхгүй"</string> <string name="reset" msgid="2448168080964209908">"Бүгдийг цэвэрлэх"</string> @@ -1645,6 +1645,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Улсын хэлийг бичнэ үү"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Санал болгосон"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Бүх хэл"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Бүх бүс нутаг"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Хайх"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Ажлын горимыг УНТРААСАН байна"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Ажлын профайлд апп, дэвсгэр синхрончлол болон бусад холбоотой тохиргоог ажиллахыг зөвшөөрнө үү."</string> diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml index 2b6abe40f82b..8dc710e75cc5 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"उमेदवार"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करीत आहे"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटींसाठी तपासत आहे"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नवीन <xliff:g id="NAME">%s</xliff:g> आढळले"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> शी कनेक्ट केले. नेटवर्क व्यवस्थापित करण्यासाठी टॅप करा."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN कनेक्ट करणे नेहमी-चालू…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN कनेक्ट केलेले नेहमी-चालू"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"नेहमी-चालू असलेले VPN डिस्कनेक्ट केले"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"VPN त्रुटी नेहमी-चालू"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"कॉन्फिगर करण्यासाठी टॅप करा"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट करण्यासाठी टॅप करा"</string> <string name="upload_file" msgid="2897957172366730416">"फाईल निवडा"</string> <string name="no_file_chosen" msgid="6363648562170759465">"फाईल निवडली नाही"</string> <string name="reset" msgid="2448168080964209908">"रीसेट करा"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"भाषा नाव टाइप करा"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"सूचित केलेले"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"सर्व भाषा"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"सर्व प्रदेश"</string> <string name="locale_search_menu" msgid="2560710726687249178">"शोध"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बंद आहे"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"कार्य प्रोफाइलला अॅप्स, पार्श्वभूमी संकालन आणि संबंधित वैशिष्ट्यांच्या समावेशासह कार्य करण्याची परवानगी द्या."</string> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index b2589e51288e..6050c9acb659 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Ketik untuk memilih bahasa dan susun atur"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Menyediakan <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Menyemak untuk mengesan ralat"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> baharu dikesan"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Bersambung kepada <xliff:g id="SESSION">%s</xliff:g>. Ketik untuk mengurus rangkaian."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sentiasa hidup sedang disambungkan..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sentiasa hidup telah disambungkan"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sentiasa hidup diputuskan sambungannya"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ralat VPN sentiasa hidup"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Ketik untuk membuat konfigurasi"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ketik untuk menyediakan"</string> <string name="upload_file" msgid="2897957172366730416">"Pilih fail"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Tiada fail dipilih"</string> <string name="reset" msgid="2448168080964209908">"Tetapkan semula"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Taipkan nama bahasa"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Dicadangkan"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Semua bahasa"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Cari"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Mod kerja DIMATIKAN"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Benarkan profil kerja berfungsi, termasuk apl, penyegerakan latar belakang dan ciri yang berkaitan."</string> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index 093914363992..3ed76a91ba20 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ရွေးချယ်ခံမည့်သူ"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ပြင်ဆင်နေသည်"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"အမှားအယွင်းများ စစ်ဆေးနေသည်"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> အသစ်တွေ့ရှိပါသည်"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> သို့ ချိတ်ဆက်ထားသည်။ ကွန်ရက်ကို စီမံခန့်ခွဲရန် တို့ပါ။"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"အမြဲတမ်းဖွင့်ထား VPN ဆက်သွယ်နေစဉ်…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"အမြဲတမ်းဖွင့်ထား VPN ဆက်သွယ်မှုရှိ"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"အမြဲတမ်းဖွင့်ထားရသော VPN ပြတ်တောက်နေသည်"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"အမြဲတမ်းဖွင့်ထား VPN အမှား"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"ပြင်ဆင်သတ်မှတ်ရန် တို့ပါ"</string> <string name="upload_file" msgid="2897957172366730416">"ဖိုင်ရွေးချယ်ရန်"</string> <string name="no_file_chosen" msgid="6363648562170759465">"မည်သည့်ဖိုင်ကိုမှမရွေးပါ"</string> <string name="reset" msgid="2448168080964209908">"ပြန်လည်သတ်မှတ်ရန်"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"ဘာသာစကားအမည် ထည့်ပါ"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"အကြံပြုထားသော"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ဘာသာစကားများအားလုံး"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"ဒေသအားလုံး"</string> <string name="locale_search_menu" msgid="2560710726687249178">"ရှာဖွေရန်"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"အလုပ်မုဒ် ပိတ်ထားသည်"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"အက်ပ်များ၊ နောက်ခံစင့်ခ်လုပ်ခြင်း၊ နှင့်သက်ဆိုင်သည့်အင်္ဂါရပ်များကို ဆောင်ရွက်ရန် အလုပ်ပရိုဖိုင်ကိုခွင့်ပြုပါ။"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index ab837931745f..55b226036844 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trykk for å velge språk og layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string> - <string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Forbereder <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sjekker for feil"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> ble oppdaget"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Koblet til <xliff:g id="SESSION">%s</xliff:g>. Trykk for å administrere nettverket."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Alltid-på VPN kobler til ..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Alltid-på VPN er tilkoblet"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Alltid på-VPN er frakoblet"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alltid-på VPN-feil"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trykk for å konfigurere"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trykk for å konfigurere"</string> <string name="upload_file" msgid="2897957172366730416">"Velg fil"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil er valgt"</string> <string name="reset" msgid="2448168080964209908">"Tilbakestill"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Skriv inn språknavn"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Foreslått"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Alle språk"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Alle områder"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Søk"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Jobbmodus er AV"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Slå på jobbprofilen, inkludert apper, synkronisering i bakgrunnen og relaterte funksjoner."</string> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index 39acf6b006f8..c0d44737b9c1 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -1170,7 +1170,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"उम्मेदवार"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"तयारी गर्दै <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटिहरूको लागि जाँच गर्दै"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"नयाँ <xliff:g id="NAME">%s</xliff:g> भेटियो"</string> @@ -1249,8 +1248,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>सँग जोडिएको। नेटवर्क प्रबन्ध गर्न हान्नुहोस्।"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN जडान सधै जोड्दै…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"सधैँ खुल्ला हुने VPN जोडिएको"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"सधैँ-सक्रिय VPN लाई विच्छेद गरियो"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"सधैँ भरि VPN त्रुटिमा"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"कन्फिगर गर्न ट्याप गर्नुहोस्"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"सेट अप गर्न ट्याप गर्नुहोस्"</string> <string name="upload_file" msgid="2897957172366730416">"फाइल छान्नुहोस्"</string> <string name="no_file_chosen" msgid="6363648562170759465">"कुनै फाइल छानिएको छैन"</string> <string name="reset" msgid="2448168080964209908">"पुनःसेट गर्नु"</string> @@ -1653,6 +1653,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"भाषाको नाम टाइप गर्नुहोस्"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"सुझाव दिइयो"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"सम्पूर्ण भाषाहरू"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"सबै क्षेत्रहरू"</string> <string name="locale_search_menu" msgid="2560710726687249178">"खोज"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"कार्य मोड बन्द छ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"अनुप्रयोग, पृष्ठभूमि सिंक र सम्बन्धित विशेषताहरू सहित, कार्य प्रोफाइललाई कार्य गर्न अनुमति दिनुहोस्।"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 99cc80f8c613..183d8668d575 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tik om een taal en indeling te selecteren"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> voorbereiden"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Controleren op fouten"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nieuwe <xliff:g id="NAME">%s</xliff:g> gedetecteerd"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Verbonden met <xliff:g id="SESSION">%s</xliff:g>. Tik om het netwerk te beheren."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Always-on VPN-verbinding maken…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN-verbinding"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN-verbinding ontkoppeld"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fout met Always-on VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tik om te configureren"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tik om in te stellen"</string> <string name="upload_file" msgid="2897957172366730416">"Bestand kiezen"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Geen bestand geselecteerd"</string> <string name="reset" msgid="2448168080964209908">"Resetten"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Typ een taalnaam"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Voorgesteld"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Alle talen"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Alle regio\'s"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Zoeken"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Werkmodus is UIT"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Functioneren van werkprofiel toestaan, waaronder apps, synchronisatie op de achtergrond en gerelateerde functies."</string> diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml index 59564601c0bc..210ef8b48f85 100644 --- a/core/res/res/values-pa-rIN/strings.xml +++ b/core/res/res/values-pa-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ਉਮੀਦਵਾਰ"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> ਤਿਆਰ ਹੋ ਰਿਹਾ ਹੈ"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"ਤਰੁੱਟੀਆਂ ਦੀ ਜਾਂਚ ਕਰ ਰਿਹਾ ਹੈ"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ਨਵੇਂ <xliff:g id="NAME">%s</xliff:g> ਦਾ ਪਤਾ ਲਗਾਇਆ ਗਿਆ"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ। ਨੈੱਟਵਰਕ ਦੇ ਪ੍ਰਬੰਧਨ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਕਨੈਕਟ ਕੀਤਾ"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ਹਮੇਸ਼ਾ-ਚਾਲੂ VPN ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"ਹਮੇਸ਼ਾਂ-ਚਾਲੂ VPN ਅਸ਼ੁੱਧੀ"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"ਸੰਰੂਪਣ ਲਈ ਟੈਪ ਕਰੋ"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="upload_file" msgid="2897957172366730416">"ਫਾਈਲ ਚੁਣੋ"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ਕੋਈ ਫਾਈਲ ਨਹੀਂ ਚੁਣੀ ਗਈ"</string> <string name="reset" msgid="2448168080964209908">"ਰੀਸੈੱਟ ਕਰੋ"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"ਭਾਸ਼ਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"ਸਾਰੇ ਖੇਤਰ"</string> <string name="locale_search_menu" msgid="2560710726687249178">"ਖੋਜ"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"ਕੰਮ ਮੋਡ ਬੰਦ ਹੈ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"ਐਪਾਂ, ਬੈਕਗ੍ਰਾਊਂਡ ਸਮਕਾਲੀਕਰਨ, ਅਤੇ ਸਬੰਧਿਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋਏ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਨੂੰ ਕੰਮ ਕਰਨ ਦੀ ਮਨਜ਼ੂਰੀ ਦਿਓ।"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 84ee0f8bb7bf..e8167085c8da 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Kliknij, by wybrać język i układ"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Przygotowuję: <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sprawdzanie w poszukiwaniu błędów"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Wykryto nowy nośnik: <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Nawiązano połączenie: <xliff:g id="SESSION">%s</xliff:g>. Dotknij, aby zarządzać siecią."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Łączę ze stałą siecią VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Połączono ze stałą siecią VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rozłączono ze stałą siecią VPN"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Błąd stałej sieci VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Kliknij, by skonfigurować"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Kliknij, by skonfigurować"</string> <string name="upload_file" msgid="2897957172366730416">"Wybierz plik"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nie wybrano pliku"</string> <string name="reset" msgid="2448168080964209908">"Resetuj"</string> @@ -1719,6 +1719,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Wpisz nazwę języka"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerowane"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Wszystkie języki"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Wszystkie kraje"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Szukaj"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Tryb pracy jest WYŁĄCZONY"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Włącz profil do pracy, w tym aplikacje, synchronizację w tle i inne funkcje."</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 67398350bc40..ae8c7e1916ce 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string> <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string> <string name="reset" msgid="2448168080964209908">"Redefinir"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 5e244a9638cb..c8d7e4ed8e4b 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o esquema"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"A preparar o <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"A verificar a presença de erros"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detetado"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"A ligar VPN sempre ativa..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa ligada"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desligada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro da VPN sempre ativa"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tocar para configurar"</string> <string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Não foi selecionado nenhum ficheiro"</string> <string name="reset" msgid="2448168080964209908">"Repor"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Todas as regiões"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir o funcionamento do perfil de trabalho, incluindo as aplicações, a sincronização em segundo plano e as funcionalidades relacionadas."</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 67398350bc40..ae8c7e1916ce 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toque para selecionar o idioma e o layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Preparando <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Procurando erros"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novo <xliff:g id="NAME">%s</xliff:g> detectado"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"VPN sempre ativa desconectada"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Toque para configurar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Toque para configurar"</string> <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string> <string name="reset" msgid="2448168080964209908">"Redefinir"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugeridos"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Todos os idiomas"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Pesquisa"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modo de trabalho DESATIVADO"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permitir que o perfil de trabalho funcione, incluindo apps, sincronização em segundo plano e recursos relacionados"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 042ea6268af3..c3c0d61c7cbb 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1189,7 +1189,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Atingeți pentru a selecta limba și aspectul"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"candidați"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Se pregătește <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Se verifică dacă există erori"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"A fost detectat un nou <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1268,8 +1267,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Apăsați pentru a gestiona rețeaua."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Se efectuează conectarea la rețeaua VPN activată permanent…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Conectat(ă) la rețeaua VPN activată permanent"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rețeaua VPN activată permanent a fost deconectată"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Eroare de rețea VPN activată permanent"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Atingeți ca să configurați"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Atingeți pentru a configura"</string> <string name="upload_file" msgid="2897957172366730416">"Alegeți un fișier"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string> <string name="reset" msgid="2448168080964209908">"Resetați"</string> @@ -1683,6 +1683,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Numele limbii"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugerate"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Toate limbile"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Toate regiunile"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Căutați"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modul de serviciu e DEZACTIVAT"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Permiteți profilului de serviciu să funcționeze, inclusiv aplicațiile, sincronizarea în fundal și funcțiile asociate."</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index bbb1488563bf..5ca96e91c775 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Нажмите, чтобы выбрать язык и раскладку"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Подготовка карты \"<xliff:g id="NAME">%s</xliff:g>\"…"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Поиск ошибок"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Обнаружена новая карта \"<xliff:g id="NAME">%s</xliff:g>\""</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Подключено: \"<xliff:g id="SESSION">%s</xliff:g>\". Нажмите здесь, чтобы изменить настройки сети."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Подключение…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Подключено"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Отключено"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Ошибка"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Нажмите, чтобы настроить."</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Нажмите, чтобы настроить"</string> <string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Не выбран файл"</string> <string name="reset" msgid="2448168080964209908">"Сбросить"</string> @@ -1719,6 +1719,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Введите язык"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Рекомендуемые"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Все языки"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Все регионы"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Поиск"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Рабочий режим отключен"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Включить рабочий профиль: приложения, фоновую синхронизацию и связанные функции."</string> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index 5917d6dc6761..8eabd5b16502 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -1166,7 +1166,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"අපේක්ෂකයන්"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> සූදානම් කරමින්"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"වැරදි සඳහා පරීක්ෂා කරමින්"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"නව <xliff:g id="NAME">%s</xliff:g> අනාවරණය කරන ලදි"</string> @@ -1245,8 +1244,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> වෙත සම්බන්ධිතයි. ජාලය කළමනාකරණය කිරීමට තට්ටු කරන්න."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"සැමවිටම VPN සම්බන්ධ වෙමින්…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"නිරතුරුවම VPN සම්බන්ධ කර ඇත"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"සැමවිට ක්රියාත්මක VPN විසන්ධි කරන ලදී"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"සැමවිට සක්රිය VPN දෝෂය"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"වින්යාස කිරීමට තට්ටු කරන්න"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"පිහිටුවීමට තට්ටු කරන්න"</string> <string name="upload_file" msgid="2897957172366730416">"ගොනුව තෝරන්න"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ගොනුවක් තෝරාගෙන නැත"</string> <string name="reset" msgid="2448168080964209908">"යළි පිහිටුවන්න"</string> @@ -1649,6 +1649,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"භාෂා නම ටයිප් කරන්න"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"යෝජිත"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"සියලු භාෂා"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"සියලු ප්රදේශ"</string> <string name="locale_search_menu" msgid="2560710726687249178">"සෙවීම"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"වැඩ ප්රකාරය ක්රියාවිරහිතයි"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"යෙදුම්, පසුබිම සමමුහුර්ත කිරීම, සහ සම්බන්ධිත විශේෂාංග ඇතුළුව, ක්රියා කිරීමට කාර්යාල පැතිකඩට ඉඩ දෙන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 10a64fe0eb5e..eca85e571add 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Klepnutím vyberte jazyk a rozloženie"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravuje sa úložisko <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Prebieha kontrola chýb"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Bolo zistené nové úložisko <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Pripojené k relácii <xliff:g id="SESSION">%s</xliff:g>. Po klepnutí môžete sieť spravovať."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Pripájanie k vždy zapnutej sieti VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Pripojenie k vždy zapnutej sieti VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Vždy zapnutá sieť VPN bola odpojená"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Chyba vždy zapnutej siete VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Klepnutím spustíte konfiguráciu"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Klepnutím prejdete do Nastavení"</string> <string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nie je vybratý žiadny súbor"</string> <string name="reset" msgid="2448168080964209908">"Obnoviť"</string> @@ -1719,6 +1719,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Zadajte názov jazyka"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Navrhované"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Všetky jazyky"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Všetky regióny"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Vyhľadávanie"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Pracovný režim je VYPNUTÝ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Povoľte fungovanie pracovného profilu vrátane aplikácií, synchronizácie na pozadí a súvisiacich funkcií."</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 28031e1b191b..ee2dd5cd77e4 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dotaknite se, če želite izbrati jezik in postavitev."</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Pripravljanje shrambe <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Iskanje napak"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Zaznana je bila nova shramba <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Povezan z mestom <xliff:g id="SESSION">%s</xliff:g>. Tapnite za upravljanje omrežja."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezovanje v stalno vklopljeno navidezno zasebno omrežje ..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Vzpostavljena povezava v stalno vklopljeno navidezno zasebno omrežje"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Povezava s stalno vklopljenim VPN-jem je prekinjena"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Napaka stalno vklopljenega navideznega zasebnega omrežja"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dotanite se, če želite konfigurirati"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dotaknite se, če želite nastaviti"</string> <string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nobena datoteka ni izbrana"</string> <string name="reset" msgid="2448168080964209908">"Ponastavi"</string> @@ -1719,6 +1719,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Vnesite ime jezika"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Predlagano"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Vsi jeziki"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Išči"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Delovni način IZKLOPLJEN"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Dovoljeno delovanje delovnega profila, vključno z aplikacijami, sinhronizacijo v ozadju in povezanimi funkcijami."</string> diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml index e83f39c6bebd..9f06b12825c7 100644 --- a/core/res/res/values-sq-rAL/strings.xml +++ b/core/res/res/values-sq-rAL/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Trokit për të zgjedhur gjuhën dhe strukturën"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidatë"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Po përgatit <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Po kontrollon për gabime"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"U zbulua karta e re <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Lidhur me <xliff:g id="SESSION">%s</xliff:g>. Trokit për të menaxhuar rrjetin."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Po lidh VPN-në për aktivizim të përhershëm…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN e lidhur në mënyrë të përhershme"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Rrjeti VPN gjithmonë aktiv u shkëput"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Gabimi VPN-je për aktivizimin e përhershëm"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Trokit për të konfiguruar"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Trokit për ta konfiguruar"</string> <string name="upload_file" msgid="2897957172366730416">"Zgjidh skedarin"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Nuk u zgjodh asnjë skedar"</string> <string name="reset" msgid="2448168080964209908">"Rivendos"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Shkruaj emrin e gjuhës"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Sugjeruar"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Të gjitha gjuhët"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Të gjitha rajonet"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Kërko"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Modaliteti i punës është JOAKTIV"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Lejoje profilin e punës të funksionojë, duke përfshirë aplikacionet, sinkronizimin në sfond dhe funksionet e lidhura."</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 5b3986fafba7..6eb2d8d2b7a3 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1189,7 +1189,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Додирните да бисте изабрали језик и распоред"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> се припрема"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Проверава се да ли постоје грешке"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Нови уређај <xliff:g id="NAME">%s</xliff:g> је откривен"</string> @@ -1268,8 +1267,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Повезано са сесијом <xliff:g id="SESSION">%s</xliff:g>. Додирните да бисте управљали мрежом."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Повезивање стално укљученог VPN-а..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Стално укључени VPN је повезан"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Веза са стално укљученим VPN-ом је прекинута"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Грешка стално укљученог VPN-а"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Додирните да бисте конфигурисали"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Додирните да бисте подесили"</string> <string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string> <string name="reset" msgid="2448168080964209908">"Поново постави"</string> @@ -1683,6 +1683,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Унесите назив језика"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Предложени"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Сви језици"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Претражи"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Режим за Work је ИСКЉУЧЕН"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Дозвољава профилу за Work да функционише, укључујући апликације, синхронизацију у позадини и сродне функције."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index b9d724772624..df2bc16b1001 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Tryck om du vill välja språk och layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Förbereder ditt <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Söker efter fel"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Nytt <xliff:g id="NAME">%s</xliff:g> har hittats"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Ansluten till <xliff:g id="SESSION">%s</xliff:g>. Knacka lätt för att hantera nätverket."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ansluter till Always-on VPN ..."</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ansluten till Always-on VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Always-on VPN har kopplats från"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Fel på Always-on VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Tryck om du vill konfigurera"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryck för att konfigurera"</string> <string name="upload_file" msgid="2897957172366730416">"Välj fil"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ingen fil har valts"</string> <string name="reset" msgid="2448168080964209908">"Återställ"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Ange språket"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Förslag"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Alla språk"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Alla regioner"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Söka"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Arbetsläget är inaktiverat"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Tillåt att jobbprofilen är aktiv, inklusive appar, bakgrundssynkronisering och andra tillhörande funktioner."</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 959c04dd29cc..0e7fca16fdcb 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1162,7 +1162,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Gonga ili uchague lugha na muundo"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inaandaa <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Inakagua hitilafu"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"<xliff:g id="NAME">%s</xliff:g> mpya imegunduliwa"</string> @@ -1241,8 +1240,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Imeunganishwa kwa <xliff:g id="SESSION">%s</xliff:g>. Gonga ili kudhibiti mtandao"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kila mara VPN iliyowashwa inaunganishwa…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Kila mara VPN iliyowashwa imeunganishwa"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Iwe imeondoa VPN kila wakati"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Kila mara kuna hitilafu ya VPN iliyowashwa"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Gonga ili uweke mipangilio"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Gonga ili uweke mipangilio"</string> <string name="upload_file" msgid="2897957172366730416">"Chagua faili"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Hakuna faili iliyochaguliwa"</string> <string name="reset" msgid="2448168080964209908">"Weka upya"</string> @@ -1645,6 +1645,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Weka jina la lugha"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Inayopendekezwa"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Lugha zote"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Tafuta"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Hali ya kazi IMEZIMWA"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Ruhusu wasifu wa kazini utumike, ikiwa ni pamoja na programu, usawazishaji wa chini chini na vipengele vinavyohusiana."</string> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index 68c0da9d9679..d7efb64bb7c8 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"கேன்டிடேட்ஸ்"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> தயாராகிறது"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"பிழைகள் உள்ளதா எனப் பார்க்கிறது"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"புதிய <xliff:g id="NAME">%s</xliff:g> கண்டறியப்பட்டது"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> உடன் இணைக்கப்பட்டது. நெட்வொர்க்கை நிர்வகிக்க, தட்டவும்."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"எப்போதும் இயங்கும் VPN உடன் இணைக்கிறது…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"எப்போதும் இயங்கும் VPN இணைக்கப்பட்டது"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"எப்போதும் இயங்கும் VPN துண்டிக்கப்பட்டது"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"எப்போதும் இயங்கும் VPN பிழை"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"உள்ளமைக்க, தட்டவும்"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"அமைக்க, தட்டவும்"</string> <string name="upload_file" msgid="2897957172366730416">"கோப்பைத் தேர்வுசெய்"</string> <string name="no_file_chosen" msgid="6363648562170759465">"எந்தக் கோப்பும் தேர்வுசெய்யப்படவில்லை"</string> <string name="reset" msgid="2448168080964209908">"மீட்டமை"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"மொழி பெயரை உள்ளிடுக"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"பரிந்துரைகள்"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"எல்லா மொழிகளும்"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"எல்லா மண்டலங்களும்"</string> <string name="locale_search_menu" msgid="2560710726687249178">"தேடு"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"பணிப் பயன்முறை முடக்கப்பட்டது"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"செயல்பட, பணி சுயவிவரத்தை அனுமதி. இதில் பயன்பாடுகள், பின்னணி ஒத்திசைவு மற்றும் தொடர்புடைய அம்சங்கள் அடங்கும்."</string> diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml index 4e2a5810df5a..15fb94f99c2f 100644 --- a/core/res/res/values-te-rIN/strings.xml +++ b/core/res/res/values-te-rIN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"భాష మరియు లేఅవుట్ను ఎంచుకోవడానికి నొక్కండి"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"క్యాండిడేట్లు"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g>ని సిద్ధం చేస్తోంది"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"లోపాల కోసం తనిఖీ చేస్తోంది"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"కొత్త <xliff:g id="NAME">%s</xliff:g> గుర్తించబడింది"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>కు కనెక్ట్ చేయబడింది. నెట్వర్క్ను నిర్వహించడానికి నొక్కండి."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ఎల్లప్పుడూ-ఆన్లో ఉండే VPN కనెక్ట్ చేయబడుతోంది…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ఎల్లప్పుడూ-ఆన్లో ఉండే VPN కనెక్ట్ చేయబడింది"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ఎల్లప్పుడూ ఆన్లో ఉండే VPN డిస్కనెక్ట్ చేయబడింది"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"ఎల్లప్పుడూ-ఆన్లో ఉండే VPN లోపం"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"కాన్ఫిగర్ చేయడానికి నొక్కండి"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"సెటప్ చేయడానికి నొక్కండి"</string> <string name="upload_file" msgid="2897957172366730416">"ఫైల్ను ఎంచుకోండి"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ఫైల్ ఎంచుకోబడలేదు"</string> <string name="reset" msgid="2448168080964209908">"రీసెట్ చేయి"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"భాష పేరును టైప్ చేయండి"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"సూచించినవి"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"అన్ని భాషలు"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"అన్ని ప్రాంతాలు"</string> <string name="locale_search_menu" msgid="2560710726687249178">"శోధించు"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"కార్యాలయ మోడ్ ఆఫ్ చేయబడింది"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"అనువర్తనాలు, నేపథ్య సమకాలీకరణ మరియు సంబంధిత లక్షణాలతో సహా కార్యాలయ ప్రొఫైల్ను పని చేయడానికి అనుమతించండి."</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 332e70b70939..5fe5d09cd2b2 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"แตะเพื่อเลือกภาษาและรูปแบบ"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"กำลังเตรียม <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"กำลังตรวจหาข้อผิดพลาด"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"ตรวจพบ <xliff:g id="NAME">%s</xliff:g> ใหม่"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"เชื่อมต่อกับ <xliff:g id="SESSION">%s</xliff:g> แตะเพื่อจัดการเครือข่าย"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"กำลังเชื่อมต่อ VPN แบบเปิดตลอดเวลา…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"เชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ยกเลิกการเชื่อมต่อ VPN แบบเปิดตลอดเวลาแล้ว"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"ข้อผิดพลาดของ VPN แบบเปิดตลอดเวลา"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"แตะเพื่อกำหนดค่า"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"แตะเพื่อตั้งค่า"</string> <string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string> <string name="no_file_chosen" msgid="6363648562170759465">"ไม่ได้เลือกไฟล์ไว้"</string> <string name="reset" msgid="2448168080964209908">"รีเซ็ต"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"พิมพ์ชื่อภาษา"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"แนะนำ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"ทุกภาษา"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"ภูมิภาคทั้งหมด"</string> <string name="locale_search_menu" msgid="2560710726687249178">"ค้นหา"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"โหมดทำงานปิดอยู่"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"อนุญาตให้โปรไฟล์งานทำงานได้ ซึ่งรวมถึงแอป การซิงค์ในพื้นหลัง และคุณลักษณะอื่นที่เกี่ยวข้อง"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 065f7b4cf967..651db3635cd3 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"I-tap upang pumili ng wika at layout"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Inihahanda ang <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Sinusuri para sa mga error"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Na-detect ang bagong <xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Nakakonekta sa <xliff:g id="SESSION">%s</xliff:g>. Tapikin upang pamahalaan ang network."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Kumukonekta ang Always-on VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Nakakonekta ang Always-on VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Hindi nakakonekta ang palaging naka-on na VPN"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Error sa Always-on VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"I-tap upang i-configure"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"I-tap upang i-set up"</string> <string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Walang napiling file"</string> <string name="reset" msgid="2448168080964209908">"I-reset"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"I-type ang wika"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iminumungkahi"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Lahat ng wika"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Lahat ng rehiyon"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Maghanap"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"NAKA-OFF ang work mode"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Payagang gumana ang profile sa trabaho, kasama na ang mga app, pag-sync sa background at mga may kaugnayang feature."</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 5cf25fdbd7f6..9d3de40bd99a 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Dili ve düzeni seçmek için hafifçe dokunun"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> hazırlanıyor"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Hatalar denetleniyor"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yeni <xliff:g id="NAME">%s</xliff:g> algılandı"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> oturumuna bağlı. Ağı yönetmek için hafifçe vurun."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Her zaman açık VPN\'ye bağlanılıyor…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Her zaman açık VPN\'ye bağlanıldı"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Her zaman açık VPN bağlantısı kesildi"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Her zaman açık VPN hatası"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Yapılandırmak için dokunun"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Ayarlamak için dokunun"</string> <string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Seçili dosya yok"</string> <string name="reset" msgid="2448168080964209908">"Sıfırla"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Dil adını yazın"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Önerilen"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Tüm diller"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Ara"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"İş modu KAPALI"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Uygulamalar, arka planda senkronizasyon ve ilgili özellikler dahil olmak üzere iş profilinin çalışmasına izin ver."</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 1f5856d25e82..77eff115efb6 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1214,7 +1214,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Торкніться, щоб вибрати мову та розкладку"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Підготовка пристрою пам’яті <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Виявлення помилок"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Виявлено новий пристрій пам’яті (<xliff:g id="NAME">%s</xliff:g>)"</string> @@ -1293,8 +1292,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Під’єднано до <xliff:g id="SESSION">%s</xliff:g>. Торкніться, щоб керувати мережею."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Під’єднання до постійної мережі VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Під’єднано до постійної мережі VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Постійну мережу VPN від’єднано"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Помилка постійної мережі VPN"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Торкніться, щоб налаштувати"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Торкніться, щоб налаштувати"</string> <string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Не вибрано файл"</string> <string name="reset" msgid="2448168080964209908">"Віднов."</string> @@ -1719,6 +1719,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Введіть назву мови"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Пропоновані"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Усі мови"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Усі регіони"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Пошук"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Робочий профіль ВИМКНЕНО"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Увімкнути робочий профіль, зокрема додатки, фонову синхронізацію та пов’язані функції."</string> diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml index 996a50ba65ad..c35bb1319693 100644 --- a/core/res/res/values-ur-rPK/strings.xml +++ b/core/res/res/values-ur-rPK/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"امیدواران"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> تیار کیا جا رہا ہے"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"خرابیوں کیلئے چیک کیا جا رہا ہے"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"نئے <xliff:g id="NAME">%s</xliff:g> کا پتا چلا"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> سے منسلک ہے۔ نیٹ ورک کا نظم کرنے کیلئے تھپتھپائیں۔"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ہمیشہ آن VPN مربوط ہو رہا ہے…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ہمیشہ آن VPN مربوط ہوگیا"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"ہمیشہ آن VPN غیر منسلک ہو گیا"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"ہمیشہ آن VPN کی خرابی"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"کنفیگر کرنے کیلئے تھپتھپائیں"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"سیٹ اپ کرنے کیلئے تھپتھپائیں"</string> <string name="upload_file" msgid="2897957172366730416">"فائل منتخب کریں"</string> <string name="no_file_chosen" msgid="6363648562170759465">"کوئی فائل منتخب نہیں کی گئی"</string> <string name="reset" msgid="2448168080964209908">"دوبارہ ترتیب دیں"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"زبان کا نام ٹائپ کریں"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"تجویز کردہ"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"سبھی زبانیں"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"تلاش"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"کام موڈ آف ہے"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"دفتری پروفائل کو کام کرنے دیں، بشمول ایپس، پس منظر کی مطابقت پذیری اور متعلقہ خصوصیات۔"</string> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index a12bdadfefb8..835e45ee8102 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Til va sxemani belgilash uchun bosing"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"nomzodlar"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> tayyorlanmoqda"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Xatolar qidirilmoqda"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Yangi <xliff:g id="NAME">%s</xliff:g> kartasi aniqlandi"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> ulandi. Tarmoq sozlamalarini o‘zgartirish uchun bu yerni bosing."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ulanmoqda…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ulandi"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Doimiy VPN o‘chirildi"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Xato"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Sozlash uchun bosing"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Sozlash uchun bosing"</string> <string name="upload_file" msgid="2897957172366730416">"Faylni tanlash"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Hech qanday fayl tanlanmadi"</string> <string name="reset" msgid="2448168080964209908">"Asliga qaytarish"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"Til nomini kiriting"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Taklif etiladi"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Barcha tillar"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"Qidiruv"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Ish rejimi O‘CHIQ"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Ishchi profilini yoqish: ilovalar, fonda sinxronlash va bog‘liq funksiyalar."</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 6984027673a4..4a4c34abbd1c 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Nhấn để chọn ngôn ngữ và bố cục"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Đang chuẩn bị <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Đang kiểm tra lỗi"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Đã phát hiện <xliff:g id="NAME">%s</xliff:g> mới"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Đã kết nối với <xliff:g id="SESSION">%s</xliff:g>. Chạm để quản lý mạng."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Đang kết nối VPN luôn bật…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Đã kết nối VPN luôn bật"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Đã ngắt kết nối VPN luôn bật"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Lỗi VPN luôn bật"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Nhấn để định cấu hình"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Nhấn để thiết lập"</string> <string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Không có tệp nào được chọn"</string> <string name="reset" msgid="2448168080964209908">"Đặt lại"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Nhập tên ngôn ngữ"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Ðược đề xuất"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Tất cả ngôn ngữ"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Tất cả khu vực"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Tìm kiếm"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Chế độ làm việc đang TẮT"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Cho phép hồ sơ công việc hoạt động, bao gồm ứng dụng, đồng bộ hóa trong nền và các tính năng liên quan."</string> diff --git a/core/res/res/values-watch/donottranslate.xml b/core/res/res/values-watch/donottranslate.xml new file mode 100644 index 000000000000..d247ff6f5694 --- /dev/null +++ b/core/res/res/values-watch/donottranslate.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <!-- DO NOT TRANSLATE Spans within this text are applied to style composing regions + within an EditText widget. The text content is ignored and not used. + Note: This is @color/material_deep_teal_200, cannot use @color references here. --> + <string name="candidates_style" translatable="false"><font color="#80cbc4">candidates</font></string> + </resources> diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml index f5735e69347a..a9f6e226510c 100644 --- a/core/res/res/values-watch/styles_material.xml +++ b/core/res/res/values-watch/styles_material.xml @@ -88,9 +88,4 @@ please see styles_device_defaults.xml. <item name="virtualButtonPressedDrawable">?selectableItemBackground</item> <item name="descendantFocusability">blocksDescendants</item> </style> - - <!-- DO NOTE TRANSLATE Spans within this text are applied to style composing regions - within an EditText widget. The text content is ignored and not used. - Note: This is @color/material_deep_teal_200, cannot use @color references here. --> - <string name="candidates_style"><font color="#80cbc4">candidates</font></string> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index d3428b3ccd5e..1bdd065ed058 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"点按即可选择语言和布局"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在准备<xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"检查是否有错误"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"检测到新的<xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"已连接到<xliff:g id="SESSION">%s</xliff:g>。点按即可管理网络。"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在连接到始终开启的 VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已连接到始终开启的 VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"始终开启的 VPN 已断开连接"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"始终开启的 VPN 出现错误"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"点按即可进行配置"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"点按即可进行设置"</string> <string name="upload_file" msgid="2897957172366730416">"选择文件"</string> <string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string> <string name="reset" msgid="2448168080964209908">"重置"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"建议语言"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"所有语言"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"搜索"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已关闭"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"启用工作资料,包括应用、后台同步和相关功能。"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 734a5063ef68..ff4f95ece2ee 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕按即可選取語言和鍵盤配置"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備<xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"已偵測到新<xliff:g id="NAME">%s</xliff:g>"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕按一下即可管理網絡。"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可設定"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕按即可設定"</string> <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string> <string name="no_file_chosen" msgid="6363648562170759465">"未選擇檔案"</string> <string name="reset" msgid="2448168080964209908">"重設"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"輸入語言名稱"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"所有國家/地區"</string> <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"工作模式已關閉"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"允許使用應用程式、背景同步及相關功能的工作設定檔。"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 73ed62c7436c..aedd91bf4e16 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"輕觸即可選取語言和版面配置"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"正在準備「<xliff:g id="NAME">%s</xliff:g>」"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"正在檢查錯誤"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"偵測到新的「<xliff:g id="NAME">%s</xliff:g>」"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕觸一下即可管理網路。"</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在連線至永久連線的 VPN…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已連線至永久連線的 VPN"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"永久連線的 VPN 已中斷連線"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"永久連線的 VPN 發生錯誤"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"輕觸即可進行設定"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"輕觸即可進行設定"</string> <string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string> <string name="no_file_chosen" msgid="6363648562170759465">"未選擇任何檔案"</string> <string name="reset" msgid="2448168080964209908">"重設"</string> @@ -1647,6 +1647,8 @@ <string name="search_language_hint" msgid="7042102592055108574">"請輸入語言名稱"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"建議語言"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"所有語言"</string> + <!-- no translation found for region_picker_section_all (8966316787153001779) --> + <skip /> <string name="locale_search_menu" msgid="2560710726687249178">"搜尋"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Work 模式已關閉"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"啟用 Work 設定檔,包括應用程式、背景同步處理和相關功能。"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 12818fc6d46f..59b6fbe0ba39 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1164,7 +1164,6 @@ <string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Thepha ukuze ukhethe ulimi nesakhiwo"</string> <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string> <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"Ilungiselela i-<xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Ihlolela amaphutha"</string> <string name="ext_media_new_notification_message" msgid="7589986898808506239">"I-<xliff:g id="NAME">%s</xliff:g> entsha itholiwe"</string> @@ -1243,8 +1242,9 @@ <string name="vpn_text_long" msgid="4907843483284977618">"Ixhume ku-<xliff:g id="SESSION">%s</xliff:g>. Thepha ukuphatha inethiwekhi."</string> <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"I-VPN ehlala ikhanya iyaxhuma…"</string> <string name="vpn_lockdown_connected" msgid="8202679674819213931">"I-VPN ehlala ikhanya ixhunyiwe"</string> + <string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Njalo kuvuliwe i-VPN kunqamukile"</string> <string name="vpn_lockdown_error" msgid="6009249814034708175">"Iphutha le-VPN ehlala ikhanya"</string> - <string name="vpn_lockdown_config" msgid="4655589351146766608">"Thinta ukuze umise"</string> + <string name="vpn_lockdown_config" msgid="5099330695245008680">"Thepha ukuze usethe"</string> <string name="upload_file" msgid="2897957172366730416">"Khetha ifayela"</string> <string name="no_file_chosen" msgid="6363648562170759465">"Ayikho ifayela ekhethiwe"</string> <string name="reset" msgid="2448168080964209908">"Setha kabusha"</string> @@ -1647,6 +1647,7 @@ <string name="search_language_hint" msgid="7042102592055108574">"Thayipha igama lolimi"</string> <string name="language_picker_section_suggested" msgid="8414489646861640885">"Okuphakanyisiwe"</string> <string name="language_picker_section_all" msgid="3097279199511617537">"Zonke izilimi"</string> + <string name="region_picker_section_all" msgid="8966316787153001779">"Zonke izifunda"</string> <string name="locale_search_menu" msgid="2560710726687249178">"Sesha"</string> <string name="work_mode_off_title" msgid="8954725060677558855">"Imodi yomsebenzi IVALIWE"</string> <string name="work_mode_off_message" msgid="3286169091278094476">"Vumela iphrofayela yomsebenzi ukuze isebenze, efaka izinhlelo zokusebenza, ukuvumelanisa kwangemuva, nezici ezisondelene."</string> diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml index a864cf384adb..92426c6a9bca 100644 --- a/core/res/res/values/colors_material.xml +++ b/core/res/res/values/colors_material.xml @@ -61,7 +61,10 @@ <color name="secondary_text_default_material_dark">#b3ffffff</color> <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item> - <item name="hint_alpha_material_light" format="float" type="dimen">0.54</item> + <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item> + + <item name="hint_pressed_alpha_material_dark" format="float" type="dimen">0.70</item> + <item name="hint_pressed_alpha_material_light" format="float" type="dimen">0.54</item> <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item> <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 55a87ee202df..004b31f3a3ae 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2540,4 +2540,12 @@ <!-- Verizon requires any SMS that starts with //VZWVVM to be treated as a VVM SMS--> <item>310004,310010,310012,310013,310590,310890,310910,311110,311270,311271,311272,311273,311274,311275,311276,311277,311278,311279,311280,311281,311282,311283,311284,311285,311286,311287,311288,311289,311390,311480,311481,311482,311483,311484,311485,311486,311487,311488,311489;^//VZWVVM.*</item> </string-array> + <!-- This config is holding calling number conversion map - expected to convert to emergency + number. Formats for this config as below: + <item>[dialstring1],[dialstring2],[dialstring3]:[replacement]</item> + + E.g. for Taiwan Type Approval, 110 and 119 should be converted to 112. + <item>110,119:112</item> + --> + <string-array translatable="false" name="config_convert_to_emergency_number_map" /> </resources> diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml index a139529482da..3a1679c19fc8 100644 --- a/core/res/res/values/donottranslate.xml +++ b/core/res/res/values/donottranslate.xml @@ -26,4 +26,7 @@ <string name="icu_abbrev_wday_month_day_no_year">eeeMMMMd</string> <!-- @hide DO NOT TRANSLATE. date formatting pattern for system ui.--> <string name="system_ui_date_pattern">@string/icu_abbrev_wday_month_day_no_year</string> + <!-- @hide DO NOT TRANSLATE Spans within this text are applied to style composing regions + within an EditText widget. The text content is ignored and not used. --> + <string name="candidates_style" translatable="false"><u>candidates</u></string> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 624d547c4751..d0107e161707 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3122,8 +3122,6 @@ <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string> <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string> - <string name="candidates_style"><u>candidates</u></string> - <!-- External media notification strings --> <skip /> @@ -4359,6 +4357,9 @@ <string name="language_picker_section_suggested">Suggested</string> <!-- List section subheader for the language picker, containing a list of all languages available [CHAR LIMIT=30] --> <string name="language_picker_section_all">All languages</string> + <!-- List section subheader for the region picker, containing a list of all regions supported for the selected language. + Warning: this is a more 'neutral' term for 'country', not for the sub-divisions of a country. [CHAR LIMIT=30] --> + <string name="region_picker_section_all">All regions</string> <!-- Menu item in the locale menu [CHAR LIMIT=30] --> <string name="locale_search_menu">Search</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 538f3bfef228..39127a43f0a3 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2508,6 +2508,7 @@ <java-symbol type="menu" name="language_selection_list" /> <java-symbol type="string" name="country_selection_title" /> <java-symbol type="string" name="language_picker_section_all" /> + <java-symbol type="string" name="region_picker_section_all" /> <java-symbol type="string" name="language_picker_section_suggested" /> <java-symbol type="string" name="language_selection_title" /> <java-symbol type="string" name="search_language_hint" /> @@ -2698,4 +2699,5 @@ <java-symbol type="drawable" name="ic_restart" /> + <java-symbol type="array" name="config_convert_to_emergency_number_map" /> </resources> diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd index f5d23e8b4032..2721c85fb62a 100644 --- a/docs/html/about/dashboards/index.jd +++ b/docs/html/about/dashboards/index.jd @@ -59,7 +59,7 @@ Platform Versions</a>.</p> </div> -<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016. +<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016. <br/>Any versions with less than 0.1% distribution are not shown.</em> </p> @@ -81,7 +81,7 @@ Screens</a>.</p> </div> -<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016. +<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016. <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p> @@ -101,7 +101,7 @@ support for any lower version (for example, support for version 2.0 also implies <img alt="" style="float:right" -src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A46.0%2C42.6%2C11.4&chco=c4df9b%2C6fad0c&cht=p&chs=400x250"> +src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A44.9%2C42.3%2C12.8&chco=c4df9b%2C6fad0c&cht=p&chs=400x250"> <p>To declare which version of OpenGL ES your application requires, you should use the {@code android:glEsVersion} attribute of the <a @@ -119,21 +119,21 @@ uses.</p> </tr> <tr> <td>2.0</td> -<td>46.0%</td> +<td>44.9%</td> </tr> <tr> <td>3.0</td> -<td>42.6%</td> +<td>42.3%</td> </tr> <tr> <td>3.1</td> -<td>11.4%</td> +<td>12.8%</td> </tr> </table> -<p style="clear:both"><em>Data collected during a 7-day period ending on August 1, 2016</em></p> +<p style="clear:both"><em>Data collected during a 7-day period ending on September 5, 2016</em></p> @@ -147,19 +147,19 @@ var SCREEN_DATA = "Large": { "hdpi": "0.5", "ldpi": "0.2", - "mdpi": "4.3", + "mdpi": "4.1", "tvdpi": "2.1", "xhdpi": "0.5" }, "Normal": { - "hdpi": "40.0", - "mdpi": "3.8", - "tvdpi": "0.1", - "xhdpi": "27.3", + "hdpi": "39.5", + "mdpi": "3.5", + "tvdpi": "0.2", + "xhdpi": "28.4", "xxhdpi": "15.5" }, "Small": { - "ldpi": "1.8" + "ldpi": "1.6" }, "Xlarge": { "hdpi": "0.3", @@ -167,8 +167,8 @@ var SCREEN_DATA = "xhdpi": "0.7" } }, - "densitychart": "//chart.googleapis.com/chart?chd=t%3A2.0%2C11.0%2C2.2%2C40.8%2C28.5%2C15.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&cht=p&chs=400x250&chco=c4df9b%2C6fad0c", - "layoutchart": "//chart.googleapis.com/chart?chd=t%3A3.9%2C7.6%2C86.7%2C1.8&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&cht=p&chs=400x250&chco=c4df9b%2C6fad0c" + "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A1.8%2C10.5%2C2.3%2C40.4%2C29.6%2C15.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250", + "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A3.9%2C7.4%2C87.2%2C1.6&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=400x250" } ]; @@ -176,7 +176,7 @@ var SCREEN_DATA = var VERSION_DATA = [ { - "chart": "//chart.googleapis.com/chart?chd=t%3A0.1%2C1.7%2C1.6%2C16.7%2C29.2%2C35.5%2C15.2&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&cht=p&chs=500x250&chco=c4df9b%2C6fad0c", + "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop%7CMarshmallow&chd=t%3A0.1%2C1.5%2C1.4%2C15.6%2C27.7%2C35.0%2C18.7&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&cht=p&chs=500x250", "data": [ { "api": 8, @@ -186,47 +186,47 @@ var VERSION_DATA = { "api": 10, "name": "Gingerbread", - "perc": "1.7" + "perc": "1.5" }, { "api": 15, "name": "Ice Cream Sandwich", - "perc": "1.6" + "perc": "1.4" }, { "api": 16, "name": "Jelly Bean", - "perc": "6.0" + "perc": "5.6" }, { "api": 17, "name": "Jelly Bean", - "perc": "8.3" + "perc": "7.7" }, { "api": 18, "name": "Jelly Bean", - "perc": "2.4" + "perc": "2.3" }, { "api": 19, "name": "KitKat", - "perc": "29.2" + "perc": "27.7" }, { "api": 21, "name": "Lollipop", - "perc": "14.1" + "perc": "13.1" }, { "api": 22, "name": "Lollipop", - "perc": "21.4" + "perc": "21.9" }, { "api": 23, "name": "Marshmallow", - "perc": "15.2" + "perc": "18.7" } ] } diff --git a/docs/html/guide/topics/location/strategies.jd b/docs/html/guide/topics/location/strategies.jd index 2dfed2ce6e8e..eb436d0138a4 100755 --- a/docs/html/guide/topics/location/strategies.jd +++ b/docs/html/guide/topics/location/strategies.jd @@ -133,36 +133,66 @@ notifications and the third is the minimum change in distance between notificati both to zero requests location notifications as frequently as possible. The last parameter is your {@link android.location.LocationListener}, which receives callbacks for location updates.</p> -<p>To request location updates from the GPS provider, -substitute <code>GPS_PROVIDER</code> for <code>NETWORK_PROVIDER</code>. You can also request -location updates from both the GPS and the Network Location Provider by calling {@link -android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} twice—once -for <code>NETWORK_PROVIDER</code> and once for <code>GPS_PROVIDER</code>.</p> +<p>To request location updates from the GPS provider, use {@link +android.location.LocationManager#GPS_PROVIDER} instead of {@link +android.location.LocationManager#NETWORK_PROVIDER}. You can also request +location updates from both the GPS and the Network Location Provider by calling +{@link android.location.LocationManager#requestLocationUpdates +requestLocationUpdates()} twice—once for {@link +android.location.LocationManager#NETWORK_PROVIDER} and once for {@link +android.location.LocationManager#GPS_PROVIDER}.</p> <h3 id="Permission">Requesting User Permissions</h3> -<p>In order to receive location updates from <code>NETWORK_PROVIDER</code> or -<code>GPS_PROVIDER</code>, you must request user permission by declaring either the {@code -ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permission, respectively, in your Android -manifest file. For example:</p> +<p> + In order to receive location updates from {@link + android.location.LocationManager#NETWORK_PROVIDER} or {@link + android.location.LocationManager#GPS_PROVIDER}, you must request the user's + permission by declaring either the {@code ACCESS_COARSE_LOCATION} or {@code + ACCESS_FINE_LOCATION} permission, respectively, in your Android manifest file. + Without these permissions, your application will fail at runtime when + requesting location updates. +</p> + +<p> + If you are using both {@link + android.location.LocationManager#NETWORK_PROVIDER} and {@link + android.location.LocationManager#GPS_PROVIDER}, then you need to request only + the {@code ACCESS_FINE_LOCATION} permission, because it includes permission + for both providers. (Permission for {@code ACCESS_COARSE_LOCATION} includes + permission only for {@link + android.location.LocationManager#NETWORK_PROVIDER}.) +</p> + +<p class="note"> + <strong>Note:</strong> If your app targets Android 5.0 (API level 21) or + higher, you must also declare that your app uses the + <code>android.hardware.location.network</code> or + <code>android.hardware.location.gps</code> hardware feature in the manifest + file, depending on whether your app receives location updates from {@link + android.location.LocationManager#NETWORK_PROVIDER} or from {@link + android.location.LocationManager#GPS_PROVIDER}. If your app receives location + information from both of these providers, you need to declare that the app + uses both <code>android.hardware.location.network</code> and + <code>android.hardware.location.gps</code>. +</p> +<p> + The following code sample demonstrates how to declare the permission and + hardware feature in the manifest file of an app that reads data from the + device's GPS: +</p> <pre> <manifest ... > <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ... + <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> + <uses-feature android:name="android.hardware.location.gps" /> + ... </manifest> </pre> -<p>Without these permissions, your application will fail at runtime when requesting -location updates.</p> - -<p class="note"><strong>Note:</strong> If you are using both <code>NETWORK_PROVIDER</code> and -<code>GPS_PROVIDER</code>, then you need to request only the {@code ACCESS_FINE_LOCATION} -permission, because it includes permission for both providers. (Permission for {@code -ACCESS_COARSE_LOCATION} includes permission only for <code>NETWORK_PROVIDER</code>.)</p> - - <h2 id="BestPerformance">Defining a Model for the Best Performance</h2> <p>Location-based applications are now commonplace, but due to the less than optimal @@ -404,9 +434,10 @@ don't have a device, you can still test your location-based features by mocking the Android emulator. There are three different ways to send your application mock location data: using Android Studio, DDMS, or the "geo" command in the emulator console.</p> -<p class="note"><strong>Note:</strong> Providing mock location data is injected as GPS location -data, so you must request location updates from <code>GPS_PROVIDER</code> in order for mock location -data to work.</p> +<p class="note"><strong>Note:</strong> Providing mock location data is injected +as GPS location data, so you must request location updates from {@link +android.location.LocationManager#GPS_PROVIDER} in order for mock location data +to work.</p> <h3 id="MockAVD">Using Android Studio</h3> diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd index 9b32244b736f..aaa5867cf4f5 100755 --- a/docs/html/guide/topics/manifest/uses-feature-element.jd +++ b/docs/html/guide/topics/manifest/uses-feature-element.jd @@ -1666,6 +1666,15 @@ densities: '160' <pre><uses-feature android:name="android.hardware.camera" android:required="false" /></pre> +<p class="note"> + <strong>Note:</strong> If your app targets Android 5.0 (API level 21) or + higher and uses the <code>ACCESS_COARSE_LOCATION</code> or + <code>ACCESS_FINE_LOCATION</code> permission in order to receive location + updates from the network or a GPS, respectively, you must also explicitly + declare that your app uses the <code>android.hardware.location.network</code> + or <code>android.hardware.location.gps</code> hardware feature, respectively. +</p> + <p class="table-caption" id="permissions-features"> <strong>Table 2. </strong>Device permissions that imply device hardware use. </p> @@ -1717,14 +1726,29 @@ densities: '160' </tr> <tr> <td><code>ACCESS_COARSE_LOCATION</code></td> - <td><code>android.hardware.location.network</code> <em>and</em> -<br><code>android.hardware.location</code></td> + <td> + <p> + <code>android.hardware.location</code> + </p> + <p> + <code>android.hardware.location.network</code> (Target API level 20 or + lower only.) + </p> + </td> <!-- <td></td> --> </tr> <tr> <td><code>ACCESS_FINE_LOCATION</code></td> - <td><code>android.hardware.location.gps</code> <em>and</em> -<br><code>android.hardware.location</code></td> + <td> + <p> + <code>android.hardware.location</code> + </p> + <p> + <code>android.hardware.location.gps</code> (Target API level 20 or lower + only.) + </p> + </td> + <!-- <td></td> --> </tr> diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd index 4995a13dda91..fcf1ab1fc9db 100644 --- a/docs/html/guide/topics/media/camera.jd +++ b/docs/html/guide/topics/media/camera.jd @@ -154,10 +154,16 @@ application must request the audio capture permission. <uses-permission android:name="android.permission.RECORD_AUDIO" /> </pre> </li> - <li><strong>Location Permission</strong> - If your application tags images with GPS location -information, you must request location permission: + <li> + <p><strong>Location Permission</strong> - If your application tags images + with GPS location information, you must request the "fine location" + permission. Note that, if your app targets Android 5.0 (API level 21) or + higher, you also need to declare that your app uses the device's GPS:</p> <pre> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> +... +<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. --> +<uses-feature android:name="android.hardware.location.gps" /> </pre> <p>For more information about getting user location, see <a href="{@docRoot}guide/topics/location/strategies.html">Location Strategies</a>.</p> diff --git a/docs/html/images/training/ctl-config.png b/docs/html/images/training/ctl-config.png Binary files differindex 82f63c85274d..3a4f7385183c 100644 --- a/docs/html/images/training/ctl-config.png +++ b/docs/html/images/training/ctl-config.png diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js index dfc30c35337a..f3469b4f4ec1 100644 --- a/docs/html/jd_extras_en.js +++ b/docs/html/jd_extras_en.js @@ -156,6 +156,16 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "lang":"en" }, { + "title":"GPU Debugger", + "summary":"Use the GPU Debugger to analyze and debug your OpenGL ES apps. Inspect the GPU state and understand what caused a specific rendering outcome.", + "url":"studio/debug/am-gpu-debugger.html", + "image":"images/tools/thumbnails/am-gpu-debugger_2-2_2x.png", + "type":"tools", + "keywords": ["android","performance","profiling","tools","monitor","debug"], + "tags": ["android","performance","profiling","tools","monitor","debug"], + "lang":"en" + }, + { "title":"HPROF Viewer and Analyzer", "summary":"Use the Memory Monitor to dump the Java heap to an HPROF file. The HPROF Viewer displays classes, instances of each class, and a reference tree to help you track memory usage and find memory leaks.", "url":"studio/profile/am-hprof.html", @@ -5453,6 +5463,12 @@ METADATA['en'].collections = { "studio/profile/am-sysinfo.html" ] }, +"tools/help/gpu": { + "title": "", + "resources": [ + "studio/debug/am-gpu-debugger.html" + ] + }, "tools/help/shot": { "title": "", "resources": [ diff --git a/docs/html/topic/libraries/data-binding/index.jd b/docs/html/topic/libraries/data-binding/index.jd index ddcc9f2e7ea8..0faa1db1bf60 100644 --- a/docs/html/topic/libraries/data-binding/index.jd +++ b/docs/html/topic/libraries/data-binding/index.jd @@ -162,7 +162,9 @@ page.tags="databinding", "layouts" <p> To use data binding, Android Plugin for Gradle <strong>1.5.0-alpha1</strong> - or higher is required. + or higher is required. See how to <a +href="/studio/releases/gradle-plugin.html#updating-plugin">update the Android +Plugin for Gradle</a>. </p> <h2 id="build_environment"> diff --git a/docs/html/topic/libraries/support-library/features.jd b/docs/html/topic/libraries/support-library/features.jd index 614392e00d44..b5f189a0886e 100755 --- a/docs/html/topic/libraries/support-library/features.jd +++ b/docs/html/topic/libraries/support-library/features.jd @@ -108,7 +108,7 @@ page.title=Support Library Features <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:support-compat:24.2.0 +com.android.support:support-compat:24.2.1 </pre> <h3 id="v4-core-utils">v4 core-utils library</h3> @@ -124,7 +124,7 @@ com.android.support:support-compat:24.2.0 </p> <pre> -com.android.support:support-core-utils:24.2.0 +com.android.support:support-core-utils:24.2.1 </pre> <h3 id="v4-core-ui">v4 core-ui library</h3> @@ -141,7 +141,7 @@ com.android.support:support-core-utils:24.2.0 </p> <pre> -com.android.support:support-core-ui:24.2.0 +com.android.support:support-core-ui:24.2.1 </pre> <h3 id="v4-media-compat">v4 media-compat library</h3> @@ -158,7 +158,7 @@ com.android.support:support-core-ui:24.2.0 </p> <pre> -com.android.support:support-media-compat:24.2.0 +com.android.support:support-media-compat:24.2.1 </pre> <h3 id="v4-fragment">v4 fragment library</h3> @@ -178,7 +178,7 @@ com.android.support:support-media-compat:24.2.0 </p> <pre> -com.android.support:support-fragment:24.2.0 +com.android.support:support-fragment:24.2.1 </pre> <h2 id="multidex">Multidex Support Library</h2> @@ -245,7 +245,7 @@ com.android.support:multidex:1.0.0 <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:appcompat-v7:24.2.0 +com.android.support:appcompat-v7:24.2.1 </pre> @@ -260,7 +260,7 @@ implementations, and are used extensively in layouts for TV apps.</p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:cardview-v7:24.2.0 +com.android.support:cardview-v7:24.2.1 </pre> @@ -276,7 +276,7 @@ For detailed information about the v7 gridlayout library APIs, see the <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:gridlayout-v7:24.2.0 +com.android.support:gridlayout-v7:24.2.1 </pre> @@ -299,7 +299,7 @@ reference.</p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:mediarouter-v7:24.2.0 +com.android.support:mediarouter-v7:24.2.1 </pre> <p class="caution">The v7 mediarouter library APIs introduced in Support Library @@ -319,7 +319,7 @@ title card.</p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:palette-v7:24.2.0 +com.android.support:palette-v7:24.2.1 </pre> @@ -335,7 +335,7 @@ limited window of data items.</p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:recyclerview-v7:24.2.0 +com.android.support:recyclerview-v7:24.2.1 </pre> @@ -358,7 +358,7 @@ such as {@link android.support.v7.preference.CheckBoxPreference} and <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:preference-v7:24.2.0 +com.android.support:preference-v7:24.2.1 </pre> <h2 id="v8">v8 Support Library</h2> @@ -409,7 +409,7 @@ defaultConfig { <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:support-v13:24.2.0 +com.android.support:support-v13:24.2.1 </pre> @@ -435,7 +435,7 @@ for preference interfaces such as <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:preference-v14:24.2.0 +com.android.support:preference-v14:24.2.1 </pre> @@ -458,7 +458,7 @@ interface and classes, such as <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:preference-leanback-v17:24.2.0 +com.android.support:preference-leanback-v17:24.2.1 </pre> @@ -494,7 +494,7 @@ com.android.support:preference-leanback-v17:24.2.0 <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:leanback-v17:24.2.0 +com.android.support:leanback-v17:24.2.1 </pre> @@ -509,7 +509,7 @@ package provides APIs to support adding annotation metadata to your apps. </p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:support-annotations:24.2.0 +com.android.support:support-annotations:24.2.1 </pre> @@ -527,7 +527,7 @@ snackbars, and <a href="{@docRoot}design/building-blocks/tabs.html">tabs</a>. < <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:design:24.2.0 +com.android.support:design:24.2.1 </pre> @@ -548,7 +548,7 @@ Callback</a>. </p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:customtabs:24.2.0 +com.android.support:customtabs:24.2.1 </pre> @@ -572,7 +572,7 @@ PercentRelativeLayout</a>. </p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:percent:24.2.0 +com.android.support:percent:24.2.1 </pre> @@ -595,5 +595,5 @@ RecommendationExtender</a>. </p> <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:recommendation:24.2.0 +com.android.support:recommendation:24.2.1 </pre> diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd index 4b743d5d5b91..9a24d1540e9b 100644 --- a/docs/html/topic/libraries/support-library/revisions.jd +++ b/docs/html/topic/libraries/support-library/revisions.jd @@ -6,9 +6,71 @@ page.metaDescription=This page provides details about the Support Library packag <p>This page provides details about the Support Library package releases.</p> <div class="toggle-content opened"> - <p id="rev24-2-0"> + <p id="rev24-2-1"> <a href="#" onclick="return toggleContent(this)"><img src= "{@docRoot}assets/images/styles/disclosure_up.png" class= + "toggle-content-img" alt="">Android Support Library, revision 24.2.1</a> + <em>(September 2016)</em> + </p> + + <div class="toggle-content-toggleme"> + + <p>Fixed issues:</p> + +<ul> + <li>{@link android.support.design.widget.FloatingActionButton} can no longer + be anchored to indirect children of {@link + android.support.design.widget.CoordinatorLayout}. (AOSP issue <a href= + "https://code.google.com/p/android/issues/detail?id=220250">220250</a>) + </li> + + <li>Image inside {@link + android.support.design.widget.CollapsingToolbarLayout} doesn’t scale properly + with <code>fitsSystemWindows=true</code>. (AOSP issue <a href= + "https://code.google.com/p/android/issues/detail?id=220389">220389</a>) + </li> + + <li>{@link android.support.design.widget.CoordinatorLayout} throws {@link + java.lang.IndexOutOfBoundsException} when {@link + android.support.design.widget.Snackbar} is shown and dismissed. (AOSP issue + <a href="https://code.google.com/p/android/issues/detail?id=220762" + >220762</a>) + </li> + + <li>{@link android.support.design.widget.TextInputLayout} fails to resolve + error text color. (AOSP issue <a href= + "https://code.google.com/p/android/issues/detail?id=220305">220305</a>) + </li> + + <li>{@link android.support.v7.util.SortedList.BatchedCallback#onMoved + BatchedCallback.onMoved()} calls {@link + android.support.v7.util.SortedList.BatchedCallback#onInserted + BatchedCallback.onInserted()}. (AOSP issue <a href= + "https://code.google.com/p/android/issues/detail?id=220309">220309</a>) + </li> + + <li>{@link android.support.design.widget.TextInputLayout} overrides right + compound drawable. (AOSP issue <a href= + "https://code.google.com/p/android/issues/detail?id=220728">220728</a>) + </li> +</ul> + +<p> + A complete list of public bug fixes is available on the <a href= + "https://code.google.com/p/android/issues/list?can=1&q=label%3ATarget-Support-24.2.1"> + AOSP Issue Tracker</a>. +</p> + + + </div> +</div> + +<!-- end of collapsible section: 24.2.1 --> + +<div class="toggle-content closed"> + <p id="rev24-2-0"> + <a href="#" onclick="return toggleContent(this)"><img src= + "{@docRoot}assets/images/styles/disclosure_down.png" class= "toggle-content-img" alt="">Android Support Library, revision 24.2.0</a> <em>(August 2016)</em> </p> @@ -2912,8 +2974,6 @@ if (animator instanceof SimpleItemAnimator) { <ul> <li>Added {@link android.support.v7.widget.GridLayout} to provide support for the {@link android.widget.GridLayout} layout object.</li> - <li>Added {@link android.support.v7.widget.Space} which can be used to create blank areas - within a {@link android.support.v7.widget.GridLayout} layout object.</li> </ul> </dl> </div> diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml index 891574fbc6ca..ef6b27666c23 100644 --- a/docs/html/training/_book.yaml +++ b/docs/html/training/_book.yaml @@ -898,6 +898,11 @@ toc: value: 順応性のある UI フローの実装 - name: zh-cn-lang value: 实施自适应用户界面流程 + - title: Build a Responsive UI with ConstraintLayout + path: /training/constraint-layout/index.html + path_attributes: + - name: description + value: How to build a layout using ConstraintLayout and the Android Studio Layout Editor. - title: Adding the App Bar path: /training/appbar/index.html path_attributes: diff --git a/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png Binary files differnew file mode 100644 index 000000000000..1e4867e6513a --- /dev/null +++ b/docs/html/training/constraint-layout/images/alignment-constraint-offset_2x.png diff --git a/docs/html/training/constraint-layout/images/alignment-constraint_2x.png b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png Binary files differnew file mode 100644 index 000000000000..afe7d4aed282 --- /dev/null +++ b/docs/html/training/constraint-layout/images/alignment-constraint_2x.png diff --git a/docs/html/training/constraint-layout/images/baseline-constraint_2x.png b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png Binary files differnew file mode 100644 index 000000000000..dfc35226fdb5 --- /dev/null +++ b/docs/html/training/constraint-layout/images/baseline-constraint_2x.png diff --git a/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png Binary files differnew file mode 100644 index 000000000000..be9d54f4fbf5 --- /dev/null +++ b/docs/html/training/constraint-layout/images/constraint-fail-fixed_2x.png diff --git a/docs/html/training/constraint-layout/images/constraint-fail_2x.png b/docs/html/training/constraint-layout/images/constraint-fail_2x.png Binary files differnew file mode 100644 index 000000000000..3f28ef7906ab --- /dev/null +++ b/docs/html/training/constraint-layout/images/constraint-fail_2x.png diff --git a/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png Binary files differnew file mode 100644 index 000000000000..ace31a6105d9 --- /dev/null +++ b/docs/html/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png diff --git a/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png Binary files differnew file mode 100644 index 000000000000..07680227fbb7 --- /dev/null +++ b/docs/html/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png diff --git a/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png Binary files differnew file mode 100644 index 000000000000..b4ffb2cd946a --- /dev/null +++ b/docs/html/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png diff --git a/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png Binary files differnew file mode 100644 index 000000000000..72a4e401a05c --- /dev/null +++ b/docs/html/training/constraint-layout/images/layout-editor_2-2_2x.png diff --git a/docs/html/training/constraint-layout/images/parent-constraint_2x.png b/docs/html/training/constraint-layout/images/parent-constraint_2x.png Binary files differnew file mode 100644 index 000000000000..0414f1d5b34b --- /dev/null +++ b/docs/html/training/constraint-layout/images/parent-constraint_2x.png diff --git a/docs/html/training/constraint-layout/images/position-constraint_2x.png b/docs/html/training/constraint-layout/images/position-constraint_2x.png Binary files differnew file mode 100644 index 000000000000..9f93e72dcd4d --- /dev/null +++ b/docs/html/training/constraint-layout/images/position-constraint_2x.png diff --git a/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png Binary files differnew file mode 100644 index 000000000000..f863e5f99bd1 --- /dev/null +++ b/docs/html/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png diff --git a/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png Binary files differnew file mode 100644 index 000000000000..d61e9b2354f1 --- /dev/null +++ b/docs/html/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png Binary files differnew file mode 100644 index 000000000000..97471025b007 --- /dev/null +++ b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-first.png diff --git a/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png Binary files differnew file mode 100644 index 000000000000..940b84955278 --- /dev/null +++ b/docs/html/training/constraint-layout/images/thumbnail-studio-constraint-second.png diff --git a/docs/html/training/constraint-layout/index.html b/docs/html/training/constraint-layout/index.html new file mode 100644 index 000000000000..62eaf15f62a7 --- /dev/null +++ b/docs/html/training/constraint-layout/index.html @@ -0,0 +1,498 @@ +<html devsite> +<head> + <title>Build a Responsive UI with ConstraintLayout</title> + <meta name="book_path" value="/training/_book.yaml" /> + <meta name="top_category" value="develop" /> + <meta name="subcategory" value="training" /> +</head> +<body> + +<div id="tb-wrapper"> +<div id="tb"> + <h2>In this document</h2> + <ol> + <li><a href="#constraints-overview">Constraints overview</a></li> + <li><a href="#add-constraintlayout-to-your-project">Add ConstraintLayout to your project</a></li> + <li><a href="#add-a-constraint">Add a constraint</a></li> + <li><a href="#use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</a></li> + <li><a href="#adjust-the-view-size">Adjust the view size</a></li> + <li><a href="#adjust-the-constraint-bias">Adjust the constraint bias</a></li> + <li><a href="#adjust-the-view-margins">Adjust the view margins</a></li> + </ol> +</div> +</div> + + +<p><code>ConstraintLayout</code> allows you to create large and complex layouts with a flat view +hierarchy (no nested view groups). It's similar to <code>RelativeLayout</code> in that all views are +layed out according to relationships between sibling views and the parent layout, but it's more +flexible than <code>RelativeLayout</code> and easier to use with Android Studio's Layout Editor. +</p> + +<p>Everything you can do with <code>ConstraintLayout</code> is available directly from the Layout Editor's visual +tools, because the layout API and the Layout Editor were specially built for each other. So you can +build your layout with <code>ConstraintLayout</code> entirely by drag-and-dropping instead of editing the XML. +</p> + +<img src="/training/constraint-layout/images/layout-editor_2-2_2x.png" alt="" + width="640"/> +<p class="img-caption"><b>Figure 1.</b> A <code>ConstraintLayout</code> in the Layout Editor</p> + + +<p> +<code>ConstraintLayout</code> is available in an API library that's compatible with Android +2.3 (API level 9) and higher, and the new layout editor is available in Android +Studio 2.2 and higher. +</p> + +<p> +This page provides a guide to building a layout with <code>ConstraintLayout</code> in Android +Studio. If you'd like more information about the Layout Editor itself, see the +Android Studio guide to <a href="/studio/write/layout-editor.html">Build a UI with +Layout Editor</a>. +</p> + + +<h2 id="constraints-overview">Constraints overview</h2> +<p> +To define a view's position in <code>ConstraintLayout</code>, you must add two +or more <em>constraints</em> for the view. Each constraint represents a connection or +alignment to another view, the parent layout, or an invisible guideline. Each +constraint defines the view's position along either the +vertical or horizontal axis; so each view must have a minimum of one constraint for each +axis, but often more are necessary. +</p> + +<p> +When you drop a view into the Layout Editor, it stays where you leave it even if +it has no constraints. However, this is only to make editing easier; if a view has +no constraints when you run your layout on a device, it is drawn at +position [0,0] (the top-left corner).</p> + +<p>In figure 2, the layout looks good in the +editor, but there's no vertical constraint on <code>TextView B</code>. When this +layout draws on a device, <code>TextView B</code> horizontally aligns with the left and +right edges of the <code>ImageView</code>, but appears at the top of the screen because +it has no vertical constraint. +</p> + +<div class="cols"> +<div class="col-1of2"> +<img src="/training/constraint-layout/images/constraint-fail_2x.png" width="100%" alt="" /> +<p class="img-caption"><strong>Figure 2.</strong> <code>TextView B</code> is missing a +vertical constraint</p> +</div> +<div class="col-1of2"> +<img src="/training/constraint-layout/images/constraint-fail-fixed_2x.png" width="100%" alt="" /> +<p class="img-caption"><strong>Figure 3.</strong> <code>TextView B</code> is now vertically +constrained to the <code>ImageView</code></p> +</div> +</div> + +<p> +Although a missing constraint won't cause a compilation error, the Layout Editor +indicates missing constraints as an error in the toolbar. To view the errors and +other warnings, click <strong>Show Warnings and Errors</strong> +<img src="/studio/images/buttons/layout-editor-errors.png" class="inline-icon" alt="" />. +To help you avoid missing constraints, the Layout Editor can automatically add +constraints for you with the <a +href="#use-autoconnect-and-infer-constraints">Autoconnect and infer +constraints</a> features. +</p> + + +<h2 id="add-constraintlayout-to-your-project">Add ConstraintLayout to your project</h2> +<p> +To use <code>ConstraintLayout</code> in your project, proceed as follows: +</p> + +<ol> +<li>Ensure you have the latest Constraint Layout library: +<ol> + <li>Click <strong>Tools > Android > SDK Manager</strong>. + <li>Click the <strong>SDK Tools</strong> tab. + <li>Expand <strong>Support Repository</strong> and then check +<b>ConstraintLayout for Android</b> and <b>Solver for ConstraintLayout</b>. +Check <b>Show Package Details</b> and take note of the version you're downloading +(you'll need this below).</p> + <li>Click <strong>OK</strong>. +<li>Add the ConstraintLayout library as a dependency in your module-level + <code>build.gradle</code> file: +<pre> +dependencies { + compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8' +} +</pre> + <p>The library version you download may be higher, so be sure the value you specify + here matches the version from step 3.</p> +</li> +<li>In the toolbar or sync notification, click <strong>Sync Project with Gradle +Files</strong>.</li> +</ol> +</li> +</ol> + +<p>Now you're ready to build your layout with <code>ConstraintLayout</code>.</p> + +<h3 id="convert">Convert a layout</h3> + +<div class="figure" style="width:415px"> +<img src="/training/constraint-layout/images/layout-editor-convert-to-constraint_2x.png" + width="415" alt="" /> +<p class="img-caption"> + <b>Figure 4.</b> The menu to convert a layout to <code>ConstraintLayout</code></p> +</div> + +<p>To convert an existing layout to a constraint layout, follow these steps:</p> +<ol> +<li>Open your layout in Android Studio and click the <strong>Design</strong> tab +at the bottom of the editor window. +<li>In the <strong>Component Tree</strong> window, right-click the layout and +click <strong>Convert <em>layout</em> to ConstraintLayout</strong>.</li> +</ol> + +<h3 id="createNew">Create a new layout</h3> + +<p>To start a new constraint layout file, follow these steps:</p> +<ol> +<li>Click anywhere in the <strong>Project</strong> window and then select +<strong>File > New > XML > Layout XML</strong>. +<li>Enter a name for the layout file and enter +"android.support.constraint.ConstraintLayout" for the <b>Root Tag</b>. +<li>Click <strong>Finish</strong>.</li> +</ol> + + +<h2 id="add-a-constraint">Add a constraint</h2> + +<p>Start by dragging a view from the <b>Palette</b> window into the editor. +When you add a view in a <code>ConstraintLayout</code>, it displays a bounding box with square +resizing handles on each corner and circular constraint handles on each side. +</p> + + +<div class="figure" style="width:460px"> +<div class="video-wrapper"> +<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-first.png" + onclick="this.play()" width="460"> + <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-first.mp4" type="video/mp4"> + <img src="/training/constraint-layout/images/thumbnail-studio-constraint-first" alt="" /> +</video> +</div> +<p class="img-caption"> +<strong>Video 1. </strong>The left side of a view is constrained to the left side of the parent +</p> +</div> + +<p> +Click the view to select it. Then click-and-hold one of the +constraint handles and drag the line to an available anchor point (the edge of +another view, the edge of the layout, or a guideline). When you release, the +constraint is made, with <a href="#adjust-the-view-margins">a default margin</a> +separating the two views. +</p> + +<p>When creating constraints, remember the following rules:</p> + +<ul> +<li>Every view must have at least two constraints: one horizontal and one +vertical. +<li>You can create constraints only between a constraint handle and an anchor +point that share the same plane. So a vertical plane (the left and right sides) +of a view can be constrained only to another vertical plane; and baselines can +constrain only to other baselines. +<li>Each constraint handle can be used for just one constraint, but you can +create multiple constraints (from different views) to the same anchor +point.</li> +</ul> + + + +<div class="figure" style="width:460px"> +<div class="video-wrapper"> +<video controls poster="/training/constraint-layout/images/thumbnail-studio-constraint-second.png" + onclick="this.play()" width="460"> + <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/studio-constraint-second.mp4" type="video/mp4"> + <img src="/training/constraint-layout/images/thumbnail-studio-constraint-second.png" alt="" /> +</video> +</div> +<p class="img-caption"> +<strong>Video 2. </strong>Adding a constraint that opposes an existing one +</p> +</div> + + + +<p> +To remove a constraint, select the view and then click the constraint handle. +</p> + +<p>If you add opposing constraints on a view, the constraint lines become squiggly +like a spring to indicate the opposing forces, as shown in video 2. The effect +is most visible when the view size is set to "fixed" or "wrap content," in which +case the view is centered between the constraints. If you instead +want the view to stretch its size to meet the constraints, <a +href="#adjust-the-view-size">switch the size to "any size"</a>; or if you want +to keep the current size but move the view so that it is not centered, <a +href="#adjust-the-constraint-bias">adjust the constraint bias</a>. +</p> + + + +<p> +There are many ways to constrain a view, but the following constraint types +provide the basic building blocks. +</p> + + + + +<h3>Parent constraint</h3> +<div class="cols"> +<div class="col-2of3"> + <p> + Connect the side of a view to the corresponding edge of the layout. + <p> + In figure 5, the left side of a view is connected to the left edge of the + parent layout. + <p> +</div> +<div class="col-1of3"> + <img src="/training/constraint-layout/images/parent-constraint_2x.png" width="100%" alt=""> + <p class="img-caption"><strong>Figure 5. </strong>A horizontal constraint to the parent</p> +</div> +</div> + + +<h3>Position constraint</h3> +<div class="cols"> +<div class="col-2of3"> +<p>Define the order of appearance for two views, either vertically or horizontally.</p> +<p>In figure 6, a <code>Button</code> is constrained below an <code>ImageView</code> with a 24dp +margin.</p> +</div> +<div class="col-1of3"> + <img src="/training/constraint-layout/images/position-constraint_2x.png" width="100%" alt=""> + <p class="img-caption"><strong>Figure 6.</strong> A vertical position constraint</p> +</div> +</div> + + + +<h3>Alignment constraint</h3> +<div class="cols"> +<div class="col-1of3"> +<p>Align the edge of a view to the same edge of another view.<p> +<p>In figure 7, the left side of a <code>Button</code> is aligned to the left side of an +<code>ImageView</code>.</p> +<p>You can offset the alignment by dragging the view +inward from the constraint. For example, figure 8 shows the same +<code>Button</code> with a 24dp offset alignment. +The offset is defined by the constrained view's margin.</p> +</div> +<div class="col-1of3"> + <img src="/training/constraint-layout/images/alignment-constraint_2x.png" width="100%" alt=""> + <p class="img-caption"><strong>Figure 7.</strong> A horizontal alignment constraint</p> +</div> +<div class="col-1of3"> + <img src="/training/constraint-layout/images/alignment-constraint-offset_2x.png" width="100%" + alt=""> + <p class="img-caption"><strong>Figure 8.</strong> An offset horizontal alignment constraint</p> +</div> +</div> + + +<h3>Baseline alignment constraint</h3> +<div class="cols"> +<div class="col-2of3"> +<p>Align the text baseline of a view to the text baseline of another view.</p> +<p>In figure 9, the first line of a <code>TextView</code> is aligned with the text in a +<code>Button</code>.</p> +<p>To create a baseline constraint, hover your mouse over the baseline handle for +two seconds until the handle blinks white. Then click and drag the line to +another baseline.</p> +</div> +<div class="col-1of3"> + <img src="/training/constraint-layout/images/baseline-constraint_2x.png" width="100%" alt=""> + <p class="img-caption"><strong>Figure 9.</strong> A baseline alignment constraint</p> +</div> +</div> + + + + + +<h3 id="constrain-to-a-guideline">Constrain to a guideline</h3> +<div class="cols"> +<div class="col-1of2"> + +<p> +You can add a vertical or horizontal guideline to which you can attach +constraints. You can position the guideline within the layout based on either dp +units or percent, relative to the layout's edge. +</p> + +<p> +To create a guideline, click <strong>Guidelines</strong> +<img src="/studio/images/buttons/layout-editor-guidelines.png" class="inline-icon" alt="" /> +in the toolbar, and then click either <strong>Add Vertical Guideline</strong> +or <strong>Add Horizontal Guideline</strong>. +</p> + +<p> +Click the circle at the edge of the guideline to toggle the measurements used to +position the guideline (either percent or dp units from the layout's edge). +</p> + +<p> +Guidelines are not visible to your users. +</p> +</div> + +<div class="col-1of2"> + <div class="video-wrapper"> + <video controls poster="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png" + onclick="this.play()" width="100%"> + <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/add-layout-guideline_2-2.mp4" type="video/mp4"> + <img src="/training/constraint-layout/images/thumbnail-add-layout-guideline_2-2.png" alt="" /> + </video> + </div> + <p class="img-caption"><strong>Video 3.</strong> Adding a constraint to a guideline</p> +</div> +</div> + + +<h2 id="use-autoconnect-and-infer-constraints">Use Autoconnect and Infer Constraints</h2> + +<div class="figure" style="width:460px"> +<div class="video-wrapper"> +<video controls poster="" + onclick="this.play()" width="460"> + <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/constraint-autoconnect_2-2.mp4" type="video/mp4"> +</video> +</div> +<p class="img-caption"><b>Video 4.</b> Adding a view with Autoconnect enabled</p> +</div> + +<p> +Autoconnect is a persistent mode that automatically creates two or more +constraints for each view you add to the layout. Autoconnect is disabled by +default. You can enable it by clicking <strong>Turn on Autoconnect</strong> +<img src="/studio/images/buttons/layout-editor-autoconnect-on.png" class="inline-icon" alt="" /> +in the Layout Editor toolbar. +</p> + +<p>While enabled, Autoconnect creates constraints for each view as you add them; it does not create +constraints for existing views in the layout. If you drag a view once the constraints are made, the +constraints do not change (though the margins do), so you must delete the constraints if you want to +significantly reposition the view.</p> + +<p>Alternatively, you can click <strong>Infer Constraints</strong> +<img src="/studio/images/buttons/layout-editor-infer.png" class="inline-icon" alt="" /> +to create constraints for all views in the layout. +</p> + +<p>Infer Constraints is a one-time action that scans the entire layout to determine the most +effective set of constraints for all views, so it may create constraints between elements that are +far from each other. Autoconnect, however, creates constraints only for the view you are adding, and +it creates constraints to only the nearest elements. In either case, you can always modify a +constraint by clicking the constraint handle to delete it, and then create a new constraint.</p> + + +<h2 id="adjust-the-view-size">Adjust the view size</h2> + +<p> +You can use the handles on each corner of the view to resize it, but doing so +hard codes the width and height values, which you should avoid for most views +because hard-coded view sizes cannot adapt to different content and screen +sizes. To select from one of the dynamic sizing modes or to define more specific +dimensions, click a view and open the <strong>Properties</strong> +<img src="/studio/images/buttons/window-properties.png" class="inline-icon" alt="" /> +window on the right side of the editor. At the top of the window is the view +inspector, as shown in figure 10. +</p> +<div class="figure" style="width:287px" > +<img src="/training/constraint-layout/images/layout-editor-properties-callouts_2-2_2x.png" alt="" + width="287" /> +<p class="img-caption"><strong>Figure 10.</strong> The <b>Properties</b> window includes controls for +<strong>(1)</strong> view size, <strong>(2)</strong> margins, and +<strong>(3)</strong> constraint bias.</p> +</div> + +<p> +The grey square represents the selected view. The symbols inside the square +represent the height and width settings as follows: +</p> + +<ul> +<li> +<img src="/studio/images/buttons/layout-width-wrap.png" class="inline-icon" alt="" /> + <strong>Wrap Content</strong>: The view expands exactly as needed to fit its +contents. +<li> +<img src="/studio/images/buttons/layout-width-match.png" class="inline-icon" alt="" /> + <strong>Any Size</strong>: The view expands exactly as needed to match the +constraints. The actual value is 0dp because the view has no desired dimensions, but +it resizes as needed to meet the constraints. However, if the given dimension +has only one constraint, then the view expands to fit its contents. Another way +to think of it is "match constraints" (instead of <code>match_parent</code>) because it +expands the view as much as possible after accounting for the limits of each +constraint and its margins. +<li> +<img src="/studio/images/buttons/layout-width-fixed.png" class="inline-icon" alt="" /> + <strong>Fixed</strong>: You specify the dimension in the text box below or by +resizing the view in the editor.</li> +</ul> + +<p>To toggle between these settings, click the symbols.</p> + +<p class="note"><strong>Note</strong>: You should not use <code>match_parent</code> for any view +in a <code>ConstraintLayout</code>. Instead use "Any Size" (<code>0dp</code>). +</p> + + +<h2 id="adjust-the-constraint-bias">Adjust the constraint bias</h2> + +<p>When you add a constraint to both sides of a view (and the view size for the same dimension is +either "fixed" or "wrap content"), the view becomes centered between the two anchor points by +default. When a view is centered, the bias is 50%. You can adjust the bias by dragging the bias +slider in the <b>Properties</b> window or by dragging the view, as shown in video 5.</p> + +<div class="video-wrapper" style="max-width:740px"> +<video controls poster="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png" + onclick="this.play();$(this.parentElement).addClass('playing');"> + <source src="https://storage.googleapis.com/androiddevelopers/videos/studio/adjust-constraint-bias.mp4" type="video/mp4"> + <img src="/training/constraint-layout/images/thumbnail-adjust-constraint-bias.png" alt="" /> +</video> +</div> +<p class="img-caption"><b>Video 5.</b> Adjusting the constraint bias</p> + +<p>If you instead want the view to stretch its size to meet the constraints, <a href="#adjust-the- +view-size">switch the size to "any size"</a>.</p> + + +<h2 id="adjust-the-view-margins">Adjust the view margins</h2> + +<p> To ensure that all your views are evenly spaced, click <strong>Margin</strong> <img +src="/studio/images/buttons/layout-editor-margin.png" class="inline-icon" alt="" /> in the toolbar +to select the default margin for each view that you add to the layout. The button changes to show +your current margin selection. Any change you make to the default margin applies only to the views +you add from then on. </p> + + +<img src="/training/constraint-layout/images/layout-editor-margin-callout_2-2_2x.png" + alt="" width="232"/> +<p class="img-caption"><strong>Figure 11.</strong> The toolbar's <b>Margin</b> button. +Click to adjust the default margin. +</p> + +<p> You can control the margin for each view in the <strong>Properties</strong> window by clicking +the number on the line that represents each constraint (in figure 10, the margins are each set to +16dp). </p> + +<p> All margins offered by the tool are factors of 8dp to help your views align to Material Design's +<a href="https://material.google.com/layout/metrics-keylines.html">8dp square grid +recommendations</a>. </p> + +</body> +</html> diff --git a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd index 8fc4dcac25d4..df8b1bc5c9a6 100644 --- a/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd +++ b/docs/html/training/testing/unit-testing/instrumented-unit-tests.jd @@ -292,23 +292,21 @@ from the command line. Test results provide test logs and include the details of any app failures.</p> <p> - Before you can start using Firebase Test Lab, you need to: + Before you can start using Firebase Test Lab, you need to do the following +unless you already have a Google account and a Firebase project with the Blaze +billing plan enabled: </p> <ol> - <li> - <a href="https://console.developers.google.com/freetrial">Create a - Google Cloud Platform account</a> to use with active billing. - </li> - - <li> - <a href="https://support.google.com/cloud/answer/6251787">Create a Google - Cloud project</a> for your app. - </li> - - <li> - <a href="https://support.google.com/cloud/answer/6288653">Set up an active - billing account</a> and associate it with the project you just created. + <li><a href="https://accounts.google.com/">Create a Google account</a>, + if you don't have one already.</li> + <li>In the <a href="https://console.firebase.google.com/">Firebase + console</a>, click <b>Create New Project</b>.</li> + <li>In the Firebase console, click <b>Upgrade</b>, and then click <b>Select +Plan</b> in the <b>Blaze</b> plan column. + <p class="note"><b>Note</b>: To learn about billing, +see <a href="https://firebase.google.com/docs/test-lab/overview#billing">Test +Lab billing</a>.</p> </li> </ol> @@ -318,10 +316,10 @@ Configure a test matrix and run a test </h4> <p> - Android Studio provides integrated tools that allow you to configure how you - want to deploy your tests to Firebase Test Lab. After you have created a Google - Cloud project with active billing, you can create a test configuration and - run your tests: +Android Studio provides integrated tools that allow you to configure how you +want to deploy your tests to Firebase Test Lab. After you have created a +Firebase project with Blaze plan billing, you can create a test configuration +and run your tests: </p> <ol> @@ -329,7 +327,8 @@ Configure a test matrix and run a test the main menu. </li> - <li>Click <strong>Add New Configuration (+)</strong> and select + <li>Click <strong>Add New Configuration</strong> <img +src="/studio/images/buttons/ic_plus.png" alt="" class="inline-icon"/> and select <strong>Android Tests</strong>. </li> @@ -340,7 +339,7 @@ Configure a test matrix and run a test </li> <li>From the <em>Target</em> drop-down menu under <em>Deployment Target - Options</em>, select <strong>Cloud Test Lab Device Matrix</strong>. + Options</em>, select <strong>Firebase Test Lab Device Matrix</strong>. </li> <li>If you are not logged in, click <strong>Connect to Google Cloud @@ -348,9 +347,9 @@ Configure a test matrix and run a test </li> <li>Next to <em>Cloud Project</em>, click the <img src= - "{@docRoot}images/tools/as-wrench.png" alt="wrench and nut" style= - "vertical-align:bottom;margin:0;"> button and select your Google Cloud - Platform project from the list. + "{@docRoot}images/tools/as-wrench.png" alt="" class="inline-icon"/> + button and select your Firebase + project from the list. </li> </ol> </li> @@ -359,7 +358,7 @@ Configure a test matrix and run a test <ol type="a"> <li>Next to the <em>Matrix Configuration</em> drop-down list, click <strong> Open Dialog</strong> <img src="{@docRoot}images/tools/as-launchavdm.png" - alt="ellipses button" style="vertical-align:bottom;margin:0;">. + alt="" class="inline-icon">. </li> <li>Click <strong>Add New Configuration (+)</strong>. @@ -385,8 +384,7 @@ Configure a test matrix and run a test </li> <li>Run your tests by clicking <strong>Run</strong> <img src= - "{@docRoot}images/tools/as-run.png" alt="" style= - "vertical-align:bottom;margin:0;">. + "{@docRoot}images/tools/as-run.png" alt="" class="inline-icon"/>. </li> </ol> @@ -404,7 +402,7 @@ Configure a test matrix and run a test When Firebase Test Lab completes running your tests, the <em>Run</em> window will open to show the results, as shown in figure 2. You may need to click <strong>Show Passed</strong> <img src="{@docRoot}images/tools/as-ok.png" alt= - "" style="vertical-align:bottom;margin:0;"> to see all your executed tests. + "" class="inline-icon"/> to see all your executed tests. </p> <img src="{@docRoot}images/training/ctl-test-results.png" alt=""> @@ -416,15 +414,7 @@ Configure a test matrix and run a test <p> You can also analyze your tests on the web by following the link displayed at - the beginning of the test execution log in the <em>Run</em> window, as shown - in figure 3. -</p> - -<img src="{@docRoot}images/training/ctl-exec-log.png" alt=""> - -<p class="img-caption"> - <strong>Figure 3.</strong> Click the link to view detailed test results on - the web. + the beginning of the test execution log in the <em>Run</em> window. </p> <p> diff --git a/docs/html/training/tv/start/hardware.jd b/docs/html/training/tv/start/hardware.jd index 97cf7ff6626d..063987159b79 100644 --- a/docs/html/training/tv/start/hardware.jd +++ b/docs/html/training/tv/start/hardware.jd @@ -227,13 +227,19 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) </tr> <tr> <td>{@link android.Manifest.permission#ACCESS_COARSE_LOCATION}</td> - <td>{@code android.hardware.location} <em>and</em> <br> - {@code android.hardware.location.network}</td> + <td> + <p>{@code android.hardware.location}</p> + <p>{@code android.hardware.location.network} (Target API level 20 or lower + only.)</p> + </td> </tr> <tr> <td>{@link android.Manifest.permission#ACCESS_FINE_LOCATION}</td> - <td>{@code android.hardware.location} <em>and</em> <br> - {@code android.hardware.location.gps}</td> + <td> + <p>{@code android.hardware.location}</p> + <p>{@code android.hardware.location.gps} (Target API level 20 or lower + only.)</p> + </td> </tr> </table> @@ -246,6 +252,13 @@ if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) required ({@code android:required="false"}). </p> +<p class="note"> + <strong>Note:</strong> If your app targets Android 5.0 (API level 21) or + higher and uses the <code>ACCESS_COARSE_LOCATION</code> or + <code>ACCESS_FINE_LOCATION</code> permission, users can still install your + app on a TV device, even if the TV device doesn't have a network card or a GPS + receiver. +</p> <h3 id="check-features">Checking for hardware features</h2> diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 366ef716c109..74b474eef371 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -3,6 +3,7 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk HWUI_NEW_OPS := true +BUGREPORT_FONT_CACHE_USAGE := true # Enables fine-grained GLES error checking # If set to true, every GLES call is wrapped & error checked @@ -135,6 +136,13 @@ ifeq (true, $(HWUI_NEW_OPS)) endif +ifeq (true, $(BUGREPORT_FONT_CACHE_USAGE)) + hwui_src_files += \ + font/FontCacheHistoryTracker.cpp + hwui_cflags += -DBUGREPORT_FONT_CACHE_USAGE +endif + + ifndef HWUI_COMPILE_SYMBOLS hwui_cflags += -fvisibility=hidden endif diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 949ad450d5f7..a8ced9b2597b 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -21,6 +21,9 @@ #include "Properties.h" #include "renderstate/RenderState.h" #include "ShadowTessellator.h" +#ifdef BUGREPORT_FONT_CACHE_USAGE +#include "font/FontCacheHistoryTracker.h" +#endif #include "utils/GLUtils.h" #include <cutils/properties.h> @@ -195,12 +198,7 @@ void Caches::dumpMemoryUsage(String8 &log) { log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(), patchCache.getMaxSize()); - const uint32_t sizeA8 = fontRenderer.getFontRendererSize(GL_ALPHA); - const uint32_t sizeRGBA = fontRenderer.getFontRendererSize(GL_RGBA); - log.appendFormat(" FontRenderer A8 %8d / %8d\n", sizeA8, sizeA8); - log.appendFormat(" FontRenderer RGBA %8d / %8d\n", sizeRGBA, sizeRGBA); - log.appendFormat(" FontRenderer total %8d / %8d\n", sizeA8 + sizeRGBA, - sizeA8 + sizeRGBA); + fontRenderer.dumpMemoryUsage(log); log.appendFormat("Other:\n"); log.appendFormat(" FboCache %8d / %8d\n", @@ -213,11 +211,14 @@ void Caches::dumpMemoryUsage(String8 &log) { total += tessellationCache.getSize(); total += dropShadowCache.getSize(); total += patchCache.getSize(); - total += fontRenderer.getFontRendererSize(GL_ALPHA); - total += fontRenderer.getFontRendererSize(GL_RGBA); + total += fontRenderer.getSize(); log.appendFormat("Total memory usage:\n"); log.appendFormat(" %d bytes, %.2f MB\n", total, total / 1024.0f / 1024.0f); + +#ifdef BUGREPORT_FONT_CACHE_USAGE + fontRenderer.getFontRenderer().historyTracker().dump(log); +#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 276c18d0d3f9..681cf55066b4 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -168,10 +168,17 @@ void FontRenderer::flushAllAndInvalidate() { for (uint32_t i = 0; i < mACacheTextures.size(); i++) { mACacheTextures[i]->init(); + +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphsCleared(mACacheTextures[i]); +#endif } for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) { mRGBACacheTextures[i]->init(); +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]); +#endif } mDrawn = false; @@ -183,6 +190,9 @@ void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) { CacheTexture* cacheTexture = cacheTextures[i]; if (cacheTexture->getPixelBuffer()) { cacheTexture->init(); +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphsCleared(cacheTexture); +#endif LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts); while (it.next()) { it.value()->invalidateTextureCache(cacheTexture); @@ -385,6 +395,10 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp } cachedGlyph->mIsValid = true; + +#ifdef BUGREPORT_FONT_CACHE_USAGE + mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight); +#endif } CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format, @@ -747,19 +761,68 @@ static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextur return size; } -uint32_t FontRenderer::getCacheSize(GLenum format) const { +static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) { + uint32_t size = 0; + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + CacheTexture* cacheTexture = cacheTextures[i]; + if (cacheTexture && cacheTexture->getPixelBuffer()) { + size += cacheTexture->calculateFreeMemory(); + } + } + return size; +} + +const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const { switch (format) { case GL_ALPHA: { - return calculateCacheSize(mACacheTextures); + return mACacheTextures; } case GL_RGBA: { - return calculateCacheSize(mRGBACacheTextures); + return mRGBACacheTextures; } default: { - return 0; + LOG_ALWAYS_FATAL("Unsupported format: %d", format); + // Impossible to hit this, but the compiler doesn't know that + return *(new std::vector<CacheTexture*>()); } } } +static void dumpTextures(String8& log, const char* tag, + const std::vector<CacheTexture*>& cacheTextures) { + for (uint32_t i = 0; i < cacheTextures.size(); i++) { + CacheTexture* cacheTexture = cacheTextures[i]; + if (cacheTexture && cacheTexture->getPixelBuffer()) { + uint32_t free = cacheTexture->calculateFreeMemory(); + uint32_t total = cacheTexture->getPixelBuffer()->getSize(); + log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total); + } + } +} + +void FontRenderer::dumpMemoryUsage(String8& log) const { + const uint32_t sizeA8 = getCacheSize(GL_ALPHA); + const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA); + const uint32_t sizeRGBA = getCacheSize(GL_RGBA); + const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA); + log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8); + dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA)); + log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA); + dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA)); + log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA); +} + +uint32_t FontRenderer::getCacheSize(GLenum format) const { + return calculateCacheSize(cacheTexturesForFormat(format)); +} + +uint32_t FontRenderer::getFreeCacheSize(GLenum format) const { + return calculateFreeCacheSize(cacheTexturesForFormat(format)); +} + +uint32_t FontRenderer::getSize() const { + return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA); +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index e10a81b8ccd8..504dce862f71 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -21,8 +21,12 @@ #include "font/CacheTexture.h" #include "font/CachedGlyphInfo.h" #include "font/Font.h" +#ifdef BUGREPORT_FONT_CACHE_USAGE +#include "font/FontCacheHistoryTracker.h" +#endif #include <utils/LruCache.h> +#include <utils/String8.h> #include <utils/StrongPointer.h> #include <SkPaint.h> @@ -132,7 +136,12 @@ public: mLinearFiltering = linearFiltering; } - uint32_t getCacheSize(GLenum format) const; + uint32_t getSize() const; + void dumpMemoryUsage(String8& log) const; + +#ifdef BUGREPORT_FONT_CACHE_USAGE + FontCacheHistoryTracker& historyTracker() { return mHistoryTracker; } +#endif private: friend class Font; @@ -175,6 +184,10 @@ private: mUploadTexture = true; } + const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const; + uint32_t getCacheSize(GLenum format) const; + uint32_t getFreeCacheSize(GLenum format) const; + uint32_t mSmallCacheWidth; uint32_t mSmallCacheHeight; uint32_t mLargeCacheWidth; @@ -199,6 +212,10 @@ private: bool mLinearFiltering; +#ifdef BUGREPORT_FONT_CACHE_USAGE + FontCacheHistoryTracker mHistoryTracker; +#endif + #ifdef ANDROID_ENABLE_RENDERSCRIPT // RS constructs RSC::sp<RSC::RS> mRs; diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h index 5813e7f717ee..bd27a1a72060 100644 --- a/libs/hwui/GammaFontRenderer.h +++ b/libs/hwui/GammaFontRenderer.h @@ -22,6 +22,8 @@ #include <SkPaint.h> +#include <utils/String8.h> + namespace android { namespace uirenderer { @@ -46,8 +48,16 @@ public: return *mRenderer; } - uint32_t getFontRendererSize(GLenum format) const { - return mRenderer ? mRenderer->getCacheSize(format) : 0; + void dumpMemoryUsage(String8& log) const { + if (mRenderer) { + mRenderer->dumpMemoryUsage(log); + } else { + log.appendFormat("FontRenderer doesn't exist.\n"); + } + } + + uint32_t getSize() const { + return mRenderer ? mRenderer->getSize() : 0; } void endPrecaching(); diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp index 8ba4761c1b2e..4b13814bfdc6 100644 --- a/libs/hwui/font/CacheTexture.cpp +++ b/libs/hwui/font/CacheTexture.cpp @@ -324,5 +324,17 @@ bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_ return false; } +uint32_t CacheTexture::calculateFreeMemory() const { + CacheBlock* cacheBlock = mCacheBlocks; + uint32_t free = 0; + // currently only two formats are supported: GL_ALPHA or GL_RGBA; + uint32_t bpp = mFormat == GL_RGBA ? 4 : 1; + while (cacheBlock) { + free += bpp * cacheBlock->mWidth * cacheBlock->mHeight; + cacheBlock = cacheBlock->mNext; + } + return free; +} + }; // namespace uirenderer }; // namespace android diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h index 4dfb41dafcc7..6750a8ae11cf 100644 --- a/libs/hwui/font/CacheTexture.h +++ b/libs/hwui/font/CacheTexture.h @@ -178,6 +178,8 @@ public: return mCurrentQuad == mMaxQuadCount; } + uint32_t calculateFreeMemory() const; + private: void setDirty(bool dirty); diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index 8e04c8715f62..a95454a4c010 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -408,9 +408,15 @@ void Font::render(const SkPaint* paint, const glyph_t* glyphs, if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { int penX = x + (int) roundf(positions[(glyphsCount << 1)]); int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]); - +#ifdef BUGREPORT_FONT_CACHE_USAGE + mState->historyTracker().glyphRendered(cachedGlyph, penX, penY); +#endif (*this.*render)(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH, bounds, positions); + } else { +#ifdef BUGREPORT_FONT_CACHE_USAGE + mState->historyTracker().glyphRendered(cachedGlyph, -1, -1); +#endif } glyphsCount++; diff --git a/libs/hwui/font/FontCacheHistoryTracker.cpp b/libs/hwui/font/FontCacheHistoryTracker.cpp new file mode 100644 index 000000000000..a2bfb27535e5 --- /dev/null +++ b/libs/hwui/font/FontCacheHistoryTracker.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "FontCacheHistoryTracker.h" + +#include "CachedGlyphInfo.h" +#include "CacheTexture.h" + +namespace android { +namespace uirenderer { + +void FontCacheHistoryTracker::dumpCachedGlyph(String8& log, const CachedGlyph& glyph) { + log.appendFormat("glyph (texture %p, position: (%d, %d), size: %dx%d, gen: %d)", glyph.texture, + glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation); +} + +void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& entry) { + if (entry.penX == -1 && entry.penY == -1) { + log.appendFormat(" glyph skipped in gen: %d\n", entry.glyph.generation); + } else { + log.appendFormat(" rendered "); + dumpCachedGlyph(log, entry.glyph); + log.appendFormat(" at (%d, %d)\n", entry.penX, entry.penY); + } +} + +void FontCacheHistoryTracker::dumpUploadEntry(String8& log, const CachedGlyph& glyph) { + if (glyph.bitmapW == 0 && glyph.bitmapH == 0) { + log.appendFormat(" cleared cachetexture %p in gen %d\n", glyph.texture, + glyph.generation); + } else { + log.appendFormat(" uploaded "); + dumpCachedGlyph(log, glyph); + log.appendFormat("\n"); + } +} + +void FontCacheHistoryTracker::dump(String8& log) const { + log.appendFormat("FontCacheHistory: \n"); + log.appendFormat(" Upload history: \n"); + for (size_t i = 0; i < mUploadHistory.size(); i++) { + dumpUploadEntry(log, mUploadHistory[i]); + } + log.appendFormat(" Render history: \n"); + for (size_t i = 0; i < mRenderHistory.size(); i++) { + dumpRenderEntry(log, mRenderHistory[i]); + } +} + +void FontCacheHistoryTracker::glyphRendered(CachedGlyphInfo* glyphInfo, int penX, int penY) { + RenderEntry& entry = mRenderHistory.next(); + entry.glyph.generation = generation; + entry.glyph.texture = glyphInfo->mCacheTexture; + entry.glyph.startX = glyphInfo->mStartX; + entry.glyph.startY = glyphInfo->mStartY; + entry.glyph.bitmapW = glyphInfo->mBitmapWidth; + entry.glyph.bitmapH = glyphInfo->mBitmapHeight; + entry.penX = penX; + entry.penY = penY; +} + +void FontCacheHistoryTracker::glyphUploaded(CacheTexture* texture, uint32_t x, uint32_t y, + uint16_t glyphW, uint16_t glyphH) { + CachedGlyph& glyph = mUploadHistory.next(); + glyph.generation = generation; + glyph.texture = texture; + glyph.startX = x; + glyph.startY = y; + glyph.bitmapW = glyphW; + glyph.bitmapH = glyphH; +} + +void FontCacheHistoryTracker::glyphsCleared(CacheTexture* texture) { + CachedGlyph& glyph = mUploadHistory.next(); + glyph.generation = generation; + glyph.texture = texture; + glyph.startX = 0; + glyph.startY = 0; + glyph.bitmapW = 0; + glyph.bitmapH = 0; +} + +void FontCacheHistoryTracker::frameCompleted() { + generation++; +} +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/font/FontCacheHistoryTracker.h b/libs/hwui/font/FontCacheHistoryTracker.h new file mode 100644 index 000000000000..f1d9b9f10dc0 --- /dev/null +++ b/libs/hwui/font/FontCacheHistoryTracker.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once +#include "../utils/RingBuffer.h" + +#include <utils/String8.h> + +namespace android { +namespace uirenderer { + +class CacheTexture; +struct CachedGlyphInfo; + +// Tracks glyph uploads and recent rendered/skipped glyphs, so it can give an idea +// what a missing character is: skipped glyph, wrong coordinates in cache texture etc. +class FontCacheHistoryTracker { +public: + void glyphRendered(CachedGlyphInfo*, int penX, int penY); + void glyphUploaded(CacheTexture*, uint32_t x, uint32_t y, uint16_t glyphW, uint16_t glyphH); + void glyphsCleared(CacheTexture*); + void frameCompleted(); + + void dump(String8& log) const; +private: + struct CachedGlyph { + void* texture; + uint16_t generation; + uint16_t startX; + uint16_t startY; + uint16_t bitmapW; + uint16_t bitmapH; + }; + + struct RenderEntry { + CachedGlyph glyph; + int penX; + int penY; + }; + + static void dumpCachedGlyph(String8& log, const CachedGlyph& glyph); + static void dumpRenderEntry(String8& log, const RenderEntry& entry); + static void dumpUploadEntry(String8& log, const CachedGlyph& glyph); + + RingBuffer<RenderEntry, 300> mRenderHistory; + RingBuffer<CachedGlyph, 120> mUploadHistory; + uint16_t generation = 0; +}; + +}; // namespace uirenderer +}; // namespace android
\ No newline at end of file diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 70b9a436dee2..975ac8368e3d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -608,6 +608,10 @@ void CanvasContext::draw() { } GpuMemoryTracker::onFrameCompleted(); +#ifdef BUGREPORT_FONT_CACHE_USAGE + caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted(); +#endif + } // Called by choreographer to do an RT-driven animation diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index 27193b743379..abef66f9ecd9 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -36,6 +36,29 @@ namespace android { +// --- WeakLooperCallback --- + +class WeakLooperCallback: public LooperCallback { +protected: + virtual ~WeakLooperCallback() { } + +public: + WeakLooperCallback(const wp<LooperCallback>& callback) : + mCallback(callback) { + } + + virtual int handleEvent(int fd, int events, void* data) { + sp<LooperCallback> callback = mCallback.promote(); + if (callback != NULL) { + return callback->handleEvent(fd, events, data); + } + return 0; // the client is gone, remove the callback + } + +private: + wp<LooperCallback> mCallback; +}; + // --- PointerController --- // Time to wait before starting the fade when the pointer is inactive. @@ -57,10 +80,11 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>& const sp<Looper>& looper, const sp<SpriteController>& spriteController) : mPolicy(policy), mLooper(looper), mSpriteController(spriteController) { mHandler = new WeakMessageHandler(this); + mCallback = new WeakLooperCallback(this); if (mDisplayEventReceiver.initCheck() == NO_ERROR) { mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, - Looper::EVENT_INPUT, this, nullptr); + Looper::EVENT_INPUT, mCallback, nullptr); } else { ALOGE("Failed to initialize DisplayEventReceiver."); } diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 99292d7ca8a6..4794f3da824c 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -144,6 +144,7 @@ private: sp<Looper> mLooper; sp<SpriteController> mSpriteController; sp<WeakMessageHandler> mHandler; + sp<LooperCallback> mCallback; DisplayEventReceiver mDisplayEventReceiver; diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 5286f8fa5ad3..89709ee6b95a 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -24,6 +24,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; +import android.util.SparseIntArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -170,6 +171,66 @@ public final class AudioAttributes implements Parcelable { public final static int USAGE_VIRTUAL_SOURCE = 15; /** + * IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES + * if applicable. + */ + + /** + * @hide + * Denotes a usage for notifications that do not expect immediate intervention from the user, + * will be muted when the Zen mode disables notifications + * @see #SUPPRESSIBLE_USAGES + */ + public final static int SUPPRESSIBLE_NOTIFICATION = 1; + /** + * @hide + * Denotes a usage for notifications that do expect immediate intervention from the user, + * will be muted when the Zen mode disables calls + * @see #SUPPRESSIBLE_USAGES + */ + public final static int SUPPRESSIBLE_CALL = 2; + + /** + * @hide + * Array of all usage types for calls and notifications to assign the suppression behavior, + * used by the Zen mode restrictions. + * @see com.android.server.notification.ZenModeHelper + */ + public static final SparseIntArray SUPPRESSIBLE_USAGES; + + static { + SUPPRESSIBLE_USAGES = new SparseIntArray(); + SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION, SUPPRESSIBLE_NOTIFICATION); + SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_RINGTONE, SUPPRESSIBLE_CALL); + SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_REQUEST,SUPPRESSIBLE_CALL); + SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_INSTANT,SUPPRESSIBLE_NOTIFICATION); + SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_DELAYED,SUPPRESSIBLE_NOTIFICATION); + SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT, SUPPRESSIBLE_NOTIFICATION); + } + + /** + * @hide + * Array of all usage types exposed in the SDK that applications can use. + */ + public final static int[] SDK_USAGES = { + USAGE_UNKNOWN, + USAGE_MEDIA, + USAGE_VOICE_COMMUNICATION, + USAGE_VOICE_COMMUNICATION_SIGNALLING, + USAGE_ALARM, + USAGE_NOTIFICATION, + USAGE_NOTIFICATION_RINGTONE, + USAGE_NOTIFICATION_COMMUNICATION_REQUEST, + USAGE_NOTIFICATION_COMMUNICATION_INSTANT, + USAGE_NOTIFICATION_COMMUNICATION_DELAYED, + USAGE_NOTIFICATION_EVENT, + USAGE_ASSISTANCE_ACCESSIBILITY, + USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, + USAGE_ASSISTANCE_SONIFICATION, + USAGE_GAME + }; + + /** * Flag defining a behavior where the audibility of the sound will be ensured by the system. */ public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0; diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 101facd4909b..9bf47938f543 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -219,26 +219,12 @@ public class MediaRouter { } if (mBluetoothA2dpRoute != null) { - final boolean a2dpEnabled = isBluetoothA2dpOn(); - if (mainType != AudioRoutesInfo.MAIN_SPEAKER && - mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) { - selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false); - } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) && - a2dpEnabled) { + if (mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) { selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false); } } } - boolean isBluetoothA2dpOn() { - try { - return mAudioService.isBluetoothA2dpOn(); - } catch (RemoteException e) { - Log.e(TAG, "Error querying Bluetooth A2DP state", e); - return false; - } - } - void updateDiscoveryRequest() { // What are we looking for today? int routeTypes = 0; @@ -908,6 +894,11 @@ public class MediaRouter { static void selectRouteStatic(int types, @NonNull RouteInfo route, boolean explicit) { Log.v(TAG, "Selecting route: " + route); assert(route != null); + if (route == sStatic.mDefaultAudioVideo && sStatic.mBluetoothA2dpRoute != null) { + Log.i(TAG, "Change the route to a BT route: " + sStatic.mBluetoothA2dpRoute + + "\nDo not select the default route when a BT route is available."); + route = sStatic.mBluetoothA2dpRoute; + } final RouteInfo oldRoute = sStatic.mSelectedRoute; if (oldRoute == route) return; if (!route.matchesTypes(types)) { @@ -917,16 +908,6 @@ public class MediaRouter { return; } - final RouteInfo btRoute = sStatic.mBluetoothA2dpRoute; - if (btRoute != null && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && - (route == btRoute || route == sStatic.mDefaultAudioVideo)) { - try { - sStatic.mAudioService.setBluetoothA2dpOn(route == btRoute); - } catch (RemoteException e) { - Log.e(TAG, "Error changing Bluetooth A2DP state", e); - } - } - final WifiDisplay activeDisplay = sStatic.mDisplayService.getWifiDisplayStatus().getActiveDisplay(); final boolean oldRouteHasAddress = oldRoute != null && oldRoute.mDeviceAddress != null; @@ -966,7 +947,7 @@ public class MediaRouter { static void selectDefaultRouteStatic() { // TODO: Be smarter about the route types here; this selects for all valid. if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute - && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) { + && sStatic.mBluetoothA2dpRoute != null) { selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false); } else { selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false); @@ -1298,12 +1279,7 @@ public class MediaRouter { selectedRoute == sStatic.mDefaultAudioVideo) { dispatchRouteVolumeChanged(selectedRoute); } else if (sStatic.mBluetoothA2dpRoute != null) { - try { - dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ? - sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo); - } catch (RemoteException e) { - Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e); - } + dispatchRouteVolumeChanged(sStatic.mBluetoothA2dpRoute); } else { dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo); } diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java index 32e335843016..808ec361fb4f 100644 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoService.java +++ b/packages/EasterEgg/src/com/android/egg/neko/NekoService.java @@ -102,6 +102,14 @@ public class NekoService extends JobService { return false; } + public static void registerJobIfNeeded(Context context, long intervalMinutes) { + JobScheduler jss = context.getSystemService(JobScheduler.class); + JobInfo info = jss.getPendingJob(JOB_ID); + if (info == null) { + registerJob(context, intervalMinutes); + } + } + public static void registerJob(Context context, long intervalMinutes) { JobScheduler jss = context.getSystemService(JobScheduler.class); jss.cancel(JOB_ID); diff --git a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java index 8a3ec8fa19e9..159b40a3e5af 100644 --- a/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java +++ b/packages/EasterEgg/src/com/android/egg/neko/NekoTile.java @@ -68,6 +68,9 @@ public class NekoTile extends TileService implements PrefsListener { Tile tile = getQsTile(); int foodState = mPrefs.getFoodState(); Food food = new Food(foodState); + if (foodState != 0) { + NekoService.registerJobIfNeeded(this, food.getInterval(this)); + } tile.setIcon(food.getIcon(this)); tile.setLabel(food.getName(this)); tile.setState(foodState != 0 ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); diff --git a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java index 5f54180bc2e0..bf71b197d3cb 100644 --- a/packages/EasterEgg/src/com/android/egg/neko/PrefState.java +++ b/packages/EasterEgg/src/com/android/egg/neko/PrefState.java @@ -43,13 +43,11 @@ public class PrefState implements OnSharedPreferenceChangeListener { public void addCat(Cat cat) { mPrefs.edit() .putString(CAT_KEY_PREFIX + String.valueOf(cat.getSeed()), cat.getName()) - .commit(); + .apply(); } public void removeCat(Cat cat) { - mPrefs.edit() - .remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())) - .commit(); + mPrefs.edit().remove(CAT_KEY_PREFIX + String.valueOf(cat.getSeed())).apply(); } public List<Cat> getCats() { @@ -71,7 +69,7 @@ public class PrefState implements OnSharedPreferenceChangeListener { } public void setFoodState(int foodState) { - mPrefs.edit().putInt(FOOD_STATE, foodState).commit(); + mPrefs.edit().putInt(FOOD_STATE, foodState).apply(); } public void setListener(PrefsListener listener) { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index e169c0d072db..dccb1a921489 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -141,6 +141,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private static final int MSG_SERVICE_STATE_CHANGE = 330; private static final int MSG_SCREEN_TURNED_ON = 331; private static final int MSG_SCREEN_TURNED_OFF = 332; + private static final int MSG_DREAMING_STATE_CHANGED = 333; /** Fingerprint state: Not listening to fingerprint. */ private static final int FINGERPRINT_STATE_STOPPED = 0; @@ -293,6 +294,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { handleScreenTurnedOff(); Trace.endSection(); break; + case MSG_DREAMING_STATE_CHANGED: + handleDreamingStateChanged(msg.arg1); + break; } } }; @@ -990,6 +994,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + private void handleDreamingStateChanged(int dreamStart) { + final int count = mCallbacks.size(); + boolean showingDream = dreamStart == 1; + for (int i = 0; i < count; i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onDreamingStateChanged(showingDream); + } + } + } + /** * IMPORTANT: Must be called from UI thread. */ @@ -1736,6 +1751,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mHandler.sendEmptyMessage(MSG_SCREEN_TURNED_OFF); } + public void dispatchDreamingStarted() { + mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 1, 0)); + } + + public void dispatchDreamingStopped() { + mHandler.sendMessage(mHandler.obtainMessage(MSG_DREAMING_STATE_CHANGED, 0, 0)); + } + public boolean isDeviceInteractive() { return mDeviceInteractive; } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 4a2d356b6ddd..eb29d9b550e3 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -245,4 +245,10 @@ public class KeyguardUpdateMonitorCallback { * Called when the state whether we have a lockscreen wallpaper has changed. */ public void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper) { } + + /** + * Called when the dream's window state is changed. + * @param dreaming true if the dream's window has been created and is visible + */ + public void onDreamingStateChanged(boolean dreaming) { } } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java index 0e3e0d584e97..5c577f8aa83c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java @@ -126,6 +126,13 @@ public class StorageMeasurement { * internal storage. Key is {@link UserHandle}. */ public SparseLongArray usersSize = new SparseLongArray(); + + @Override + public String toString() { + return "MeasurementDetails: [totalSize: " + totalSize + " availSize: " + availSize + + " cacheSize: " + cacheSize + " mediaSize: " + mediaSize + + " miscSize: " + miscSize + "usersSize: " + usersSize + "]"; + } } public interface MeasurementReceiver { @@ -435,7 +442,7 @@ public class StorageMeasurement { private static long getDirectorySize(IMediaContainerService imcs, File path) { try { final long size = imcs.calculateDirectorySize(path.toString()); - Log.d(TAG, "getDirectorySize(" + path + ") returned " + size); + if (LOGV) Log.v(TAG, "getDirectorySize(" + path + ") returned " + size); return size; } catch (Exception e) { Log.w(TAG, "Could not read memory from default container service for " + path, e); diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java index a99e66873958..af8fd4c46a64 100644 --- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java @@ -23,6 +23,7 @@ import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.os.AsyncTask; import android.os.RemoteException; +import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.Log; import android.util.MathUtils; @@ -207,39 +208,41 @@ public class DisplayDensityUtils { /** * Asynchronously applies display density changes to the specified display. + * <p> + * The change will be applied to the user specified by the value of + * {@link UserHandle#myUserId()} at the time the method is called. * * @param displayId the identifier of the display to modify */ public static void clearForcedDisplayDensity(final int displayId) { - AsyncTask.execute(new Runnable() { - @Override - public void run() { - try { - final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); - wm.clearForcedDisplayDensity(displayId); - } catch (RemoteException exc) { - Log.w(LOG_TAG, "Unable to clear forced display density setting"); - } + final int userId = UserHandle.myUserId(); + AsyncTask.execute(() -> { + try { + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + wm.clearForcedDisplayDensityForUser(displayId, userId); + } catch (RemoteException exc) { + Log.w(LOG_TAG, "Unable to clear forced display density setting"); } }); } /** * Asynchronously applies display density changes to the specified display. + * <p> + * The change will be applied to the user specified by the value of + * {@link UserHandle#myUserId()} at the time the method is called. * * @param displayId the identifier of the display to modify * @param density the density to force for the specified display */ public static void setForcedDisplayDensity(final int displayId, final int density) { - AsyncTask.execute(new Runnable() { - @Override - public void run() { - try { - final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); - wm.setForcedDisplayDensity(displayId, density); - } catch (RemoteException exc) { - Log.w(LOG_TAG, "Unable to save forced display density setting"); - } + final int userId = UserHandle.myUserId(); + AsyncTask.execute(() -> { + try { + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + wm.setForcedDisplayDensityForUser(displayId, density, userId); + } catch (RemoteException exc) { + Log.w(LOG_TAG, "Unable to save forced display density setting"); } }); } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index a50b366c26ac..458672a41b77 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -28,6 +28,8 @@ import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.os.AsyncTask; import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.support.v4.widget.DrawerLayout; import android.util.ArraySet; @@ -73,6 +75,7 @@ public class SettingsDrawerActivity extends Activity { private FrameLayout mContentHeaderContainer; private DrawerLayout mDrawerLayout; private boolean mShowingMenu; + private UserManager mUserManager; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -110,6 +113,8 @@ public class SettingsDrawerActivity extends Activity { onTileClicked(mDrawerAdapter.getTile(position)); }; }); + + mUserManager = UserManager.get(this); if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms"); } @@ -257,6 +262,7 @@ public class SettingsDrawerActivity extends Activity { return true; } try { + updateUserHandlesIfNeeded(tile); int numUserHandles = tile.userHandle.size(); if (numUserHandles > 1) { ProfileSelectDialog.show(getFragmentManager(), tile); @@ -278,6 +284,19 @@ public class SettingsDrawerActivity extends Activity { return true; } + private void updateUserHandlesIfNeeded(Tile tile) { + List<UserHandle> userHandles = tile.userHandle; + + for (int i = userHandles.size()-1; i >= 0; i--) { + if (mUserManager.getUserInfo(userHandles.get(i).getIdentifier()) == null) { + if (DEBUG_TIMING) { + Log.d(TAG, "Delete the user: " + userHandles.get(i).getIdentifier()); + } + userHandles.remove(i); + } + } + } + protected void onTileClicked(Tile tile) { if (openTile(tile)) { finish(); diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index f7e9541b0d33..cd2d6b337f73 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -36,7 +36,7 @@ <fraction name="def_window_transition_scale">100%</fraction> <bool name="def_haptic_feedback">true</bool> - <bool name="def_bluetooth_on">false</bool> + <bool name="def_bluetooth_on">true</bool> <bool name="def_wifi_display_on">false</bool> <bool name="def_install_non_market_apps">false</bool> <bool name="def_package_verifier_enable">true</bool> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 7a0b666113d9..dcc30e2495b3 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -347,8 +347,8 @@ <string name="description_direction_left" msgid="7207478719805562165">"لغزاندن به چپ برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> <string name="zen_priority_introduction" msgid="3070506961866919502">"صداها و لرزشهایی به جز هشدارها، یادآوریها، رویدادها و تماسگیرندههایی که مشخص میکنید، مزاحم شما نمیشوند."</string> <string name="zen_priority_customize_button" msgid="7948043278226955063">"سفارشی کردن"</string> - <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزشها از جمله هشدارها، موسیقی، ویدیوها و بازیها را مسدود میکند. همچنان میتوانید تماس تلفنی برقرار کنید."</string> - <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزشها از جمله هشدارها، موسیقی، ویدیوها و بازیها را مسدود میکند."</string> + <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"این کار «همه» صداها و لرزشها از جمله هشدارها، موسیقی، ویدئوها و بازیها را مسدود میکند. همچنان میتوانید تماس تلفنی برقرار کنید."</string> + <string name="zen_silence_introduction" msgid="3137882381093271568">"این کار «همه» صداها و لرزشها از جمله هشدارها، موسیقی، ویدئوها و بازیها را مسدود میکند."</string> <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="1288875699658819755">"اعلانهای کمتر فوری در زیر"</string> <string name="notification_tap_again" msgid="7590196980943943842">"دوباره ضربه بزنید تا باز شود"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 33e7ec00b4ac..62ece3c10e47 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -404,7 +404,7 @@ <string name="device_owned_footer" msgid="3802752663326030053">"डिवाइस को मॉनीटर किया जा सकता है"</string> <string name="profile_owned_footer" msgid="8021888108553696069">"प्रोफ़ाइल को मॉनीटर किया जा सकता है"</string> <string name="vpn_footer" msgid="2388611096129106812">"नेटवर्क को मॉनीटर किया जा सकता है"</string> - <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्क को मॉनीटर किया जा सकता है"</string> + <string name="branded_vpn_footer" msgid="2168111859226496230">"नेटवर्क को मॉनिटर किया जा सकता है"</string> <string name="monitoring_title_device_owned" msgid="7121079311903859610">"डिवाइस को मॉनीटर करना"</string> <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"प्रोफ़ाइल को मॉनीटर करना"</string> <string name="monitoring_title" msgid="169206259253048106">"नेटवर्क को मॉनीटर करना"</string> @@ -417,7 +417,7 @@ <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string> <string name="monitoring_description_app" msgid="6259179342284742878">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है."</string> <string name="monitoring_description_app_personal" msgid="484599052118316268">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्स और वेबसाइटों सहित आपकी व्यक्तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string> - <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्यक्तिगत नेटवर्क गतिविधि को मॉनीटर कर सकता है."</string> + <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आप <xliff:g id="APPLICATION">%1$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्लिकेशन और वेबसाइट सहित आपकी व्यक्तिगत नेटवर्क गतिविधि को मॉनिटर कर सकता है."</string> <string name="monitoring_description_app_work" msgid="1754325860918060897">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्ट है, जो ईमेल, ऐप्स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string> <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"आपकी कार्य प्रोफ़ाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है. वह <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> से कनेक्ट है, जो ईमेल, ऐप्स और वेबसाइटों सहित आपकी कार्य नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nआप <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> से भी कनेक्ट हैं, जो आपकी व्यक्तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string> <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"आपका डिवाइस <xliff:g id="ORGANIZATION">%1$s</xliff:g> के द्वारा प्रबंधित है.\n\nआपका नियंत्रक सेटिंग, कॉर्पोरेट ऐक्सेस, ऐप्स, आपके डिवाइस से संबद्ध डेटा और आपके डिवाइस की स्थान जानकारी की निगरानी और उसका प्रबंधन कर सकता है.\n\nआप <xliff:g id="APPLICATION">%2$s</xliff:g> से कनेक्ट हैं, जो ईमेल, ऐप्स और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nअधिक जानकारी के लिए, अपने नियंत्रक से संपर्क करें."</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 1e3b8419de99..c659acfaf14e 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -217,7 +217,7 @@ <style name="Animation.StatusBar"> </style> - <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" /> + <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.Settings.Dark" /> <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light"> <item name="android:colorAccent">@color/remote_input_accent</item> diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index b9ae585c339c..19ae2954bb2a 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -49,7 +49,6 @@ public final class Prefs { Key.QS_WORK_ADDED, }) public @interface Key { - @Deprecated String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime"; String DEBUG_MODE_ENABLED = "debugModeEnabled"; String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed"; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 4449435dde40..6103355a568e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -964,6 +964,7 @@ public class KeyguardViewMediator extends SystemUI { * if there is a secure lock pattern. */ public void onDreamingStarted() { + KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStarted(); synchronized (this) { if (mDeviceInteractive && mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) { @@ -976,6 +977,7 @@ public class KeyguardViewMediator extends SystemUI { * A dream stopped. */ public void onDreamingStopped() { + KeyguardUpdateMonitor.getInstance(mContext).dispatchDreamingStopped(); synchronized (this) { if (mDeviceInteractive) { cancelDoKeyguardLaterLocked(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index a7d7df50691c..72074635999c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -34,7 +34,6 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; @@ -47,7 +46,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; -import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.SystemUI; @@ -252,19 +250,6 @@ public class Recents extends SystemUI registerWithSystemUser(); } putComponent(Recents.class, this); - - // Migrate the old stack active time if necessary, otherwise, it will already be managed - // when the tasks are loaded in the system. See TaskPersister.restoreTasksForUserLocked(). - long lastVisibleTaskActiveTime = Prefs.getLong(mContext, - Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1); - if (lastVisibleTaskActiveTime != -1) { - long uptime = SystemClock.elapsedRealtime(); - Settings.Secure.putLongForUser(mContext.getContentResolver(), - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, - uptime - Math.max(0, System.currentTimeMillis() - lastVisibleTaskActiveTime), - processUser); - Prefs.remove(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME); - } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 1e418706dd59..7bdb1c499bd9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -20,7 +20,6 @@ import android.app.Activity; import android.app.ActivityOptions; import android.app.TaskStackBuilder; import android.content.BroadcastReceiver; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -171,6 +170,13 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD if (action.equals(Intent.ACTION_SCREEN_OFF)) { // When the screen turns off, dismiss Recents to Home dismissRecentsToHomeIfVisible(false); + } else if (action.equals(Intent.ACTION_TIME_CHANGED)) { + // For the time being, if the time changes, then invalidate the + // last-stack-active-time, this ensures that we will just show the last N tasks + // the next time that Recents loads, but prevents really old tasks from showing + // up if the task time is set forward. + Prefs.putLong(RecentsActivity.this, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, + 0); } } }; @@ -316,6 +322,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD // Register the broadcast receiver to handle messages when the screen is turned off IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_TIME_CHANGED); registerReceiver(mSystemBroadcastReceiver, filter); getWindow().addPrivateFlags(LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION); @@ -793,19 +800,14 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD EventBus.getDefault().dump(prefix, writer); Recents.getTaskLoader().dump(prefix, writer); - ContentResolver cr = getContentResolver(); - long lastPersistUptime = Settings.Secure.getLong(cr, - Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0); - long lastVisibleTaskActiveUptime = Settings.Secure.getLongForUser(cr, - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, - SystemClock.elapsedRealtime(), Recents.getSystemServices().getCurrentUser()); - String id = Integer.toHexString(System.identityHashCode(this)); + long lastStackActiveTime = Prefs.getLong(this, + Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1); writer.print(prefix); writer.print(TAG); writer.print(" visible="); writer.print(mIsVisible ? "Y" : "N"); - writer.print(" lastPersistUptime="); writer.print(lastPersistUptime); - writer.print(" lastVisibleTaskActiveUptime="); writer.print(lastVisibleTaskActiveUptime); + writer.print(" lastStackTaskActiveTime="); writer.print(lastStackActiveTime); + writer.print(" currentTime="); writer.print(System.currentTimeMillis()); writer.print(" [0x"); writer.print(id); writer.print("]"); writer.println(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 0dd9e5428ad8..b896f8a4d815 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -59,7 +59,6 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; @@ -75,7 +74,6 @@ import android.view.WindowManager.KeyboardShortcutsReceiver; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.AssistUtils; import com.android.internal.os.BackgroundThread; import com.android.systemui.R; @@ -200,9 +198,6 @@ public class SystemServicesProxy { */ private List<TaskStackListener> mTaskStackListeners = new ArrayList<>(); - /** Test constructor */ - @VisibleForTesting public SystemServicesProxy() {} - /** Private constructor */ private SystemServicesProxy(Context context) { mAccm = AccessibilityManager.getInstance(context); @@ -304,7 +299,7 @@ public class SystemServicesProxy { rti.baseIntent = new Intent(); rti.baseIntent.setComponent(cn); rti.description = description; - rti.firstActiveTime = rti.lastActiveTime = SystemClock.elapsedRealtime(); + rti.firstActiveTime = rti.lastActiveTime = i; if (i % 2 == 0) { rti.taskDescription = new ActivityManager.TaskDescription(description, Bitmap.createBitmap(mDummyIcon), null, diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index ecd48e1f8da0..1278b735a7cd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -24,15 +24,13 @@ import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; -import android.provider.Settings; import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseIntArray; -import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsConfiguration; @@ -58,11 +56,6 @@ public class RecentsTaskLoadPlan { private static int SESSION_BEGIN_TIME = 1000 /* ms/s */ * 60 /* s/min */ * 60 /* min/hr */ * 6 /* hrs */; - @VisibleForTesting - public interface SystemTimeProvider { - public long getTime(); - } - /** The set of conditions to load tasks. */ public static class Options { public int runningTaskId = -1; @@ -74,46 +67,15 @@ public class RecentsTaskLoadPlan { public int numVisibleTaskThumbnails = 0; } - private Context mContext; - @VisibleForTesting private SystemServicesProxy mSystemServicesProxy; - - private List<ActivityManager.RecentTaskInfo> mRawTasks; - private long mLastVisibileTaskActiveTime; - private TaskStack mStack; - private ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>(); - private SystemTimeProvider mTimeProvider = new SystemTimeProvider() { - @Override - public long getTime() { - return SystemClock.elapsedRealtime(); - } - }; + Context mContext; - @VisibleForTesting - public RecentsTaskLoadPlan(Context context, SystemServicesProxy ssp) { - mContext = context; - mSystemServicesProxy = ssp; - } - - @VisibleForTesting - public void setInternals(List<ActivityManager.RecentTaskInfo> tasks, - final long currentTime, long lastVisibleTaskActiveTime) { - setInternals(tasks, MIN_NUM_TASKS, currentTime, lastVisibleTaskActiveTime, - SESSION_BEGIN_TIME); - } + List<ActivityManager.RecentTaskInfo> mRawTasks; + TaskStack mStack; + ArraySet<Integer> mCurrentQuietProfiles = new ArraySet<Integer>(); - @VisibleForTesting - public void setInternals(List<ActivityManager.RecentTaskInfo> tasks, int minNumTasks, - final long currentTime, long lastVisibleTaskActiveTime, int sessionBeginTime) { - mRawTasks = tasks; - mLastVisibileTaskActiveTime = lastVisibleTaskActiveTime; - mTimeProvider = new SystemTimeProvider() { - @Override - public long getTime() { - return currentTime; - } - }; - MIN_NUM_TASKS = minNumTasks; - SESSION_BEGIN_TIME = sessionBeginTime; + /** Package level ctor */ + RecentsTaskLoadPlan(Context context) { + mContext = context; } private void updateCurrentQuietProfilesCache(int currentUserId) { @@ -141,13 +103,9 @@ public class RecentsTaskLoadPlan { public synchronized void preloadRawTasks(boolean includeFrontMostExcludedTask) { int currentUserId = UserHandle.USER_CURRENT; updateCurrentQuietProfilesCache(currentUserId); - mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), + SystemServicesProxy ssp = Recents.getSystemServices(); + mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), currentUserId, includeFrontMostExcludedTask, mCurrentQuietProfiles); - mLastVisibileTaskActiveTime = RecentsDebugFlags.Static.EnableMockTasks - ? SystemClock.elapsedRealtime() - : Settings.Secure.getLongForUser(mContext.getContentResolver(), - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, - 0, currentUserId); // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it Collections.reverse(mRawTasks); @@ -176,9 +134,12 @@ public class RecentsTaskLoadPlan { R.string.accessibility_recents_item_will_be_dismissed); String appInfoDescFormat = mContext.getString( R.string.accessibility_recents_item_open_app_info); - boolean updatedLastVisibleTaskActiveTime = false; - long newLastVisibileTaskActiveTime = 0; - long currentTime = mTimeProvider.getTime(); + long lastStackActiveTime = Prefs.getLong(mContext, + Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0); + if (RecentsDebugFlags.Static.EnableMockTasks) { + lastStackActiveTime = 0; + } + long newLastStackActiveTime = -1; int taskCount = mRawTasks.size(); for (int i = 0; i < taskCount; i++) { ActivityManager.RecentTaskInfo t = mRawTasks.get(i); @@ -187,20 +148,19 @@ public class RecentsTaskLoadPlan { Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent, t.userId, t.firstActiveTime, t.lastActiveTime); - // Only show the task if it is freeform, or later than the last visible task active time - // and either recently used, or within the last five tasks - boolean isFreeformTask = mSystemServicesProxy.isFreeformStack(t.stackId); - boolean isRecentlyUsedTask = t.lastActiveTime >= (currentTime - SESSION_BEGIN_TIME); - boolean isMoreRecentThanLastVisible = t.lastActiveTime >= mLastVisibileTaskActiveTime; - boolean isStackTask = isFreeformTask || (isMoreRecentThanLastVisible && - (isRecentlyUsedTask || i >= (taskCount - MIN_NUM_TASKS))); - boolean isLaunchTarget = t.persistentId == runningTaskId; - - // If this is the first task satisfying the stack constraints, update the baseline - // at which we show visible tasks - if (isStackTask && !updatedLastVisibleTaskActiveTime) { - newLastVisibileTaskActiveTime = t.lastActiveTime; - updatedLastVisibleTaskActiveTime = true; + // This task is only shown in the stack if it statisfies the historical time or min + // number of tasks constraints. Freeform tasks are also always shown. + boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId); + boolean isStackTask = isFreeformTask || !isHistoricalTask(t) || + (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS)); + boolean isLaunchTarget = taskKey.id == runningTaskId; + + // The last stack active time is the baseline for which we show visible tasks. Since + // the system will store all the tasks, we don't want to show the tasks prior to the + // last visible ones, otherwise, as you dismiss them, the previous tasks may satisfy + // the other stack-task constraints. + if (isStackTask && newLastStackActiveTime < 0) { + newLastStackActiveTime = t.lastActiveTime; } // Load the title, icon, and color @@ -228,12 +188,9 @@ public class RecentsTaskLoadPlan { affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1); affiliatedTasks.put(taskKey.id, taskKey); } - if (updatedLastVisibleTaskActiveTime && - newLastVisibileTaskActiveTime != mLastVisibileTaskActiveTime) { - Settings.Secure.putLongForUser(mContext.getContentResolver(), - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, - newLastVisibileTaskActiveTime, UserHandle.USER_CURRENT); - mLastVisibileTaskActiveTime = newLastVisibileTaskActiveTime; + if (newLastStackActiveTime != -1) { + Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, + newLastStackActiveTime); } // Initialize the stacks @@ -298,4 +255,11 @@ public class RecentsTaskLoadPlan { } return false; } + + /** + * Returns whether this task is too old to be shown. + */ + private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) { + return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index e0eda376eac2..ba31e3e835c0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -30,7 +30,6 @@ import android.os.HandlerThread; import android.util.Log; import android.util.LruCache; -import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsConfiguration; @@ -287,20 +286,6 @@ public class RecentsTaskLoader { } }; - @VisibleForTesting - public RecentsTaskLoader() { - mActivityInfoCache = null; - mIconCache = null; - mThumbnailCache = null; - mActivityLabelCache = null; - mContentDescriptionCache = null; - mLoadQueue = null; - mLoader = null; - - mMaxThumbnailCacheSize = 0; - mMaxIconCacheSize = 0; - } - public RecentsTaskLoader(Context context) { Resources res = context.getResources(); mDefaultTaskBarBackgroundColor = @@ -347,8 +332,7 @@ public class RecentsTaskLoader { /** Creates a new plan for loading the recent tasks. */ public RecentsTaskLoadPlan createLoadPlan(Context context) { - RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context, - Recents.getSystemServices()); + RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context); return plan; } @@ -471,8 +455,7 @@ public class RecentsTaskLoader { /** * Returns the cached task label if the task key is not expired, updating the cache if it is. */ - @VisibleForTesting public String getAndUpdateActivityTitle(Task.TaskKey taskKey, - ActivityManager.TaskDescription td) { + String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) { SystemServicesProxy ssp = Recents.getSystemServices(); // Return the task description label if it exists @@ -500,8 +483,7 @@ public class RecentsTaskLoader { * Returns the cached task content description if the task key is not expired, updating the * cache if it is. */ - @VisibleForTesting public String getAndUpdateContentDescription(Task.TaskKey taskKey, - Resources res) { + String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) { SystemServicesProxy ssp = Recents.getSystemServices(); // Return the cached content description if it exists @@ -525,8 +507,8 @@ public class RecentsTaskLoader { /** * Returns the cached task icon if the task key is not expired, updating the cache if it is. */ - @VisibleForTesting public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, - ActivityManager.TaskDescription td, Resources res, boolean loadIfNotCached) { + Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td, + Resources res, boolean loadIfNotCached) { SystemServicesProxy ssp = Recents.getSystemServices(); // Return the cached activity icon if it exists @@ -560,8 +542,7 @@ public class RecentsTaskLoader { /** * Returns the cached thumbnail if the task key is not expired, updating the cache if it is. */ - @VisibleForTesting public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, - boolean loadIfNotCached) { + Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) { SystemServicesProxy ssp = Recents.getSystemServices(); // Return the cached thumbnail if it exists @@ -589,7 +570,7 @@ public class RecentsTaskLoader { * Returns the task's primary color if possible, defaulting to the default color if there is * no specified primary color. */ - @VisibleForTesting public int getActivityPrimaryColor(ActivityManager.TaskDescription td) { + int getActivityPrimaryColor(ActivityManager.TaskDescription td) { if (td != null && td.getPrimaryColor() != 0) { return td.getPrimaryColor(); } @@ -599,7 +580,7 @@ public class RecentsTaskLoader { /** * Returns the task's background color if possible. */ - @VisibleForTesting public int getActivityBackgroundColor(ActivityManager.TaskDescription td) { + int getActivityBackgroundColor(ActivityManager.TaskDescription td) { if (td != null && td.getBackgroundColor() != 0) { return td.getBackgroundColor(); } @@ -610,7 +591,7 @@ public class RecentsTaskLoader { * Returns the activity info for the given task key, retrieving one from the system if the * task key is expired. */ - @VisibleForTesting public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) { + ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) { SystemServicesProxy ssp = Recents.getSystemServices(); ComponentName cn = taskKey.getComponent(); ActivityInfo activityInfo = mActivityInfoCache.get(cn); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 4191f52c35e4..86a0315496a1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -290,10 +290,7 @@ public class Task { */ public boolean isFreeformTask() { SystemServicesProxy ssp = Recents.getSystemServices(); - if (ssp != null) { - return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId); - } - return false; + return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId); } /** Notifies the callback listeners that this task has been loaded */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index a1854fa06562..b3a1893832e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -1944,9 +1944,18 @@ public abstract class BaseStatusBar extends SystemUI implements .getIdentifier(); if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId) && mKeyguardManager.isDeviceLocked(userId)) { - if (startWorkChallengeIfNecessary(userId, - intent.getIntentSender(), notificationKey)) { - // Show work challenge, do not run pendingintent and + boolean canBypass = false; + try { + canBypass = ActivityManagerNative.getDefault() + .canBypassWorkChallenge(intent); + } catch (RemoteException e) { + } + // For direct-boot aware activities, they can be shown when + // the device is still locked without triggering the work + // challenge. + if ((!canBypass) && startWorkChallengeIfNecessary(userId, + intent.getIntentSender(), notificationKey)) { + // Show work challenge, do not run PendingIntent and // remove notification return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java index 2045ec8dfa2d..1d7bede962d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java @@ -56,6 +56,8 @@ public class DismissView extends StackScrollerDecorView { protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDismissButton.setText(R.string.clear_all_notifications_text); + mDismissButton.setContentDescription( + mContext.getString(R.string.accessibility_clear_all)); } public boolean isButtonVisible() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 68de16b2af21..caf5447d9d26 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -905,6 +905,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } public void resetTranslation() { + if (mTranslateAnim != null) { + mTranslateAnim.cancel(); + } if (mTranslateableViews != null) { for (int i = 0; i < mTranslateableViews.size(); i++) { mTranslateableViews.get(i).setTranslationX(0); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java index 88f37a320926..8b4225a8ab0b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java @@ -174,7 +174,10 @@ public class KeyguardAffordanceView extends ImageView { private void drawBackgroundCircle(Canvas canvas) { if (mCircleRadius > 0 || mFinishing) { - if (mFinishing && mSupportHardware) { + if (mFinishing && mSupportHardware && mHwCenterX != null) { + // Our hardware drawing proparties can be null if the finishing started but we have + // never drawn before. In that case we are not doing a render thread animation + // anyway, so we need to use the normal drawing. DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas; displayListCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius, mHwCirclePaint); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 9fd09d92162c..78e56c04ce9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -205,7 +205,7 @@ public class NotificationContentView extends FrameLayout { && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) { singleLineWidthSpec = MeasureSpec.makeMeasureSpec( width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(), - MeasureSpec.AT_MOST); + MeasureSpec.EXACTLY); } mSingleLineView.measure(singleLineWidthSpec, MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 93ed1398c2a6..41b0bb2c59ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -308,6 +308,7 @@ public class KeyguardStatusBarView extends RelativeLayout super.setVisibility(visibility); if (visibility != View.VISIBLE) { mSystemIconsSuperContainer.animate().cancel(); + mSystemIconsSuperContainer.setTranslationX(0); mMultiUserSwitch.animate().cancel(); mMultiUserSwitch.setAlpha(1f); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index b1bea0287ddb..9251f32099a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -664,6 +664,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private boolean mNoAnimationOnNextBarModeChange; private FalsingManager mFalsingManager; + private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() { + @Override + public void onDreamingStateChanged(boolean dreaming) { + if (dreaming) { + maybeEscalateHeadsUp(); + } + } + }; + @Override public void start() { mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) @@ -701,8 +710,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mUnlockMethodCache.addListener(this); startKeyguard(); + KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateCallback); mDozeServiceHost = new DozeServiceHost(); - KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mDozeServiceHost); putComponent(DozeHost.class, mDozeServiceHost); putComponent(PhoneStatusBar.class, this); @@ -4445,6 +4454,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } if (state == StatusBarState.KEYGUARD) { removeRemoteInputEntriesKeptUntilCollapsed(); + maybeEscalateHeadsUp(); } mState = state; mGroupManager.setStatusBarState(state); @@ -4964,7 +4974,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } - private final class DozeServiceHost extends KeyguardUpdateMonitorCallback implements DozeHost { + private final class DozeServiceHost implements DozeHost { // Amount of time to allow to update the time shown on the screen before releasing // the wakelock. This timeout is design to compensate for the fact that we don't // currently have a way to know when time display contents have actually been diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index d3ae54984e99..f6c0942d7ed0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -381,7 +381,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL } public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) { - if (mIsExpanded) { + if (mIsExpanded || mBar.isBouncerShowing()) { // The touchable region is always the full area when expanded return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java index 3c9373bd46a2..d7920a9b1e7b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java @@ -123,8 +123,10 @@ public class NotificationChildrenContainer extends ViewGroup { mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight); } if (mOverflowNumber != null) { - mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(), - mOverflowNumber.getMeasuredHeight()); + boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; + int left = (isRtl ? 0 : getWidth() - mOverflowNumber.getMeasuredWidth()); + int right = left + mOverflowNumber.getMeasuredWidth(); + mOverflowNumber.layout(left, 0, right, mOverflowNumber.getMeasuredHeight()); } if (mNotificationHeader != null) { mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index d1de38c7b9e4..5f4bd1d7c240 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -3900,6 +3900,7 @@ public class NotificationStackScrollLayout extends ViewGroup private class NotificationSwipeHelper extends SwipeHelper { private static final long SHOW_GEAR_DELAY = 60; private static final long COVER_GEAR_DELAY = 4000; + private static final long SWIPE_GEAR_TIMING = 200; private CheckForDrag mCheckForDrag; private Runnable mFalsingCheck; private Handler mHandler; @@ -4016,6 +4017,9 @@ public class NotificationStackScrollLayout extends ViewGroup boolean gestureTowardsGear = isTowardsGear(velocity, mCurrIconRow.isIconOnLeft()); boolean gestureFastEnough = Math.abs(velocity) > getEscapeVelocity(); + final double timeForGesture = ev.getEventTime() - ev.getDownTime(); + final boolean showGearForSlowOnGoing = !canChildBeDismissed(animView) + && timeForGesture >= SWIPE_GEAR_TIMING; if (mGearSnappedTo && mCurrIconRow.isVisible()) { if (mGearSnappedOnLeft == mCurrIconRow.isIconOnLeft()) { @@ -4040,7 +4044,8 @@ public class NotificationStackScrollLayout extends ViewGroup } else { dismissOrSnapBack(animView, velocity, ev); } - } else if ((!gestureFastEnough && swipedEnoughToShowGear(animView)) + } else if (((!gestureFastEnough || showGearForSlowOnGoing) + && swipedEnoughToShowGear(animView)) || gestureTowardsGear) { // Gear has not been snapped to previously and this is gear revealing gesture snapToGear(animView, velocity); @@ -4092,13 +4097,9 @@ public class NotificationStackScrollLayout extends ViewGroup final float multiplier = canChildBeDismissed(animView) ? 0.4f : 0.2f; final float snapBackThreshold = getSpaceForGear(animView) * multiplier; final float translation = getTranslation(animView); - final boolean fromLeft = translation > 0; - final float absTrans = Math.abs(translation); - final float notiThreshold = getSize(mTranslatingParentView) * 0.4f; - - return mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft() - ? (translation > snapBackThreshold && translation <= notiThreshold) - : (translation < -snapBackThreshold && translation >= -notiThreshold)); + return !swipedFarEnough() && mCurrIconRow.isVisible() && (mCurrIconRow.isIconOnLeft() + ? translation > snapBackThreshold + : translation < -snapBackThreshold); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java deleted file mode 100644 index dd78595a0aa5..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTaskLoadPlanTest.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2016 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.recents; - -import android.app.ActivityManager; -import android.content.pm.ActivityInfo; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.model.RecentsTaskLoadPlan; -import com.android.systemui.recents.model.RecentsTaskLoader; -import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.TaskStack; - -import java.util.ArrayList; - -/** - * Mock task loader that does not actually load any tasks. - */ -class MockRecentsTaskNonLoader extends RecentsTaskLoader { - @Override - public String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) { - return ""; - } - - @Override - public String getAndUpdateContentDescription(Task.TaskKey taskKey, Resources res) { - return ""; - } - - @Override - public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td, Resources res, boolean loadIfNotCached) { - return null; - } - - @Override - public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) { - return null; - } - - @Override - public int getActivityPrimaryColor(ActivityManager.TaskDescription td) { - return 0; - } - - @Override - public int getActivityBackgroundColor(ActivityManager.TaskDescription td) { - return 0; - } - - @Override - public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) { - return null; - } -} - -/** - * TODO(winsonc): - * - add test to ensure excluded tasks are loaded at the front of the list - * - add test to ensure the last visible task active time is migrated from absolute to uptime - */ -public class RecentsTaskLoadPlanTest extends SysuiTestCase { - private static final String TAG = "RecentsTaskLoadPlanTest"; - - private MockRecentsTaskNonLoader mDummyLoader = new MockRecentsTaskNonLoader(); - private SystemServicesProxy mDummySsp = new SystemServicesProxy(); - - @Override - protected void setUp() throws Exception { - super.setUp(); - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - } - - public void testEmptyRecents() { - RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getTestContext(), mDummySsp); - ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>(); - loadPlan.setInternals(tasks, 0 /* current */, 0 /* lastVisibleTaskActive */); - loadPlan.preloadPlan(mDummyLoader, 0 /* runningTaskId */, - false /* includeFrontMostExcludedTask */); - assertFalse("Expected task to be empty", loadPlan.getTaskStack().getStackTaskCount() > 0); - } - - public void testLessThanEqualMinTasks() { - RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getTestContext(), mDummySsp); - ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>(); - int minTasks = 3; - - resetTaskInfoList(tasks, - createTaskInfo(0, 1), - createTaskInfo(1, 2), - createTaskInfo(2, 3)); - - // Ensure that all tasks are loaded if the tasks are within the session and after the last - // visible active time (all tasks are loaded because there are < minTasks number of tasks) - loadPlan.setInternals(tasks, minTasks, 0 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */, - 0 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 3 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 3 /* current */, 1 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 50 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - // Ensure that only tasks are not loaded if are after the last visible active time, even if - // they are within the session - loadPlan.setInternals(tasks, minTasks, 50 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 50 /* current */, 1 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2); - - loadPlan.setInternals(tasks, minTasks, 50 /* current */, 2 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0); - assertTasksInStack(loadPlan.getTaskStack(), 1, 2); - - loadPlan.setInternals(tasks, minTasks, 50 /* current */, 3 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1); - assertTasksInStack(loadPlan.getTaskStack(), 2); - - loadPlan.setInternals(tasks, minTasks, 50 /* current */, 50 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2); - } - - public void testMoreThanMinTasks() { - RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getTestContext(), mDummySsp); - ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<>(); - int minTasks = 3; - - // Create all tasks within the session - resetTaskInfoList(tasks, - createTaskInfo(0, 1), - createTaskInfo(1, 50), - createTaskInfo(2, 100), - createTaskInfo(3, 101), - createTaskInfo(4, 102), - createTaskInfo(5, 103)); - - // Ensure that only the tasks that are within the window but after the last visible active - // time is loaded, or the minTasks number of tasks are loaded if there are less than that - - // Session window shifts - loadPlan.setInternals(tasks, minTasks, 0 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 1 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 51 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 52 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0); - assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 100 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0); - assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 101 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1); - assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 103 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1); - assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1); - assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 151 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2); - assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 200 /* current */, 0 /* lastVisibleTaskActive */, - 50 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2); - assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5); - - // Last visible active time shifts (everything is in window) - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 0 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 1 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 2 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0); - assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 50 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0); - assertTasksInStack(loadPlan.getTaskStack(), 1, 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 51 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1); - assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 100 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1); - assertTasksInStack(loadPlan.getTaskStack(), 2, 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 101 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2); - assertTasksInStack(loadPlan.getTaskStack(), 3, 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 102 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3); - assertTasksInStack(loadPlan.getTaskStack(), 4, 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 103 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4); - assertTasksInStack(loadPlan.getTaskStack(), 5); - - loadPlan.setInternals(tasks, minTasks, 150 /* current */, 104 /* lastVisibleTaskActive */, - 150 /* sessionBegin */); - loadPlan.preloadPlan(mDummyLoader, 0, false); - assertTasksNotInStack(loadPlan.getTaskStack(), 0, 1, 2, 3, 4, 5); - } - - private ActivityManager.RecentTaskInfo createTaskInfo(int taskId, long lastActiveTime) { - ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo(); - info.id = info.persistentId = taskId; - info.lastActiveTime = lastActiveTime; - return info; - } - - private void resetTaskInfoList(ArrayList<ActivityManager.RecentTaskInfo> tasks, - ActivityManager.RecentTaskInfo ... infos) { - tasks.clear(); - for (ActivityManager.RecentTaskInfo info : infos) { - tasks.add(info); - } - } - - private void assertTasksInStack(TaskStack stack, int... taskIds) { - for (int taskId : taskIds) { - assertNotNull("Expected task " + taskId + " in stack", stack.findTaskWithId(taskId)); - } - } - - private void assertTasksNotInStack(TaskStack stack, int... taskIds) { - for (int taskId : taskIds) { - assertNull("Expected task " + taskId + " not in stack", stack.findTaskWithId(taskId)); - } - } -} diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 8c5887f7a514..89fdfaf30559 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -293,7 +293,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { */ private final boolean isBluetoothPersistedStateOn() { return Settings.Global.getInt(mContentResolver, - Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF; + Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) != BLUETOOTH_OFF; } /** @@ -301,7 +301,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { */ private final boolean isBluetoothPersistedStateOnBluetooth() { return Settings.Global.getInt(mContentResolver, - Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH; + Settings.Global.BLUETOOTH_ON, BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH; } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 58431c856dcf..6b2d9df0d15c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; @@ -262,6 +263,11 @@ public class ConnectivityService extends IConnectivityManager.Stub DONT_REAP }; + private enum UnneededFor { + LINGER, // Determine whether this network is unneeded and should be lingered. + TEARDOWN, // Determine whether this network is unneeded and should be torn down. + } + /** * used internally to change our mobile data enabled flag */ @@ -691,13 +697,13 @@ public class ConnectivityService extends IConnectivityManager.Stub if (DBG) log("ConnectivityService starting up"); mMetricsLog = logger; - mDefaultRequest = createInternetRequestForTransport(-1); + mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder()); mNetworkRequests.put(mDefaultRequest, defaultNRI); mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI); mDefaultMobileDataRequest = createInternetRequestForTransport( - NetworkCapabilities.TRANSPORT_CELLULAR); + NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST); mHandlerThread = createHandlerThread(); mHandlerThread.start(); @@ -848,15 +854,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit); } - private NetworkRequest createInternetRequestForTransport(int transportType) { + private NetworkRequest createInternetRequestForTransport( + int transportType, NetworkRequest.Type type) { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED); if (transportType > -1) { netCap.addTransportType(transportType); } - return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), - NetworkRequest.Type.REQUEST); + return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type); } // Used only for testing. @@ -1970,8 +1976,12 @@ public class ConnectivityService extends IConnectivityManager.Stub for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { pw.println(nai.toString()); pw.increaseIndent(); - pw.println(String.format("Requests: %d request/%d total", - nai.numRequestNetworkRequests(), nai.numNetworkRequests())); + pw.println(String.format( + "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d", + nai.numForegroundNetworkRequests(), + nai.numNetworkRequests() - nai.numRequestNetworkRequests(), + nai.numBackgroundNetworkRequests(), + nai.numNetworkRequests())); pw.increaseIndent(); for (int i = 0; i < nai.numNetworkRequests(); i++) { pw.println(nai.requestAt(i).toString()); @@ -2130,14 +2140,10 @@ public class ConnectivityService extends IConnectivityManager.Stub case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: { final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj; if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) || - networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { + networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) || + networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) { Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability."); } - if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities( - networkCapabilities)) { - Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: " - + nai.networkCapabilities + " -> " + networkCapabilities); - } updateCapabilities(nai, networkCapabilities); break; } @@ -2292,15 +2298,13 @@ public class ConnectivityService extends IConnectivityManager.Stub // 3. If this network is unneeded (which implies it is not lingering), and there is at least // one lingered request, start lingering. nai.updateLingerTimer(); - if (nai.isLingering() && nai.numRequestNetworkRequests() > 0) { + if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) { if (DBG) log("Unlingering " + nai.name()); nai.unlinger(); logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER); - } else if (unneeded(nai) && nai.getLingerExpiry() > 0) { // unneeded() calls isLingering() + } else if (unneeded(nai, UnneededFor.LINGER) && nai.getLingerExpiry() > 0) { int lingerTime = (int) (nai.getLingerExpiry() - now); - if (DBG) { - Log.d(TAG, "Lingering " + nai.name() + " for " + lingerTime + "ms"); - } + if (DBG) log("Lingering " + nai.name() + " for " + lingerTime + "ms"); nai.linger(); logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER); notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime); @@ -2479,15 +2483,37 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - // Is nai unneeded by all NetworkRequests (and should be disconnected)? - // This is whether it is satisfying any NetworkRequests or were it to become validated, - // would it have a chance of satisfying any NetworkRequests. - private boolean unneeded(NetworkAgentInfo nai) { - if (!nai.everConnected || nai.isVPN() || - nai.isLingering() || nai.numRequestNetworkRequests() > 0) { + // Determines whether the network is the best (or could become the best, if it validated), for + // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends + // on the value of reason: + // + // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason, + // then it should be torn down. + // - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason, + // then it should be lingered. + private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) { + final int numRequests; + switch (reason) { + case TEARDOWN: + numRequests = nai.numRequestNetworkRequests(); + break; + case LINGER: + numRequests = nai.numForegroundNetworkRequests(); + break; + default: + Slog.wtf(TAG, "Invalid reason. Cannot happen."); + return true; + } + + if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) { return false; } for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) { + // Background requests don't affect lingering. + continue; + } + // If this Network is already the highest scoring Network for a request, or if // there is hope for it to become one if it validated, then it is needed. if (nri.request.isRequest() && nai.satisfies(nri.request) && @@ -2575,6 +2601,7 @@ public class ConnectivityService extends IConnectivityManager.Stub boolean wasKept = false; NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); if (nai != null) { + boolean wasBackgroundNetwork = nai.isBackgroundNetwork(); nai.removeRequest(nri.request.requestId); if (VDBG) { log(" Removing from current network " + nai.name() + @@ -2583,13 +2610,17 @@ public class ConnectivityService extends IConnectivityManager.Stub // If there are still lingered requests on this network, don't tear it down, // but resume lingering instead. updateLingerState(nai, SystemClock.elapsedRealtime()); - if (unneeded(nai)) { + if (unneeded(nai, UnneededFor.TEARDOWN)) { if (DBG) log("no live requests for " + nai.name() + "; disconnecting"); teardownUnneededNetwork(nai); } else { wasKept = true; } mNetworkForRequestId.remove(nri.request.requestId); + if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) { + // Went from foreground to background. + updateCapabilities(nai, nai.networkCapabilities); + } } // TODO: remove this code once we know that the Slog.wtf is never hit. @@ -4463,6 +4494,12 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param networkCapabilities the new network capabilities. */ private void updateCapabilities(NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) { + if (nai.everConnected && !nai.networkCapabilities.equalImmutableCapabilities( + networkCapabilities)) { + Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities: " + + nai.networkCapabilities + " -> " + networkCapabilities); + } + // Don't modify caller's NetworkCapabilities. networkCapabilities = new NetworkCapabilities(networkCapabilities); if (nai.lastValidated) { @@ -4475,21 +4512,40 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL); } - if (!Objects.equals(nai.networkCapabilities, networkCapabilities)) { - final int oldScore = nai.getCurrentScore(); - if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) != - networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { - try { - mNetd.setNetworkPermission(nai.network.netId, - networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) ? - null : NetworkManagementService.PERMISSION_SYSTEM); - } catch (RemoteException e) { - loge("Exception in setNetworkPermission: " + e); - } - } - synchronized (nai) { - nai.networkCapabilities = networkCapabilities; + if (nai.isBackgroundNetwork()) { + networkCapabilities.removeCapability(NET_CAPABILITY_FOREGROUND); + } else { + networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); + } + + if (Objects.equals(nai.networkCapabilities, networkCapabilities)) return; + + if (nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) != + networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { + try { + mNetd.setNetworkPermission(nai.network.netId, + networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) ? + null : NetworkManagementService.PERMISSION_SYSTEM); + } catch (RemoteException e) { + loge("Exception in setNetworkPermission: " + e); } + } + + final int oldScore = nai.getCurrentScore(); + final NetworkCapabilities prevNc = nai.networkCapabilities; + synchronized (nai) { + nai.networkCapabilities = networkCapabilities; + } + if (nai.getCurrentScore() == oldScore && + networkCapabilities.equalRequestableCapabilities(prevNc)) { + // If the requestable capabilities haven't changed, and the score hasn't changed, then + // the change we're processing can't affect any requests, it can only affect the listens + // on this network. We might have been called by rematchNetworkAndRequests when a + // network changed foreground state. + processListenRequests(nai, true); + } else { + // If the requestable capabilities have changed or the score changed, we can't have been + // called by rematchNetworkAndRequests, so it's safe to start a rematch. rematchAllNetworksAndRequests(nai, oldScore); notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); } @@ -4612,8 +4668,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // must be no other active linger timers, and we must stop lingering. oldNetwork.clearLingerState(); - if (unneeded(oldNetwork)) { + if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) { + // Tear the network down. teardownUnneededNetwork(oldNetwork); + } else { + // Put the network in the background. + updateCapabilities(oldNetwork, oldNetwork.networkCapabilities); } } @@ -4631,6 +4691,31 @@ public class ConnectivityService extends IConnectivityManager.Stub setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); } + private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { + // For consistency with previous behaviour, send onLost callbacks before onAvailable. + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + NetworkRequest nr = nri.request; + if (!nr.isListen()) continue; + if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) { + nai.removeRequest(nri.request.requestId); + callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0); + } + } + + if (capabilitiesChanged) { + notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); + } + + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + NetworkRequest nr = nri.request; + if (!nr.isListen()) continue; + if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) { + nai.addRequest(nr); + notifyNetworkCallback(nai, nri); + } + } + } + // Handles a network appearing or improving its score. // // - Evaluates all current NetworkRequests that can be @@ -4664,13 +4749,25 @@ public class ConnectivityService extends IConnectivityManager.Stub boolean keep = newNetwork.isVPN(); boolean isNewDefault = false; NetworkAgentInfo oldDefaultNetwork = null; + + final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork(); + final int score = newNetwork.getCurrentScore(); + if (VDBG) log("rematching " + newNetwork.name()); + // Find and migrate to this Network any NetworkRequests for // which this network is now the best. ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>(); ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>(); - if (VDBG) log(" network has: " + newNetwork.networkCapabilities); + NetworkCapabilities nc = newNetwork.networkCapabilities; + if (VDBG) log(" network has: " + nc); for (NetworkRequestInfo nri : mNetworkRequests.values()) { + // Process requests in the first pass and listens in the second pass. This allows us to + // change a network's capabilities depending on which requests it has. This is only + // correct if the change in capabilities doesn't affect whether the network satisfies + // requests or not, and doesn't affect the network's score. + if (nri.request.isListen()) continue; + final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); final boolean satisfies = newNetwork.satisfies(nri.request); if (newNetwork == currentNetwork && satisfies) { @@ -4685,22 +4782,14 @@ public class ConnectivityService extends IConnectivityManager.Stub // check if it satisfies the NetworkCapabilities if (VDBG) log(" checking if request is satisfied: " + nri.request); if (satisfies) { - if (nri.request.isListen()) { - // This is not a request, it's a callback listener. - // Add it to newNetwork regardless of score. - if (newNetwork.addRequest(nri.request)) addedRequests.add(nri); - continue; - } - // next check if it's better than any current network we're using for // this request if (VDBG) { log("currentScore = " + (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) + - ", newScore = " + newNetwork.getCurrentScore()); + ", newScore = " + score); } - if (currentNetwork == null || - currentNetwork.getCurrentScore() < newNetwork.getCurrentScore()) { + if (currentNetwork == null || currentNetwork.getCurrentScore() < score) { if (VDBG) log("rematch for " + newNetwork.name()); if (currentNetwork != null) { if (VDBG) log(" accepting network in place of " + currentNetwork.name()); @@ -4722,7 +4811,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO - this could get expensive if we have alot of requests for this // network. Think about if there is a way to reduce this. Push // netid->request mapping to each factory? - sendUpdatedScoreToFactories(nri.request, newNetwork.getCurrentScore()); + sendUpdatedScoreToFactories(nri.request, score); if (isDefaultRequest(nri)) { isNewDefault = true; oldDefaultNetwork = currentNetwork; @@ -4748,16 +4837,14 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkForRequestId.remove(nri.request.requestId); sendUpdatedScoreToFactories(nri.request, 0); } else { - if (nri.request.isRequest()) { - Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " + - newNetwork.name() + - " without updating mNetworkForRequestId or factories!"); - } + Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " + + newNetwork.name() + + " without updating mNetworkForRequestId or factories!"); } - // TODO: technically, sending CALLBACK_LOST here is - // incorrect if nri is a request (not a listen) and there - // is a replacement network currently connected that can - // satisfy it. However, the only capability that can both + // TODO: Technically, sending CALLBACK_LOST here is + // incorrect if there is a replacement network currently + // connected that can satisfy nri, which is a request + // (not a listen). However, the only capability that can both // a) be requested and b) change is NET_CAPABILITY_TRUSTED, // so this code is only incorrect for a network that loses // the TRUSTED capability, which is a rare case. @@ -4782,6 +4869,28 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) { + Slog.wtf(TAG, String.format( + "BUG: %s changed requestable capabilities during rematch: %s -> %s", + nc, newNetwork.networkCapabilities)); + } + if (newNetwork.getCurrentScore() != score) { + Slog.wtf(TAG, String.format( + "BUG: %s changed score during rematch: %d -> %d", + score, newNetwork.getCurrentScore())); + } + + // Second pass: process all listens. + if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) { + // If the network went from background to foreground or vice versa, we need to update + // its foreground state. It is safe to do this after rematching the requests because + // NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable + // capability and does not affect the network's score (see the Slog.wtf call above). + updateCapabilities(newNetwork, newNetwork.networkCapabilities); + } else { + processListenRequests(newNetwork, false); + } + // do this after the default net is switched, but // before LegacyTypeTracker sends legacy broadcasts for (NetworkRequestInfo nri : addedRequests) notifyNetworkCallback(newNetwork, nri); @@ -4859,7 +4968,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) { for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { - if (unneeded(nai)) { + if (unneeded(nai, UnneededFor.TEARDOWN)) { if (nai.getLingerExpiry() > 0) { // This network has active linger timers and no requests, but is not // lingering. Linger it. @@ -4973,6 +5082,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!networkAgent.created && (state == NetworkInfo.State.CONNECTED || (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) { + + // A network that has just connected has zero requests and is thus a foreground network. + networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND); + try { // This should never fail. Specifying an already in use NetID will cause failure. if (networkAgent.isVPN()) { @@ -5134,6 +5247,8 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest nr = networkAgent.requestAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); if (VDBG) log(" sending notification for " + nr); + // TODO: if we're in the middle of a rematch, can we send a CAP_CHANGED callback for + // a network that no longer satisfies the listen? if (nri.mPendingIntent == null) { callCallbackForRequest(nri, networkAgent, notifyType, arg1); } else { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 71ac54492cb6..8ae491707542 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -822,7 +822,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub public void onUnlockUser(final @UserIdInt int userHandle) { // Called on ActivityManager thread. mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_SYSTEM_UNLOCK_USER, - userHandle)); + userHandle /* arg1 */, 0 /* arg2 */)); } } diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 3fdccebd0228..83d374c41a51 100644 --- a/services/core/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java @@ -364,6 +364,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, listCut.get(i), resultList, userId); } + filterResults(resultList); sortResults(resultList); return resultList; } @@ -457,6 +458,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { buildResolveList(intent, categories, debug, defaultOnly, resolvedType, scheme, schemeCut, finalList, userId); } + filterResults(finalList); sortResults(finalList); if (debug) { @@ -521,6 +523,12 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { Collections.sort(results, mResolvePrioritySorter); } + /** + * Apply filtering to the results. This happens before the results are sorted. + */ + protected void filterResults(List<R> results) { + } + protected void dumpFilter(PrintWriter out, String prefix, F filter) { out.print(prefix); out.println(filter); } diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java new file mode 100644 index 000000000000..1361a3166cf0 --- /dev/null +++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accounts; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountManagerInternal; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.Log; +import android.util.PackageUtils; +import android.util.Xml; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.content.PackageMonitor; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.XmlUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class for backup and restore of account access grants. + */ +public final class AccountManagerBackupHelper { + private static final String TAG = "AccountManagerBackupHelper"; + + private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour + + private static final String TAG_PERMISSIONS = "permissions"; + private static final String TAG_PERMISSION = "permission"; + private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256"; + private static final String ATTR_PACKAGE = "package"; + private static final String ATTR_DIGEST = "digest"; + + private static final String ACCOUNT_ACCESS_GRANTS = "" + + "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", " + + AccountManagerService.GRANTS_GRANTEE_UID + + " FROM " + AccountManagerService.TABLE_ACCOUNTS + + ", " + AccountManagerService.TABLE_GRANTS + + " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID + + "=" + AccountManagerService.ACCOUNTS_ID; + + private final Object mLock = new Object(); + + private final AccountManagerService mAccountManagerService; + private final AccountManagerInternal mAccountManagerInternal; + + @GuardedBy("mLock") + private List<PendingAppPermission> mRestorePendingAppPermissions; + + @GuardedBy("mLock") + private RestorePackageMonitor mRestorePackageMonitor; + + @GuardedBy("mLock") + private Runnable mRestoreCancelCommand; + + public AccountManagerBackupHelper(AccountManagerService accountManagerService, + AccountManagerInternal accountManagerInternal) { + mAccountManagerService = accountManagerService; + mAccountManagerInternal = accountManagerInternal; + } + + private final class PendingAppPermission { + private final @NonNull String accountDigest; + private final @NonNull String packageName; + private final @NonNull String certDigest; + private final @IntRange(from = 0) int userId; + + public PendingAppPermission(String accountDigest, String packageName, + String certDigest, int userId) { + this.accountDigest = accountDigest; + this.packageName = packageName; + this.certDigest = certDigest; + this.userId = userId; + } + + public boolean apply(PackageManager packageManager) { + Account account = null; + AccountManagerService.UserAccounts accounts = mAccountManagerService + .getUserAccounts(userId); + synchronized (accounts.cacheLock) { + for (Account[] accountsPerType : accounts.accountCache.values()) { + for (Account accountPerType : accountsPerType) { + if (accountDigest.equals(PackageUtils.computeSha256Digest( + accountPerType.name.getBytes()))) { + account = accountPerType; + break; + } + } + if (account != null) { + break; + } + } + } + if (account == null) { + return false; + } + final PackageInfo packageInfo; + try { + packageInfo = packageManager.getPackageInfoAsUser(packageName, + PackageManager.GET_SIGNATURES, userId); + } catch (PackageManager.NameNotFoundException e) { + return false; + } + String currentCertDigest = PackageUtils.computeCertSha256Digest( + packageInfo.signatures[0]); + if (!certDigest.equals(currentCertDigest)) { + return false; + } + final int uid = packageInfo.applicationInfo.uid; + if (!mAccountManagerInternal.hasAccountAccess(account, uid)) { + mAccountManagerService.grantAppPermission(account, + AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid); + } + return true; + } + } + + public byte[] backupAccountAccessPermissions(int userId) { + final AccountManagerService.UserAccounts accounts = mAccountManagerService + .getUserAccounts(userId); + synchronized (accounts.cacheLock) { + SQLiteDatabase db = accounts.openHelper.getReadableDatabase(); + try ( + Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null); + ) { + if (cursor == null || !cursor.moveToFirst()) { + return null; + } + + final int nameColumnIdx = cursor.getColumnIndex( + AccountManagerService.ACCOUNTS_NAME); + final int uidColumnIdx = cursor.getColumnIndex( + AccountManagerService.GRANTS_GRANTEE_UID); + + ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); + try { + final XmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(dataStream, StandardCharsets.UTF_8.name()); + serializer.startDocument(null, true); + serializer.startTag(null, TAG_PERMISSIONS); + + PackageManager packageManager = mAccountManagerService.mContext + .getPackageManager(); + + do { + final String accountName = cursor.getString(nameColumnIdx); + final int uid = cursor.getInt(uidColumnIdx); + + final String[] packageNames = packageManager.getPackagesForUid(uid); + if (packageNames == null) { + continue; + } + + for (String packageName : packageNames) { + String digest = PackageUtils.computePackageCertSha256Digest( + packageManager, packageName, userId); + if (digest != null) { + serializer.startTag(null, TAG_PERMISSION); + serializer.attribute(null, ATTR_ACCOUNT_SHA_256, + PackageUtils.computeSha256Digest(accountName.getBytes())); + serializer.attribute(null, ATTR_PACKAGE, packageName); + serializer.attribute(null, ATTR_DIGEST, digest); + serializer.endTag(null, TAG_PERMISSION); + } + } + } while (cursor.moveToNext()); + + serializer.endTag(null, TAG_PERMISSIONS); + serializer.endDocument(); + serializer.flush(); + } catch (IOException e) { + Log.e(TAG, "Error backing up account access grants", e); + return null; + } + + return dataStream.toByteArray(); + } + } + } + + public void restoreAccountAccessPermissions(byte[] data, int userId) { + try { + ByteArrayInputStream dataStream = new ByteArrayInputStream(data); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(dataStream, StandardCharsets.UTF_8.name()); + PackageManager packageManager = mAccountManagerService.mContext.getPackageManager(); + + final int permissionsOuterDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) { + if (!TAG_PERMISSIONS.equals(parser.getName())) { + continue; + } + final int permissionOuterDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) { + if (!TAG_PERMISSION.equals(parser.getName())) { + continue; + } + String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256); + if (TextUtils.isEmpty(accountDigest)) { + XmlUtils.skipCurrentTag(parser); + } + String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); + if (TextUtils.isEmpty(packageName)) { + XmlUtils.skipCurrentTag(parser); + } + String digest = parser.getAttributeValue(null, ATTR_DIGEST); + if (TextUtils.isEmpty(digest)) { + XmlUtils.skipCurrentTag(parser); + } + + PendingAppPermission pendingAppPermission = new PendingAppPermission( + accountDigest, packageName, digest, userId); + + if (!pendingAppPermission.apply(packageManager)) { + synchronized (mLock) { + // Start watching before add pending to avoid a missed signal + if (mRestorePackageMonitor == null) { + mRestorePackageMonitor = new RestorePackageMonitor(); + mRestorePackageMonitor.register(mAccountManagerService.mContext, + mAccountManagerService.mMessageHandler.getLooper(), true); + } + if (mRestorePendingAppPermissions == null) { + mRestorePendingAppPermissions = new ArrayList<>(); + } + mRestorePendingAppPermissions.add(pendingAppPermission); + } + } + } + } + + // Make sure we eventually prune the in-memory pending restores + synchronized (mLock) { + mRestoreCancelCommand = new CancelRestoreCommand(); + } + mAccountManagerService.mMessageHandler.postDelayed(mRestoreCancelCommand, + PENDING_RESTORE_TIMEOUT_MILLIS); + } catch (XmlPullParserException | IOException e) { + Log.e(TAG, "Error restoring app permissions", e); + } + } + + private final class RestorePackageMonitor extends PackageMonitor { + @Override + public void onPackageAdded(String packageName, int uid) { + synchronized (mLock) { + // Can happen if restore is cancelled and there is a notification in flight + if (mRestorePendingAppPermissions == null) { + return; + } + if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) { + return; + } + final int count = mRestorePendingAppPermissions.size(); + for (int i = count - 1; i >= 0; i--) { + PendingAppPermission pendingAppPermission = + mRestorePendingAppPermissions.get(i); + if (!pendingAppPermission.packageName.equals(packageName)) { + continue; + } + if (pendingAppPermission.apply( + mAccountManagerService.mContext.getPackageManager())) { + mRestorePendingAppPermissions.remove(i); + } + } + if (mRestorePendingAppPermissions.isEmpty() + && mRestoreCancelCommand != null) { + mAccountManagerService.mMessageHandler.removeCallbacks(mRestoreCancelCommand); + mRestoreCancelCommand.run(); + mRestoreCancelCommand = null; + } + } + } + } + + private final class CancelRestoreCommand implements Runnable { + @Override + public void run() { + synchronized (mLock) { + mRestorePendingAppPermissions = null; + if (mRestorePackageMonitor != null) { + mRestorePackageMonitor.unregister(); + mRestorePackageMonitor = null; + } + } + } + } +} diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 2f96b20e512a..bee7fdb39813 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -26,12 +26,14 @@ import android.accounts.AccountManagerInternal; import android.accounts.AuthenticatorDescription; import android.accounts.CantAddAccountActivity; import android.accounts.GrantCredentialsPermissionActivity; +import android.accounts.IAccountAccessTracker; import android.accounts.IAccountAuthenticator; import android.accounts.IAccountAuthenticatorResponse; import android.accounts.IAccountManager; import android.accounts.IAccountManagerResponse; import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityThread; @@ -85,15 +87,16 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; -import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Log; +import android.util.PackageUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.util.ArrayUtils; @@ -125,6 +128,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -155,13 +159,6 @@ public class AccountManagerService } @Override - public void onBootPhase(int phase) { - if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { - mService.systemReady(); - } - } - - @Override public void onUnlockUser(int userHandle) { mService.onUnlockUser(userHandle); } @@ -174,13 +171,13 @@ public class AccountManagerService private static final int MAX_DEBUG_DB_SIZE = 64; - private final Context mContext; + final Context mContext; private final PackageManager mPackageManager; private final AppOpsManager mAppOpsManager; private UserManager mUserManager; - private final MessageHandler mMessageHandler; + final MessageHandler mMessageHandler; // Messages that can be sent on mHandler private static final int MESSAGE_TIMED_OUT = 3; @@ -188,9 +185,9 @@ public class AccountManagerService private final IAccountAuthenticatorCache mAuthenticatorCache; - private static final String TABLE_ACCOUNTS = "accounts"; - private static final String ACCOUNTS_ID = "_id"; - private static final String ACCOUNTS_NAME = "name"; + static final String TABLE_ACCOUNTS = "accounts"; + static final String ACCOUNTS_ID = "_id"; + static final String ACCOUNTS_NAME = "name"; private static final String ACCOUNTS_TYPE = "type"; private static final String ACCOUNTS_TYPE_COUNT = "count(type)"; private static final String ACCOUNTS_PASSWORD = "password"; @@ -204,10 +201,10 @@ public class AccountManagerService private static final String AUTHTOKENS_TYPE = "type"; private static final String AUTHTOKENS_AUTHTOKEN = "authtoken"; - private static final String TABLE_GRANTS = "grants"; - private static final String GRANTS_ACCOUNTS_ID = "accounts_id"; + static final String TABLE_GRANTS = "grants"; + static final String GRANTS_ACCOUNTS_ID = "accounts_id"; private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type"; - private static final String GRANTS_GRANTEE_UID = "uid"; + static final String GRANTS_GRANTEE_UID = "uid"; private static final String TABLE_EXTRAS = "extras"; private static final String EXTRAS_ID = "_id"; @@ -274,16 +271,16 @@ public class AccountManagerService static class UserAccounts { private final int userId; - private final DeDatabaseHelper openHelper; + final DeDatabaseHelper openHelper; private final HashMap<Pair<Pair<Account, String>, Integer>, Integer> credentialsPermissionNotificationIds = new HashMap<Pair<Pair<Account, String>, Integer>, Integer>(); private final HashMap<Account, Integer> signinRequiredNotificationIds = new HashMap<Account, Integer>(); - private final Object cacheLock = new Object(); + final Object cacheLock = new Object(); /** protected by the {@link #cacheLock} */ - private final HashMap<String, Account[]> accountCache = - new LinkedHashMap<String, Account[]>(); + final HashMap<String, Account[]> accountCache = + new LinkedHashMap<>(); /** protected by the {@link #cacheLock} */ private final HashMap<Account, HashMap<String, String>> userDataCache = new HashMap<Account, HashMap<String, String>>(); @@ -322,6 +319,8 @@ public class AccountManagerService private final SparseArray<UserAccounts> mUsers = new SparseArray<>(); private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray(); + private final CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener> + mAppPermissionChangeListeners = new CopyOnWriteArrayList<>(); private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>(); private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{}; @@ -502,7 +501,7 @@ public class AccountManagerService if (!checkAccess || hasAccountAccess(account, packageName, UserHandle.getUserHandleForUid(uid))) { cancelNotification(getCredentialPermissionNotificationId(account, - AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName, + AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName, UserHandle.getUserHandleForUid(uid)); } } @@ -522,9 +521,6 @@ public class AccountManagerService } } - public void systemReady() { - } - private UserManager getUserManager() { if (mUserManager == null) { mUserManager = UserManager.get(mContext); @@ -695,7 +691,8 @@ public class AccountManagerService final ArrayList<String> accountNames = cur.getValue(); final Account[] accountsForType = new Account[accountNames.size()]; for (int i = 0; i < accountsForType.length; i++) { - accountsForType[i] = new Account(accountNames.get(i), accountType); + accountsForType[i] = new Account(accountNames.get(i), accountType, + new AccountAccessTracker()); } accounts.accountCache.put(accountType, accountsForType); } @@ -1505,6 +1502,8 @@ public class AccountManagerService Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name); result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type); + result.putBinder(AccountManager.KEY_ACCOUNT_ACCESS_TRACKER, + resultingAccount.getAccessTracker().asBinder()); try { response.onResult(result); } catch (RemoteException e) { @@ -1857,7 +1856,7 @@ public class AccountManagerService for (Pair<Pair<Account, String>, Integer> key : accounts.credentialsPermissionNotificationIds.keySet()) { if (account.equals(key.first.first) - && AccountManager.ACCOUNT_ACCESS_TOKEN.equals(key.first.second)) { + && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) { final int uid = (Integer) key.second; mMessageHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded( account, uid, false)); @@ -3457,22 +3456,36 @@ public class AccountManagerService Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete"); try { - final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); - // Use null token which means any token. Having a token means the package - // is trusted by the authenticator, hence it is fine to access the account. - if (permissionIsGranted(account, null, uid, userId)) { - return true; - } - // In addition to the permissions required to get an auth token we also allow - // the account to be accessed by holders of the get accounts permissions. - return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName) - || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName); + return hasAccountAccess(account, packageName, uid); } catch (NameNotFoundException e) { return false; } } + private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName, + int uid) { + if (packageName == null) { + String[] packageNames = mPackageManager.getPackagesForUid(uid); + if (ArrayUtils.isEmpty(packageNames)) { + return false; + } + // For app op checks related to permissions all packages in the UID + // have the same app op state, so doesn't matter which one we pick. + packageName = packageNames[0]; + } + + // Use null token which means any token. Having a token means the package + // is trusted by the authenticator, hence it is fine to access the account. + if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) { + return true; + } + // In addition to the permissions required to get an auth token we also allow + // the account to be accessed by holders of the get accounts permissions. + return checkUidPermission(Manifest.permission.GET_ACCOUNTS_PRIVILEGED, uid, packageName) + || checkUidPermission(Manifest.permission.GET_ACCOUNTS, uid, packageName); + } + private boolean checkUidPermission(String permission, int uid, String opPackageName) { final long identity = Binder.clearCallingIdentity(); try { @@ -3548,7 +3561,7 @@ public class AccountManagerService private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException { cancelNotification(getCredentialPermissionNotificationId(account, - AccountManager.ACCOUNT_ACCESS_TOKEN, uid), packageName, + AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid), packageName, UserHandle.getUserHandleForUid(uid)); if (callback != null) { Bundle result = new Bundle(); @@ -3556,7 +3569,7 @@ public class AccountManagerService callback.sendResult(result); } } - }), AccountManager.ACCOUNT_ACCESS_TOKEN, false); + }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false); } @Override @@ -4432,7 +4445,7 @@ public class AccountManagerService } } - private class MessageHandler extends Handler { + class MessageHandler extends Handler { MessageHandler(Looper looper) { super(looper); } @@ -5583,7 +5596,7 @@ public class AccountManagerService * which is in the system. This means we don't need to protect it with permissions. * @hide */ - private void grantAppPermission(Account account, String authTokenType, int uid) { + void grantAppPermission(Account account, String authTokenType, int uid) { if (account == null || authTokenType == null) { Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception()); return; @@ -5610,6 +5623,12 @@ public class AccountManagerService cancelAccountAccessRequestNotificationIfNeeded(account, uid, true); } + + // Listeners are a final CopyOnWriteArrayList, hence no lock needed. + for (AccountManagerInternal.OnAppPermissionChangeListener listener + : mAppPermissionChangeListeners) { + mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid)); + } } /** @@ -5642,9 +5661,16 @@ public class AccountManagerService } finally { db.endTransaction(); } + cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid), new UserHandle(accounts.userId)); } + + // Listeners are a final CopyOnWriteArrayList, hence no lock needed. + for (AccountManagerInternal.OnAppPermissionChangeListener listener + : mAppPermissionChangeListeners) { + mMessageHandler.post(() -> listener.onAppPermissionChanged(account, uid)); + } } static final private String stringArrayToString(String[] value) { @@ -5683,7 +5709,7 @@ public class AccountManagerService if (accountsForType != null) { System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength); } - newAccountsForType[oldLength] = account; + newAccountsForType[oldLength] = new Account(account, new AccountAccessTracker()); accounts.accountCache.put(account.type, newAccountsForType); } @@ -5927,7 +5953,39 @@ public class AccountManagerService } } + private final class AccountAccessTracker extends IAccountAccessTracker.Stub { + @Override + public void onAccountAccessed() throws RemoteException { + final int uid = Binder.getCallingUid(); + if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) { + return; + } + final int userId = UserHandle.getCallingUserId(); + final long identity = Binder.clearCallingIdentity(); + try { + for (Account account : getAccounts(userId, mContext.getOpPackageName())) { + IAccountAccessTracker accountTracker = account.getAccessTracker(); + if (accountTracker != null && asBinder() == accountTracker.asBinder()) { + // An app just accessed the account. At this point it knows about + // it and there is not need to hide this account from the app. + if (!hasAccountAccess(account, null, uid)) { + updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, + uid, true); + } + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + } + private final class AccountManagerInternalImpl extends AccountManagerInternal { + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private AccountManagerBackupHelper mBackupHelper; + @Override public void requestAccountAccess(@NonNull Account account, @NonNull String packageName, @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) { @@ -5948,7 +6006,8 @@ public class AccountManagerService return; } - if (hasAccountAccess(account, packageName, new UserHandle(userId))) { + if (AccountManagerService.this.hasAccountAccess(account, packageName, + new UserHandle(userId))) { Bundle result = new Bundle(); result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); callback.sendResult(result); @@ -5964,7 +6023,44 @@ public class AccountManagerService } Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback); - doNotification(mUsers.get(userId), account, null, intent, packageName, userId); + final UserAccounts userAccounts; + synchronized (mUsers) { + userAccounts = mUsers.get(userId); + } + doNotification(userAccounts, account, null, intent, packageName, userId); + } + + @Override + public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) { + // Listeners are a final CopyOnWriteArrayList, hence no lock needed. + mAppPermissionChangeListeners.add(listener); + } + + @Override + public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) { + return AccountManagerService.this.hasAccountAccess(account, null, uid); + } + + @Override + public byte[] backupAccountAccessPermissions(int userId) { + synchronized (mLock) { + if (mBackupHelper == null) { + mBackupHelper = new AccountManagerBackupHelper( + AccountManagerService.this, this); + } + return mBackupHelper.backupAccountAccessPermissions(userId); + } + } + + @Override + public void restoreAccountAccessPermissions(byte[] data, int userId) { + synchronized (mLock) { + if (mBackupHelper == null) { + mBackupHelper = new AccountManagerBackupHelper( + AccountManagerService.this, this); + } + mBackupHelper.restoreAccountAccessPermissions(data, userId); + } } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ab33dbf9f80b..f65fab8d98aa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -641,7 +641,8 @@ public final class ActivityManagerService extends ActivityManagerNative boolean mDoingSetFocusedActivity; public boolean canShowErrorDialogs() { - return mShowDialogs && !mSleeping && !mShuttingDown; + return mShowDialogs && !mSleeping && !mShuttingDown + && mLockScreenShown != LOCK_SCREEN_SHOWN; } private static final class PriorityState { @@ -22197,4 +22198,22 @@ public final class ActivityManagerService extends ActivityManagerNative Binder.restoreCallingIdentity(callingId); } } + + @Override + public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException { + final int userId = intent.getCreatorUserHandle().getIdentifier(); + if (!mUserController.isUserRunningLocked(userId, ActivityManager.FLAG_AND_LOCKED)) { + return false; + } + IIntentSender target = intent.getTarget(); + if (!(target instanceof PendingIntentRecord)) { + return false; + } + final PendingIntentRecord record = (PendingIntentRecord) target; + final ResolveInfo rInfo = mStackSupervisor.resolveIntent(record.key.requestIntent, + record.key.requestResolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE); + // For direct boot aware activities, they can be shown without triggering a work challenge + // before the profile user is unlocked. + return rInfo != null && rInfo.activityInfo != null; + } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index f374c09db285..589563333dfa 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -17,6 +17,7 @@ package com.android.server.am; import static android.app.ActivityManager.StackId; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; @@ -946,21 +947,29 @@ final class ActivityRecord { // The activity now gets access to the data associated with this Intent. service.grantUriPermissionFromIntentLocked(callingUid, packageName, intent, getUriPermissionsLocked(), userId); - // We want to immediately deliver the intent to the activity if - // it is currently the top resumed activity... however, if the - // device is sleeping, then all activities are stopped, so in that - // case we will deliver it if this is the current top activity on its - // stack. final ReferrerIntent rintent = new ReferrerIntent(intent, referrer); boolean unsent = true; - if ((state == ActivityState.RESUMED - || (service.isSleepingLocked() && task.stack != null - && task.stack.topRunningActivityLocked() == this)) - && app != null && app.thread != null) { + final ActivityStack stack = task.stack; + final boolean isTopActivityInStack = + stack != null && stack.topRunningActivityLocked() == this; + final boolean isTopActivityWhileSleeping = + service.isSleepingLocked() && isTopActivityInStack; + final boolean isTopActivityInMinimizedDockedStack = isTopActivityInStack + && stack.mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized + && state == ActivityState.PAUSED; + + // We want to immediately deliver the intent to the activity if: + // - It is the resumed activity. + // - The device is sleeping and it is the top activity behind the lock screen (b/6700897). + // - It is the top activity in a minimized docked stack. In this case the activity will be + // temporarily resumed then paused again on the client side. + if ((state == ActivityState.RESUMED || isTopActivityWhileSleeping + || isTopActivityInMinimizedDockedStack) && app != null && app.thread != null) { try { ArrayList<ReferrerIntent> ar = new ArrayList<>(1); ar.add(rintent); - app.thread.scheduleNewIntent(ar, appToken); + app.thread.scheduleNewIntent( + ar, appToken, isTopActivityInMinimizedDockedStack /* andPause */); unsent = false; } catch (RemoteException e) { Slog.w(TAG, "Exception thrown sending new intent to " + this, e); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index b4303c50296c..60d3d1ec349b 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1308,7 +1308,9 @@ final class ActivityStack { // It is possible the activity was freezing the screen before it was paused. // In that case go ahead and remove the freeze this activity has on the screen // since it is no longer visible. - prev.stopFreezingScreenLocked(true /*force*/); + if (prev != null) { + prev.stopFreezingScreenLocked(true /*force*/); + } mPausingActivity = null; } @@ -2493,7 +2495,8 @@ final class ActivityStack { break; } } - next.app.thread.scheduleNewIntent(next.newIntents, next.appToken); + next.app.thread.scheduleNewIntent( + next.newIntents, next.appToken, false /* andPause */); } // Well the app will no longer be stopped. diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java index f26e47e934c4..d719c586f6c5 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java @@ -29,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.KeyguardManager; import android.app.admin.DevicePolicyManagerInternal; @@ -210,6 +211,11 @@ class ActivityStartInterceptor { if (!mService.mUserController.shouldConfirmCredentials(userId)) { return null; } + // Allow direct boot aware activity to be displayed before the user is unlocked. + if (aInfo.directBootAware && mService.mUserController.isUserRunningLocked(userId, + ActivityManager.FLAG_AND_LOCKED)) { + return null; + } final IIntentSender target = mService.getIntentSenderLocked( INTENT_SENDER_ACTIVITY, callingPackage, Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent }, diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 576f2b27f111..0c67c75dc3e8 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -22,7 +22,6 @@ import com.android.internal.logging.MetricsProto; import com.android.internal.os.ProcessCpuTracker; import com.android.server.Watchdog; -import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityThread; @@ -33,10 +32,7 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageDataObserver; -import android.content.pm.PackageManager; import android.os.Binder; -import android.os.Bundle; import android.os.Message; import android.os.Process; import android.os.RemoteException; @@ -59,7 +55,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Set; -import java.util.concurrent.Semaphore; import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; @@ -359,7 +354,7 @@ class AppErrors { return; } - Message msg = Message.obtain(); + final Message msg = Message.obtain(); msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG; task = data.task; diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index 6cdabaac361f..43eb251ba23b 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -17,7 +17,6 @@ package com.android.server.am; import android.annotation.NonNull; -import android.content.ContentResolver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Debug; @@ -25,7 +24,6 @@ import android.os.Environment; import android.os.FileUtils; import android.os.Process; import android.os.SystemClock; -import android.provider.Settings; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Slog; @@ -82,7 +80,7 @@ public class TaskPersister { private static final String PERSISTED_TASK_IDS_FILENAME = "persisted_taskIds.txt"; static final String IMAGE_EXTENSION = ".png"; - @VisibleForTesting static final String TAG_TASK = "task"; + private static final String TAG_TASK = "task"; private final ActivityManagerService mService; private final ActivityStackSupervisor mStackSupervisor; @@ -409,43 +407,18 @@ public class TaskPersister { return null; } - @VisibleForTesting List<TaskRecord> restoreTasksForUserLocked(final int userId) { final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>(); ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>(); File userTasksDir = getUserTasksDir(userId); + File[] recentFiles = userTasksDir.listFiles(); if (recentFiles == null) { Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir); return tasks; } - // Get the last persist uptime so we know how to adjust the first/last active times for each - // task - ContentResolver cr = mService.mContext.getContentResolver(); - long lastPersistUptime = Settings.Secure.getLong(cr, - Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0); - if (DEBUG) { - Slog.d(TaskPersister.TAG, "restoreTasksForUserLocked: lastPersistUptime=" + - lastPersistUptime); - } - - // Adjust the overview last visible task active time as we adjust the task active times when - // loading. See TaskRecord.restoreFromXml(). If we have not migrated yet, SystemUI will - // migrate the old value into the system setting. - if (lastPersistUptime > 0) { - long overviewLastActiveTime = Settings.Secure.getLongForUser(cr, - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, 0, userId); - if (DEBUG) { - Slog.d(TaskPersister.TAG, "restoreTasksForUserLocked: overviewLastActiveTime=" + - overviewLastActiveTime + " lastPersistUptime=" + lastPersistUptime); - } - Settings.Secure.putLongForUser(cr, - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, - -lastPersistUptime + overviewLastActiveTime, userId); - } - for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) { File taskFile = recentFiles[taskNdx]; if (DEBUG) { @@ -466,11 +439,15 @@ public class TaskPersister { if (event == XmlPullParser.START_TAG) { if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name); if (TAG_TASK.equals(name)) { - final TaskRecord task = TaskRecord.restoreFromXml(in, mService, - mStackSupervisor, lastPersistUptime); + final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor); if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: restored task=" + task); if (task != null) { + // XXX Don't add to write queue... there is no reason to write + // out the stuff we just read, if we don't write it we will + // read the same thing again. + // mWriteQueue.add(new TaskWriteQueueItem(task)); + final int taskId = task.taskId; if (mStackSupervisor.anyTaskForIdLocked(taskId, /* restoreFromRecents= */ false, 0) != null) { @@ -486,12 +463,6 @@ public class TaskPersister { task.isPersistable = true; tasks.add(task); recoveredTaskIds.add(taskId); - - // We've shifted the first and last active times, so we need to - // persist the new task data to disk otherwise they will not - // have the updated values. This is only done once whenever - // the recents are first loaded for the user. - wakeup(task, false); } } else { Slog.e(TAG, "restoreTasksForUserLocked: Unable to restore taskFile=" @@ -780,15 +751,6 @@ public class TaskPersister { } } } - - // Always update the task persister uptime when updating any tasks - if (DEBUG) { - Slog.d(TAG, "LazyTaskWriter: Updating last write uptime=" + - SystemClock.elapsedRealtime()); - } - Settings.Secure.putLong(mService.mContext.getContentResolver(), - Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, - SystemClock.elapsedRealtime()); } } } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index b3d802778c94..3f6db990a5b5 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -39,14 +39,12 @@ import android.graphics.Rect; import android.os.Debug; import android.os.ParcelFileDescriptor; import android.os.RemoteException; -import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; import android.util.DisplayMetrics; import android.util.Slog; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; import com.android.internal.util.XmlUtils; @@ -152,10 +150,8 @@ final class TaskRecord { ComponentName realActivity; // The actual activity component that started the task. boolean realActivitySuspended; // True if the actual activity component that started the // task is suspended. - long firstActiveTime; // First time this task was active, relative to boot time. This can be - // negative if this task was last used prior to boot. - long lastActiveTime; // Last time this task was active, relative to boot time. This can be - // negative if this task was last used prior to boot. + long firstActiveTime; // First time this task was active. + long lastActiveTime; // Last time this task was active, including sleep. boolean inRecents; // Actually in the recents list? boolean isAvailable; // Is the activity available to be launched? boolean rootWasReset; // True if the intent at the root of the task had @@ -381,14 +377,14 @@ final class TaskRecord { } void touchActiveTime() { - lastActiveTime = SystemClock.elapsedRealtime(); + lastActiveTime = System.currentTimeMillis(); if (firstActiveTime == 0) { firstActiveTime = lastActiveTime; } } long getInactiveDuration() { - return SystemClock.elapsedRealtime() - lastActiveTime; + return System.currentTimeMillis() - lastActiveTime; } /** Sets the original intent, and the calling uid and package. */ @@ -459,9 +455,8 @@ final class TaskRecord { rootWasReset = true; } userId = UserHandle.getUserId(info.applicationInfo.uid); - mUserSetupComplete = mService != null && - Settings.Secure.getIntForUser(mService.mContext.getContentResolver(), - USER_SETUP_COMPLETE, 0, userId) != 0; + mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(), + USER_SETUP_COMPLETE, 0, userId) != 0; if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { // If the activity itself has requested auto-remove, then just always do it. autoRemoveRecents = true; @@ -1173,9 +1168,7 @@ final class TaskRecord { if (lastTaskDescription != null) { lastTaskDescription.saveToXml(out); } - if (mLastThumbnailInfo != null) { - mLastThumbnailInfo.saveToXml(out); - } + mLastThumbnailInfo.saveToXml(out); out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); @@ -1197,11 +1190,9 @@ final class TaskRecord { out.endTag(null, TAG_AFFINITYINTENT); } - if (intent != null) { - out.startTag(null, TAG_INTENT); - intent.saveToXml(out); - out.endTag(null, TAG_INTENT); - } + out.startTag(null, TAG_INTENT); + intent.saveToXml(out); + out.endTag(null, TAG_INTENT); final ArrayList<ActivityRecord> activities = mActivities; final int numActivities = activities.size(); @@ -1220,9 +1211,8 @@ final class TaskRecord { } } - static TaskRecord restoreFromXml(XmlPullParser in, ActivityManagerService service, - ActivityStackSupervisor stackSupervisor, long lastPersistUptime) - throws IOException, XmlPullParserException { + static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) + throws IOException, XmlPullParserException { Intent intent = null; Intent affinityIntent = null; ArrayList<ActivityRecord> activities = new ArrayList<>(); @@ -1335,31 +1325,6 @@ final class TaskRecord { } } - if (lastPersistUptime > 0) { - if (TaskPersister.DEBUG) { - Slog.d(TaskPersister.TAG, "TaskRecord: Adjust firstActiveTime=" + firstActiveTime + - " lastPersistUptime=" + lastPersistUptime); - Slog.d(TaskPersister.TAG, "TaskRecord: Migrate lastActiveTime=" + lastActiveTime + - " lastActiveTime=" + lastPersistUptime); - } - // The first and last task active times are relative to the last boot time, so offset - // them to be prior to the current boot time - firstActiveTime = -lastPersistUptime + firstActiveTime; - lastActiveTime = -lastPersistUptime + lastActiveTime; - } else { - // The first/last active times are still absolute clock times, so offset them to be - // relative to the current boot time - long currentTime = System.currentTimeMillis(); - if (TaskPersister.DEBUG) { - Slog.d(TaskPersister.TAG, "TaskRecord: Migrate firstActiveTime=" + firstActiveTime + - " currentTime=" + currentTime); - Slog.d(TaskPersister.TAG, "TaskRecord: Migrate lastActiveTime=" + lastActiveTime + - " currentTime=" + currentTime); - } - firstActiveTime = -Math.max(0, currentTime - firstActiveTime); - lastActiveTime = -Math.max(0, currentTime - lastActiveTime); - } - int event; while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { @@ -1409,7 +1374,7 @@ final class TaskRecord { + ": effectiveUid=" + effectiveUid); } - final TaskRecord task = new TaskRecord(service, taskId, intent, + final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription, activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, @@ -1812,7 +1777,7 @@ final class TaskRecord { pw.print(prefix + "hasBeenVisible=" + hasBeenVisible); pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode)); pw.print(" isResizeable=" + isResizeable()); - pw.print(" firstActiveTime=" + firstActiveTime); + pw.print(" firstActiveTime=" + lastActiveTime); pw.print(" lastActiveTime=" + lastActiveTime); pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); } diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java index 6e371c1138ca..0aa54d910ea7 100644 --- a/services/core/java/com/android/server/am/UriPermission.java +++ b/services/core/java/com/android/server/am/UriPermission.java @@ -19,6 +19,7 @@ package com.android.server.am; import android.content.Intent; import android.os.UserHandle; import android.util.ArraySet; +import android.util.Log; import android.util.Slog; import com.android.server.am.ActivityManagerService.GrantUri; @@ -93,7 +94,16 @@ final class UriPermission { } private void updateModeFlags() { + final int oldModeFlags = modeFlags; modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags; + + if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) { + Slog.d(TAG, + "Permission for " + targetPkg + " to " + uri + " is changing from 0x" + + Integer.toHexString(oldModeFlags) + " to 0x" + + Integer.toHexString(modeFlags), + new Throwable()); + } } /** diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 275870e3d4b0..b4606bb652cf 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -206,7 +206,6 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; private static final int MSG_SET_ALL_VOLUMES = 10; private static final int MSG_REPORT_NEW_ROUTES = 12; - private static final int MSG_SET_FORCE_BT_A2DP_USE = 13; private static final int MSG_CHECK_MUSIC_ACTIVE = 14; private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15; private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16; @@ -512,6 +511,10 @@ public class AudioService extends IAudioService.Stub { // Request to override default use of A2DP for media. private boolean mBluetoothA2dpEnabled; + // FIXME: remove when MediaRouter does not use setBluetoothA2dpOn() anymore + // state of bluetooth A2DP enable request sen by deprecated APIs setBluetoothA2dpOn() and + // isBluettohA2dpOn() + private boolean mBluetoothA2dpEnabledExternal; private final Object mBluetoothA2dpEnabledLock = new Object(); // Monitoring of audio routes. Protected by mCurAudioRoutes. @@ -2706,22 +2709,23 @@ public class AudioService extends IAudioService.Stub { return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); } - /** @see AudioManager#setBluetoothA2dpOn(boolean) */ + /** + * Deprecated. + * Keep stub implementation until MediaRouter stops using it. + * @deprecated + * */ public void setBluetoothA2dpOn(boolean on) { - synchronized (mBluetoothA2dpEnabledLock) { - mBluetoothA2dpEnabled = on; - sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, - AudioSystem.FOR_MEDIA, - mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, - null, 0); - } + mBluetoothA2dpEnabledExternal = on; + Log.e(TAG, "setBluetoothA2dpOn() is deprecated, now a no-op", + new Exception("Deprecated use of setBluetoothA2dpOn()")); } - /** @see AudioManager#isBluetoothA2dpOn() */ + /** Deprecated. + * Keep stub implementation until MediaRouter stops using it + * @deprecated + * */ public boolean isBluetoothA2dpOn() { - synchronized (mBluetoothA2dpEnabledLock) { - return mBluetoothA2dpEnabled; - } + return mBluetoothA2dpEnabledExternal; } /** @see AudioManager#startBluetoothSco() */ @@ -3792,6 +3796,11 @@ public class AudioService extends IAudioService.Stub { Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:" + address + ")"); } + if ((state == 0) && ((type == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || + (type == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) || + (type == AudioSystem.DEVICE_OUT_LINE))) { + setBluetoothA2dpOnInt(true); + } int delay = checkSendBecomingNoisyIntent(type, state); queueMsgUnderWakeLock(mAudioHandler, MSG_SET_WIRED_DEVICE_CONNECTION_STATE, @@ -4603,7 +4612,6 @@ public class AudioService extends IAudioService.Stub { break; case MSG_SET_FORCE_USE: - case MSG_SET_FORCE_BT_A2DP_USE: setForceUse(msg.arg1, msg.arg2); break; @@ -5011,6 +5019,7 @@ public class AudioService extends IAudioService.Stub { devices |= dev; } } + if (devices == device) { sendMsg(mAudioHandler, MSG_BROADCAST_AUDIO_BECOMING_NOISY, @@ -5106,11 +5115,6 @@ public class AudioService extends IAudioService.Stub { } synchronized (mConnectedDevices) { - if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || - (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) || - (device == AudioSystem.DEVICE_OUT_LINE))) { - setBluetoothA2dpOnInt(true); - } boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) || (((device & AudioSystem.DEVICE_BIT_IN) != 0) && ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0)); @@ -5594,7 +5598,6 @@ public class AudioService extends IAudioService.Stub { public void setBluetoothA2dpOnInt(boolean on) { synchronized (mBluetoothA2dpEnabledLock) { mBluetoothA2dpEnabled = on; - mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE); setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA, mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); } diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index 49be879b93c7..cc18114120eb 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -40,9 +40,9 @@ public class FocusRequester { private static final String TAG = "MediaFocusControl"; private static final boolean DEBUG = false; - private AudioFocusDeathHandler mDeathHandler; - private final IAudioFocusDispatcher mFocusDispatcher; // may be null - private final IBinder mSourceRef; + private AudioFocusDeathHandler mDeathHandler; // may be null + private IAudioFocusDispatcher mFocusDispatcher; // may be null + private final IBinder mSourceRef; // may be null private final String mClientId; private final String mPackageName; private final int mCallingUid; @@ -205,6 +205,7 @@ public class FocusRequester { if (mSourceRef != null && mDeathHandler != null) { mSourceRef.unlinkToDeath(mDeathHandler, 0); mDeathHandler = null; + mFocusDispatcher = null; } } catch (java.util.NoSuchElementException e) { Log.e(TAG, "FocusRequester.release() hit ", e); @@ -275,12 +276,13 @@ public class FocusRequester { mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE; mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(), AudioManager.AUDIOFOCUS_REQUEST_GRANTED); - if (mFocusDispatcher != null) { + final IAudioFocusDispatcher fd = mFocusDispatcher; + if (fd != null) { if (DEBUG) { Log.v(TAG, "dispatching " + focusChangeToString(focusGain) + " to " + mClientId); } - mFocusDispatcher.dispatchAudioFocusChange(focusGain, mClientId); + fd.dispatchAudioFocusChange(focusGain, mClientId); } } catch (android.os.RemoteException e) { Log.e(TAG, "Failure to signal gain of audio focus due to: ", e); @@ -311,14 +313,15 @@ public class FocusRequester { toAudioFocusInfo(), false /* wasDispatched */); return; } - if (mFocusDispatcher != null) { + final IAudioFocusDispatcher fd = mFocusDispatcher; + if (fd != null) { if (DEBUG) { Log.v(TAG, "dispatching " + focusChangeToString(mFocusLossReceived) + " to " + mClientId); } mFocusController.notifyExtPolicyFocusLoss_syncAf( toAudioFocusInfo(), true /* wasDispatched */); - mFocusDispatcher.dispatchAudioFocusChange(mFocusLossReceived, mClientId); + fd.dispatchAudioFocusChange(mFocusLossReceived, mClientId); } } } catch (android.os.RemoteException e) { diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java index 278d70b2226d..206834e9adc4 100644 --- a/services/core/java/com/android/server/audio/MediaFocusControl.java +++ b/services/core/java/com/android/server/audio/MediaFocusControl.java @@ -160,6 +160,7 @@ public class MediaFocusControl { Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for " + clientToRemove); stackIterator.remove(); + // stack entry not used anymore, clear references fr.release(); } } @@ -171,7 +172,7 @@ public class MediaFocusControl { * Called synchronized on mAudioFocusLock * Remove focus listeners from the focus stack for a particular client when it has died. */ - private void removeFocusStackEntryForClient(IBinder cb) { + private void removeFocusStackEntryOnDeath(IBinder cb) { // is the owner of the audio focus part of the client to remove? boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && mFocusStack.peek().hasSameBinder(cb); @@ -181,9 +182,10 @@ public class MediaFocusControl { while(stackIterator.hasNext()) { FocusRequester fr = stackIterator.next(); if(fr.hasSameBinder(cb)) { - Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for " + cb); + Log.i(TAG, "AudioFocus removeFocusStackEntryOnDeath(): removing entry for " + cb); stackIterator.remove(); - // the client just died, no need to unlink to its death + // stack entry not used anymore, clear references + fr.release(); } } if (isTopOfStackForClientToRemove) { @@ -257,14 +259,9 @@ public class MediaFocusControl { public void binderDied() { synchronized(mAudioFocusLock) { - Log.w(TAG, " AudioFocus audio focus client died"); - removeFocusStackEntryForClient(mCb); + removeFocusStackEntryOnDeath(mCb); } } - - public IBinder getBinder() { - return mCb; - } } /** @@ -420,6 +417,7 @@ public class MediaFocusControl { // (premature death == death before abandoning focus) // Register for client death notification AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); + try { cb.linkToDeath(afdh, 0); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index b0330b94a678..e750fecbeb34 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -104,14 +104,16 @@ import java.util.TreeSet; // ----------------------------------------------- // If a network has no chance of satisfying any requests (even if it were to become validated // and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel. -// If the network ever for any period of time had satisfied a NetworkRequest (i.e. had been -// the highest scoring that satisfied the NetworkRequest's constraints), but is no longer the -// highest scoring network for any NetworkRequest, then there will be a 30s pause before -// ConnectivityService disconnects the NetworkAgent's AsyncChannel. During this pause the -// network is considered "lingering". This pause exists to allow network communication to be -// wrapped up rather than abruptly terminated. During this pause if the network begins satisfying -// a NetworkRequest, ConnectivityService will cancel the future disconnection of the NetworkAgent's -// AsyncChannel, and the network is no longer considered "lingering". +// +// If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that +// satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any +// foreground NetworkRequest, then there will be a 30s pause to allow network communication to be +// wrapped up rather than abruptly terminated. During this pause the network is said to be +// "lingering". During this pause if the network begins satisfying a foreground NetworkRequest, +// ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and +// the network is no longer considered "lingering". After the linger timer expires, if the network +// is satisfying one or more background NetworkRequests it is kept up in the background. If it is +// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel. public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public NetworkInfo networkInfo; // This Network object should always be used if possible, so as to encourage reuse of the @@ -227,11 +229,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // The list of NetworkRequests being satisfied by this Network. private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); - // The list of NetworkRequests that this Network previously satisfied with the highest - // score. A non-empty list indicates that if this Network was validated it is lingered. + // How many of the satisfied requests are actual requests and not listens. private int mNumRequestNetworkRequests = 0; + // How many of the satisfied requests are of type BACKGROUND_REQUEST. + private int mNumBackgroundNetworkRequests = 0; + public final Messenger messenger; public final AsyncChannel asyncChannel; @@ -265,6 +269,32 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // // These functions must only called on ConnectivityService's main thread. + private static final boolean ADD = true; + private static final boolean REMOVE = false; + + private void updateRequestCounts(boolean add, NetworkRequest request) { + int delta = add ? +1 : -1; + switch (request.type) { + case REQUEST: + case TRACK_DEFAULT: + mNumRequestNetworkRequests += delta; + break; + + case BACKGROUND_REQUEST: + mNumRequestNetworkRequests += delta; + mNumBackgroundNetworkRequests += delta; + break; + + case LISTEN: + break; + + case NONE: + default: + Log.wtf(TAG, "Unhandled request type " + request.type); + break; + } + } + /** * Add {@code networkRequest} to this network as it's satisfied by this network. * @return true if {@code networkRequest} was added or false if {@code networkRequest} was @@ -273,9 +303,15 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public boolean addRequest(NetworkRequest networkRequest) { NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId); if (existing == networkRequest) return false; - if (existing != null && existing.isRequest()) mNumRequestNetworkRequests--; + if (existing != null) { + // Should only happen if the requestId wraps. If that happens lots of other things will + // be broken as well. + Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s", + networkRequest, existing, name())); + updateRequestCounts(REMOVE, existing); + } mNetworkRequests.put(networkRequest.requestId, networkRequest); - if (networkRequest.isRequest()) mNumRequestNetworkRequests++; + updateRequestCounts(ADD, networkRequest); return true; } @@ -285,9 +321,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { public void removeRequest(int requestId) { NetworkRequest existing = mNetworkRequests.get(requestId); if (existing == null) return; + updateRequestCounts(REMOVE, existing); mNetworkRequests.remove(requestId); if (existing.isRequest()) { - mNumRequestNetworkRequests--; unlingerRequest(existing); } } @@ -316,12 +352,37 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } /** + * Returns the number of requests currently satisfied by this network of type + * {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}. + */ + public int numBackgroundNetworkRequests() { + return mNumBackgroundNetworkRequests; + } + + /** + * Returns the number of foreground requests currently satisfied by this network. + */ + public int numForegroundNetworkRequests() { + return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests; + } + + /** * Returns the number of requests of any type currently satisfied by this network. */ public int numNetworkRequests() { return mNetworkRequests.size(); } + /** + * Returns whether the network is a background network. A network is a background network if it + * is satisfying no foreground requests and at least one background request. (If it did not have + * a background request, it would be a speculative network that is only being kept up because + * it might satisfy a request if it validated). + */ + public boolean isBackgroundNetwork() { + return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0; + } + // Does this network satisfy request? public boolean satisfies(NetworkRequest request) { return created && diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 12955f5771d2..4e236d164a69 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -482,7 +482,7 @@ public final class ContentService extends IContentService.Stub { SyncManager syncManager = getSyncManager(); if (syncManager != null) { syncManager.scheduleSync(account, userId, uId, authority, extras, - false /* onlyThoseWithUnkownSyncableState */); + SyncStorageEngine.AuthorityInfo.UNDEFINED); } } finally { restoreCallingIdentity(identityToken); @@ -548,7 +548,7 @@ public final class ContentService extends IContentService.Stub { } else { syncManager.scheduleSync( request.getAccount(), userId, callerUid, request.getProvider(), extras, - false /* onlyThoseWithUnknownSyncableState */); + SyncStorageEngine.AuthorityInfo.UNDEFINED); } } finally { restoreCallingIdentity(identityToken); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 705eae677d2b..6870c56c2ef0 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -48,6 +48,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.ProviderInfo; import android.content.pm.RegisteredServicesCache; import android.content.pm.RegisteredServicesCacheListener; @@ -324,6 +325,8 @@ public class SyncManager { private final AccountManagerInternal mAccountManagerInternal; + private final PackageManagerInternal mPackageManagerInternal; + private List<UserInfo> getAllUsers() { return mUserManager.getUsers(); } @@ -504,7 +507,7 @@ public class SyncManager { @Override public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) { scheduleSync(info.account, info.userId, reason, info.provider, extras, - false); + AuthorityInfo.UNDEFINED); } }); @@ -534,7 +537,7 @@ public class SyncManager { if (!removed) { scheduleSync(null, UserHandle.USER_ALL, SyncOperation.REASON_SERVICE_CHANGED, - type.authority, null, false /* onlyThoseWithUnkownSyncableState */); + type.authority, null, AuthorityInfo.UNDEFINED); } } }, mSyncHandler); @@ -575,6 +578,16 @@ public class SyncManager { mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE); mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class); + mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); + + mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> { + // If the UID gained access to the account kick-off syncs lacking account access + if (mAccountManagerInternal.hasAccountAccess(account, uid)) { + scheduleSync(account, UserHandle.getUserId(uid), + SyncOperation.REASON_ACCOUNTS_UPDATED, + null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS); + } + }); mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( BatteryStats.SERVICE_NAME)); @@ -671,7 +684,7 @@ public class SyncManager { service.type.accountType, userHandle)) { if (!canAccessAccount(account, packageName, userId)) { mAccountManager.updateAppPermission(account, - AccountManager.ACCOUNT_ACCESS_TOKEN, service.uid, true); + AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true); } } } @@ -778,10 +791,11 @@ public class SyncManager { * @param extras a Map of SyncAdapter-specific information to control * syncs of a specific provider. Can be null. Is ignored * if the url is null. - * @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state. + * @param targetSyncState Only sync authorities that have the specified sync state. + * Use {@link AuthorityInfo#UNDEFINED} to sync all authorities. */ public void scheduleSync(Account requestedAccount, int userId, int reason, - String requestedAuthority, Bundle extras, boolean onlyThoseWithUnkownSyncableState) { + String requestedAuthority, Bundle extras, int targetSyncState) { final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (extras == null) { extras = new Bundle(); @@ -881,14 +895,18 @@ public class SyncManager { + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS"); } Bundle finalExtras = new Bundle(extras); + String packageName = syncAdapterInfo.componentName.getPackageName(); + // If the app did not run and has no account access, done + if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) { + continue; + } mAccountManagerInternal.requestAccountAccess(account.account, - syncAdapterInfo.componentName.getPackageName(), - UserHandle.getUserId(owningUid), + packageName, userId, new RemoteCallback((Bundle result) -> { if (result != null && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) { scheduleSync(account.account, userId, reason, authority, - finalExtras, onlyThoseWithUnkownSyncableState); + finalExtras, targetSyncState); } } )); @@ -903,9 +921,10 @@ public class SyncManager { isSyncable = AuthorityInfo.SYNCABLE; } - if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) { + if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) { continue; } + if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) { continue; } @@ -931,7 +950,7 @@ public class SyncManager { final String owningPackage = syncAdapterInfo.componentName.getPackageName(); - if (isSyncable < 0) { + if (isSyncable == AuthorityInfo.NOT_INITIALIZED) { // Initialisation sync. Bundle newExtras = new Bundle(); newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); @@ -950,8 +969,8 @@ public class SyncManager { owningUid, owningPackage, reason, source, authority, newExtras, allowParallelSyncs) ); - } - if (!onlyThoseWithUnkownSyncableState) { + } else if (targetSyncState == AuthorityInfo.UNDEFINED + || targetSyncState == isSyncable) { if (isLoggable) { Slog.v(TAG, "scheduleSync:" + " delay until " + delayUntil @@ -1076,7 +1095,7 @@ public class SyncManager { final Bundle extras = new Bundle(); extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true); scheduleSync(account, userId, reason, authority, extras, - false /* onlyThoseWithUnkownSyncableState */); + AuthorityInfo.UNDEFINED); } public SyncAdapterType[] getSyncAdapterTypes(int userId) { @@ -1535,7 +1554,7 @@ public class SyncManager { mContext.getOpPackageName()); for (Account account : accounts) { scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null, - true /* onlyThoseWithUnknownSyncableState */); + AuthorityInfo.NOT_INITIALIZED); } } @@ -2714,7 +2733,8 @@ public class SyncManager { if (syncTargets != null) { scheduleSync(syncTargets.account, syncTargets.userId, - SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, null, true); + SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider, + null, AuthorityInfo.NOT_INITIALIZED); } } @@ -2786,9 +2806,14 @@ public class SyncManager { final int syncOpState = computeSyncOpState(op); switch (syncOpState) { case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: { + String packageName = op.owningPackage; + final int userId = UserHandle.getUserId(op.owningUid); + // If the app did not run and has no account access, done + if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) { + return; + } mAccountManagerInternal.requestAccountAccess(op.target.account, - op.owningPackage, UserHandle.getUserId(op.owningUid), - new RemoteCallback((Bundle result) -> { + packageName, userId, new RemoteCallback((Bundle result) -> { if (result != null && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) { updateOrAddPeriodicSync(target, pollFrequency, flex, extras); diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index 8289bae8793b..069ae7394319 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -211,6 +211,12 @@ public class SyncStorageEngine extends Handler { public static class AuthorityInfo { // Legal values of getIsSyncable + + /** + * The syncable state is undefined. + */ + public static final int UNDEFINED = -2; + /** * Default state for a newly installed adapter. An uninitialized adapter will receive an * initialization sync which are governed by a different set of rules to that of regular diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 7626e2af36e4..3e1c529a5fc6 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -90,6 +90,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.Manifest; import android.annotation.IntDef; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -290,6 +291,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_UPDATE_INTERFACE_QUOTA = 10; private static final int MSG_REMOVE_INTERFACE_QUOTA = 11; private static final int MSG_RESTRICT_BACKGROUND_BLACKLIST_CHANGED = 12; + private static final int MSG_SET_FIREWALL_RULES = 13; private final Context mContext; private final IActivityManager mActivityManager; @@ -715,6 +717,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { synchronized (mUidRulesFirstLock) { updatePowerSaveWhitelistUL(); updateRulesForRestrictPowerUL(); + updateRulesForAppIdleUL(); } } }; @@ -1439,8 +1442,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + "; generating default policy"); // Build default mobile policy, and assume usage cycle starts today - final long warningBytes = mContext.getResources().getInteger( - com.android.internal.R.integer.config_networkPolicyDefaultWarning) * MB_IN_BYTES; + final int dataWarningConfig = mContext.getResources().getInteger( + com.android.internal.R.integer.config_networkPolicyDefaultWarning); + final long warningBytes; + if (dataWarningConfig == WARNING_DISABLED) { + warningBytes = WARNING_DISABLED; + } else { + warningBytes = dataWarningConfig * MB_IN_BYTES; + } final Time time = new Time(); time.setToNow(); @@ -2214,23 +2223,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void setDeviceIdleMode(boolean enabled) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDeviceIdleMode"); try { synchronized (mUidRulesFirstLock) { - if (mDeviceIdleMode != enabled) { - mDeviceIdleMode = enabled; - if (mSystemReady) { - // Device idle change means we need to rebuild rules for all - // known apps, so do a global refresh. - updateRulesForRestrictPowerUL(); - } - if (enabled) { - EventLogTags.writeDeviceIdleOnPhase("net"); - } else { - EventLogTags.writeDeviceIdleOffPhase("net"); - } + if (mDeviceIdleMode == enabled) { + return; } + mDeviceIdleMode = enabled; + if (mSystemReady) { + // Device idle change means we need to rebuild rules for all + // known apps, so do a global refresh. + updateRulesForRestrictPowerUL(); + } + } + if (enabled) { + EventLogTags.writeDeviceIdleOnPhase("net"); + } else { + EventLogTags.writeDeviceIdleOffPhase("net"); } } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); @@ -2654,10 +2663,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW); } } - setUidFirewallRules(chain, uidRules); + setUidFirewallRulesAsync(chain, uidRules, CHAIN_TOGGLE_ENABLE); + } else { + setUidFirewallRulesAsync(chain, null, CHAIN_TOGGLE_DISABLE); } - - enableFirewallChainUL(chain, enabled); } private boolean isWhitelistedBatterySaverUL(int uid) { @@ -2701,7 +2710,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - setUidFirewallRules(FIREWALL_CHAIN_STANDBY, uidRules); + setUidFirewallRulesAsync(FIREWALL_CHAIN_STANDBY, uidRules, CHAIN_TOGGLE_NONE); } finally { Trace.traceEnd(Trace.TRACE_TAG_NETWORK); } @@ -2731,6 +2740,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateRulesForGlobalChangeAL(boolean restrictedNetworksChanged) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForGlobalChangeAL"); try { + updateRulesForAppIdleUL(); updateRulesForRestrictPowerUL(); updateRulesForRestrictBackgroundUL(); @@ -2744,11 +2754,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + // TODO: rename / document to make it clear these are global (not app-specific) rules private void updateRulesForRestrictPowerUL() { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForRestrictPowerUL"); try { updateRulesForDeviceIdleUL(); - updateRulesForAppIdleUL(); updateRulesForPowerSaveUL(); updateRulesForAllAppsUL(TYPE_RESTRICT_POWER); } finally { @@ -3356,6 +3366,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { removeInterfaceQuota((String) msg.obj); return true; } + case MSG_SET_FIREWALL_RULES: { + final int chain = msg.arg1; + final int toggle = msg.arg2; + final SparseIntArray uidRules = (SparseIntArray) msg.obj; + if (uidRules != null) { + setUidFirewallRules(chain, uidRules); + } + if (toggle != CHAIN_TOGGLE_NONE) { + enableFirewallChainUL(chain, toggle == CHAIN_TOGGLE_ENABLE); + } + return true; + } default: { return false; } @@ -3405,6 +3427,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private static final int CHAIN_TOGGLE_NONE = 0; + private static final int CHAIN_TOGGLE_ENABLE = 1; + private static final int CHAIN_TOGGLE_DISABLE = 2; + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = false, value = { + CHAIN_TOGGLE_NONE, + CHAIN_TOGGLE_ENABLE, + CHAIN_TOGGLE_DISABLE + }) + public @interface ChainToggleType { + } + + /** + * Calls {@link #setUidFirewallRules(int, SparseIntArray)} and + * {@link #enableFirewallChainUL(int, boolean)} asynchronously. + * + * @param chain firewall chain. + * @param uidRules new UID rules; if {@code null}, only toggles chain state. + * @param toggle whether the chain should be enabled, disabled, or not changed. + */ + private void setUidFirewallRulesAsync(int chain, @Nullable SparseIntArray uidRules, + @ChainToggleType int toggle) { + mHandler.obtainMessage(MSG_SET_FIREWALL_RULES, chain, toggle, uidRules).sendToTarget(); + } + /** * Set uid rules on a particular firewall chain. This is going to synchronize the rules given * here to netd. It will clean up dead rules and make sure the target chain only contains rules diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index c22bfb321a5c..afd42ea67c0f 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -35,6 +35,7 @@ import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.ContentObserver; +import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioManagerInternal; import android.media.AudioSystem; @@ -736,13 +737,14 @@ public class ZenModeHelper { // total silence restrictions final boolean muteEverything = mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS; - for (int i = USAGE_UNKNOWN; i <= USAGE_VIRTUAL_SOURCE; i++) { - if (i == USAGE_NOTIFICATION) { - applyRestrictions(muteNotifications || muteEverything, i); - } else if (i == USAGE_NOTIFICATION_RINGTONE) { - applyRestrictions(muteCalls || muteEverything, i); + for (int usage : AudioAttributes.SDK_USAGES) { + final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage); + if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) { + applyRestrictions(muteNotifications || muteEverything, usage); + } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) { + applyRestrictions(muteCalls || muteEverything, usage); } else { - applyRestrictions(muteEverything, i); + applyRestrictions(muteEverything, usage); } } } diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java index 8d926f5d316f..68b465aaf816 100644 --- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java +++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java @@ -60,7 +60,7 @@ final class EphemeralResolverConnection { public EphemeralResolverConnection(Context context, ComponentName componentName) { mContext = context; - mIntent = new Intent().setComponent(componentName); + mIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE).setComponent(componentName); } public final List<EphemeralResolveInfo> getEphemeralResolveInfoList( diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 72c549f7bec6..2e18b1c417fe 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -230,6 +230,11 @@ public final class Installer extends SystemService { mInstaller.execute("move_ab", apkPath, instructionSet, outputPath); } + public void deleteOdex(String apkPath, String instructionSet, String outputPath) + throws InstallerException { + mInstaller.execute("delete_odex", apkPath, instructionSet, outputPath); + } + private static void assertValidInstructionSet(String instructionSet) throws InstallerException { for (String abi : Build.SUPPORTED_ABIS) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index bff6d2d4786e..42079fb0df1b 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -31,7 +31,7 @@ import android.os.ServiceManager; import android.os.storage.StorageManager; import android.util.Log; import android.util.Slog; - +import com.android.internal.logging.MetricsLogger; import com.android.internal.os.InstallerConnection; import com.android.internal.os.InstallerConnection.InstallerException; @@ -40,6 +40,7 @@ import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.concurrent.TimeUnit; /** * A service for A/B OTA dexopting. @@ -53,6 +54,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub { // The synthetic library dependencies denoting "no checks." private final static String[] NO_LIBRARIES = new String[] { "&" }; + // The amount of "available" (free - low threshold) space necessary at the start of an OTA to + // not bulk-delete unused apps' odex files. + private final static long BULK_DELETE_THRESHOLD = 1024 * 1024 * 1024; // 1GB. + private final Context mContext; private final PackageManagerService mPackageManagerService; @@ -65,6 +70,25 @@ public class OtaDexoptService extends IOtaDexopt.Stub { private int completeSize; + // MetricsLogger properties. + + // Space before and after. + private long availableSpaceBefore; + private long availableSpaceAfterBulkDelete; + private long availableSpaceAfterDexopt; + + // Packages. + private int importantPackageCount; + private int otherPackageCount; + + // Number of dexopt commands. This may be different from the count of packages. + private int dexoptCommandCountTotal; + private int dexoptCommandCountExecuted; + + // For spent time. + private long otaDexoptTimeStart; + + public OtaDexoptService(Context context, PackageManagerService packageManagerService) { this.mContext = context; this.mPackageManagerService = packageManagerService; @@ -128,6 +152,18 @@ public class OtaDexoptService extends IOtaDexopt.Stub { generatePackageDexopts(p, PackageManagerService.REASON_FIRST_BOOT)); } completeSize = mDexoptCommands.size(); + + long spaceAvailable = getAvailableSpace(); + if (spaceAvailable < BULK_DELETE_THRESHOLD) { + Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: " + + PackageManagerServiceUtils.packagesToString(others)); + for (PackageParser.Package pkg : others) { + deleteOatArtifactsOfPackage(pkg); + } + } + long spaceAvailableNow = getAvailableSpace(); + + prepareMetricsLogging(important.size(), others.size(), spaceAvailable, spaceAvailableNow); } @Override @@ -136,6 +172,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub { Log.i(TAG, "Cleaning up OTA Dexopt state."); } mDexoptCommands = null; + + performMetricsLogging(); } @Override @@ -169,28 +207,67 @@ public class OtaDexoptService extends IOtaDexopt.Stub { String next = mDexoptCommands.remove(0); - if (IsFreeSpaceAvailable()) { + if (getAvailableSpace() > 0) { + dexoptCommandCountExecuted++; + return next; } else { + if (DEBUG_DEXOPT) { + Log.w(TAG, "Not enough space for OTA dexopt, stopping with " + + (mDexoptCommands.size() + 1) + " commands left."); + } mDexoptCommands.clear(); return "(no free space)"; } } - /** - * Check for low space. Returns true if there's space left. - */ - private boolean IsFreeSpaceAvailable() { - // TODO: If apps are not installed in the internal /data partition, we should compare - // against that storage's free capacity. + private long getMainLowSpaceThreshold() { File dataDir = Environment.getDataDirectory(); @SuppressWarnings("deprecation") long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir); if (lowThreshold == 0) { throw new IllegalStateException("Invalid low memory threshold"); } + return lowThreshold; + } + + /** + * Returns the difference of free space to the low-storage-space threshold. Positive values + * indicate free bytes. + */ + private long getAvailableSpace() { + // TODO: If apps are not installed in the internal /data partition, we should compare + // against that storage's free capacity. + long lowThreshold = getMainLowSpaceThreshold(); + + File dataDir = Environment.getDataDirectory(); long usableSpace = dataDir.getUsableSpace(); - return (usableSpace >= lowThreshold); + + return usableSpace - lowThreshold; + } + + private static String getOatDir(PackageParser.Package pkg) { + if (!pkg.canHaveOatDir()) { + return null; + } + File codePath = new File(pkg.codePath); + if (codePath.isDirectory()) { + return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath(); + } + return null; + } + + private void deleteOatArtifactsOfPackage(PackageParser.Package pkg) { + String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + for (String codePath : pkg.getAllCodePaths()) { + for (String isa : instructionSets) { + try { + mPackageManagerService.mInstaller.deleteOdex(codePath, isa, getOatDir(pkg)); + } catch (InstallerException e) { + Log.e(TAG, "Failed deleting oat files for " + codePath, e); + } + } + } } /** @@ -271,6 +348,55 @@ public class OtaDexoptService extends IOtaDexopt.Stub { } } + /** + * Initialize logging fields. + */ + private void prepareMetricsLogging(int important, int others, long spaceBegin, long spaceBulk) { + availableSpaceBefore = spaceBegin; + availableSpaceAfterBulkDelete = spaceBulk; + availableSpaceAfterDexopt = 0; + + importantPackageCount = important; + otherPackageCount = others; + + dexoptCommandCountTotal = mDexoptCommands.size(); + dexoptCommandCountExecuted = 0; + + otaDexoptTimeStart = System.nanoTime(); + } + + private static int inMegabytes(long value) { + long in_mega_bytes = value / (1024 * 1024); + if (in_mega_bytes > Integer.MAX_VALUE) { + Log.w(TAG, "Recording " + in_mega_bytes + "MB of free space, overflowing range"); + return Integer.MAX_VALUE; + } + return (int)in_mega_bytes; + } + + private void performMetricsLogging() { + long finalTime = System.nanoTime(); + + MetricsLogger.histogram(mContext, "ota_dexopt_available_space_before_mb", + inMegabytes(availableSpaceBefore)); + MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_bulk_delete_mb", + inMegabytes(availableSpaceAfterBulkDelete)); + MetricsLogger.histogram(mContext, "ota_dexopt_available_space_after_dexopt_mb", + inMegabytes(availableSpaceAfterDexopt)); + + MetricsLogger.histogram(mContext, "ota_dexopt_num_important_packages", + importantPackageCount); + MetricsLogger.histogram(mContext, "ota_dexopt_num_other_packages", otherPackageCount); + + MetricsLogger.histogram(mContext, "ota_dexopt_num_commands", dexoptCommandCountTotal); + MetricsLogger.histogram(mContext, "ota_dexopt_num_commands_executed", + dexoptCommandCountExecuted); + + final int elapsedTimeSeconds = + (int) TimeUnit.NANOSECONDS.toSeconds(finalTime - otaDexoptTimeStart); + MetricsLogger.histogram(mContext, "ota_dexopt_time_s", elapsedTimeSeconds); + } + private static class OTADexoptPackageDexOptimizer extends PackageDexOptimizer.ForcedUpdatePackageDexOptimizer { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 419e4ad19e71..783db051f8de 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -212,6 +212,7 @@ import android.util.ExceptionUtils; import android.util.Log; import android.util.LogPrinter; import android.util.MathUtils; +import android.util.Pair; import android.util.PrintStreamPrinter; import android.util.Slog; import android.util.SparseArray; @@ -365,8 +366,8 @@ public class PackageManagerService extends IPackageManager.Stub { static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false; - // STOPSHIP; b/30256615 - private static final boolean DISABLE_EPHEMERAL_APPS = !Build.IS_DEBUGGABLE; + private static final boolean DISABLE_EPHEMERAL_APPS = false; + private static final boolean HIDE_EPHEMERAL_APIS = true; private static final int RADIO_UID = Process.PHONE_UID; private static final int LOG_UID = Process.LOG_UID; @@ -1128,6 +1129,7 @@ public class PackageManagerService extends IPackageManager.Stub { final @NonNull String mRequiredInstallerPackage; final @NonNull String mRequiredUninstallerPackage; final @Nullable String mSetupWizardPackage; + final @Nullable String mStorageManagerPackage; final @NonNull String mServicesSystemSharedLibraryPackageName; final @NonNull String mSharedSystemSharedLibraryPackageName; @@ -2469,6 +2471,9 @@ public class PackageManagerService extends IPackageManager.Stub { } mExpectingBetter.clear(); + // Resolve the storage manager. + mStorageManagerPackage = getStorageManagerPackageName(); + // Resolve protected action filters. Only the setup wizard is allowed to // have a high priority filter for these actions. mSetupWizardPackage = getSetupWizardPackageName(); @@ -6278,7 +6283,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ParceledListSlice<EphemeralApplicationInfo> getEphemeralApplications(int userId) { - if (isEphemeralDisabled()) { + if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) { return null; } @@ -6302,7 +6307,7 @@ public class PackageManagerService extends IPackageManager.Stub { enforceCrossUserPermission(Binder.getCallingUid(), userId, true /* requireFullPermission */, false /* checkShell */, "isEphemeral"); - if (isEphemeralDisabled()) { + if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) { return false; } @@ -6320,7 +6325,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public byte[] getEphemeralApplicationCookie(String packageName, int userId) { - if (isEphemeralDisabled()) { + if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) { return null; } @@ -6338,7 +6343,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) { - if (isEphemeralDisabled()) { + if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) { return true; } @@ -6356,7 +6361,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public Bitmap getEphemeralApplicationIcon(String packageName, int userId) { - if (isEphemeralDisabled()) { + if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) { return null; } @@ -11261,6 +11266,19 @@ public class PackageManagerService extends IPackageManager.Stub { private static final class EphemeralIntentResolver extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> { + /** + * The result that has the highest defined order. Ordering applies on a + * per-package basis. Mapping is from package name to Pair of order and + * EphemeralResolveInfo. + * <p> + * NOTE: This is implemented as a field variable for convenience and efficiency. + * By having a field variable, we're able to track filter ordering as soon as + * a non-zero order is defined. Otherwise, multiple loops across the result set + * would be needed to apply ordering. If the intent resolver becomes re-entrant, + * this needs to be contained entirely within {@link #filterResults()}. + */ + final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>(); + @Override protected EphemeralResolveIntentInfo[] newArray(int size) { return new EphemeralResolveIntentInfo[size]; @@ -11277,7 +11295,51 @@ public class PackageManagerService extends IPackageManager.Stub { if (!sUserManager.exists(userId)) { return null; } - return info.getEphemeralResolveInfo(); + final String packageName = info.getEphemeralResolveInfo().getPackageName(); + final Integer order = info.getOrder(); + final Pair<Integer, EphemeralResolveInfo> lastOrderResult = + mOrderResult.get(packageName); + // ordering is enabled and this item's order isn't high enough + if (lastOrderResult != null && lastOrderResult.first >= order) { + return null; + } + final EphemeralResolveInfo res = info.getEphemeralResolveInfo(); + if (order > 0) { + // non-zero order, enable ordering + mOrderResult.put(packageName, new Pair<>(order, res)); + } + return res; + } + + @Override + protected void filterResults(List<EphemeralResolveInfo> results) { + // only do work if ordering is enabled [most of the time it won't be] + if (mOrderResult.size() == 0) { + return; + } + int resultSize = results.size(); + for (int i = 0; i < resultSize; i++) { + final EphemeralResolveInfo info = results.get(i); + final String packageName = info.getPackageName(); + final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName); + if (savedInfo == null) { + // package doesn't having ordering + continue; + } + if (savedInfo.second == info) { + // circled back to the highest ordered item; remove from order list + mOrderResult.remove(savedInfo); + if (mOrderResult.size() == 0) { + // no more ordered items + break; + } + continue; + } + // item has a worse order, remove it from the result list + results.remove(i); + resultSize--; + i--; + } } } @@ -15513,6 +15575,12 @@ public class PackageManagerService extends IPackageManager.Stub { callingUid == getPackageUid(mRequiredUninstallerPackage, 0, callingUserId)) { return true; } + + // Allow storage manager to silently uninstall. + if (mStorageManagerPackage != null && + callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) { + return true; + } return false; } @@ -17728,6 +17796,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } } + private @Nullable String getStorageManagerPackageName() { + final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE); + + final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null, + MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE + | MATCH_DISABLED_COMPONENTS, + UserHandle.myUserId()); + if (matches.size() == 1) { + return matches.get(0).getComponentInfo().packageName; + } else { + Slog.e(TAG, "There should probably be exactly one storage manager; found " + + matches.size() + ": matches=" + matches); + return null; + } + } + @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { @@ -20980,6 +21064,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); public boolean isPackageDataProtected(int userId, String packageName) { return mProtectedPackages.isPackageDataProtected(userId, packageName); } + + @Override + public boolean wasPackageEverLaunched(String packageName, int userId) { + synchronized (mPackages) { + return mSettings.wasPackageEverLaunchedLPr(packageName, userId); + } + } } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 9a8ebedf105e..cfd0af7635e8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -168,23 +168,8 @@ public class PackageManagerServiceUtils { packageManagerService); if (DEBUG_DEXOPT) { - StringBuilder sb = new StringBuilder(); - for (PackageParser.Package pkg : result) { - if (sb.length() > 0) { - sb.append(", "); - } - sb.append(pkg.packageName); - } - Log.i(TAG, "Packages to be dexopted: " + sb.toString()); - - sb.setLength(0); - for (PackageParser.Package pkg : remainingPkgs) { - if (sb.length() > 0) { - sb.append(", "); - } - sb.append(pkg.packageName); - } - Log.i(TAG, "Packages skipped from dexopt: " + sb.toString()); + Log.i(TAG, "Packages to be dexopted: " + packagesToString(result)); + Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs)); } return result; @@ -201,4 +186,15 @@ public class PackageManagerServiceUtils { throw ee.rethrowAsIOException(); } } + + public static String packagesToString(Collection<PackageParser.Package> c) { + StringBuilder sb = new StringBuilder(); + for (PackageParser.Package pkg : c) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(pkg.packageName); + } + return sb.toString(); + } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 5126305dd0d1..b0c536f04652 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4154,6 +4154,14 @@ final class Settings { return pkg.getCurrentEnabledStateLPr(classNameStr, userId); } + boolean wasPackageEverLaunchedLPr(String packageName, int userId) { + final PackageSetting pkgSetting = mPackages.get(packageName); + if (pkgSetting == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + return !pkgSetting.getNotLaunched(userId); + } + boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName, boolean stopped, boolean allowedByPermission, int uid, int userId) { int appId = UserHandle.getAppId(uid); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index bd6851c939d4..ccf9b898d7b2 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5534,7 +5534,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void onServiceDisconnected(ComponentName name) { - notifyScreenshotError(); + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + mHandler.removeCallbacks(mScreenshotTimeout); + notifyScreenshotError(); + } + } } }; if (mContext.bindServiceAsUser(serviceIntent, conn, @@ -7771,7 +7778,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int delta = newRotation - oldRotation; if (delta < 0) delta += 4; // Likewise we don't rotate seamlessly for 180 degree rotations - // in this case the surfaces never resize, and our logic to + // in this case the surfaces never resize, and our logic to // revert the transformations on size change will fail. We could // fix this in the future with the "tagged" frames idea. if (delta == Surface.ROTATION_180) { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 2824e6e66ffa..570b93c09c9a 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2538,18 +2538,18 @@ public final class PowerManagerService extends SystemService boolean setDeviceIdleModeInternal(boolean enabled) { synchronized (mLock) { - if (mDeviceIdleMode != enabled) { - mDeviceIdleMode = enabled; - updateWakeLockDisabledStatesLocked(); - if (enabled) { - EventLogTags.writeDeviceIdleOnPhase("power"); - } else { - EventLogTags.writeDeviceIdleOffPhase("power"); - } - return true; + if (mDeviceIdleMode == enabled) { + return false; } - return false; + mDeviceIdleMode = enabled; + updateWakeLockDisabledStatesLocked(); + } + if (enabled) { + EventLogTags.writeDeviceIdleOnPhase("power"); + } else { + EventLogTags.writeDeviceIdleOffPhase("power"); } + return true; } boolean setLightDeviceIdleModeInternal(boolean enabled) { diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 022848eb37c3..1ee5a22195ef 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -121,6 +121,9 @@ public class WindowAnimator { private final AppTokenList mTmpExitingAppTokens = new AppTokenList(); + /** The window that was previously hiding the Keyguard. */ + private WindowState mLastShowWinWhenLocked; + private String forceHidingToString() { switch (mForceHiding) { case KEYGUARD_NOT_SHOWN: return "KEYGUARD_NOT_SHOWN"; @@ -221,27 +224,43 @@ public class WindowAnimator { } } + /** + * @return The window that is currently hiding the Keyguard, or if it was hiding the Keyguard, + * and it's still animating. + */ + private WindowState getWinShowWhenLockedOrAnimating() { + final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw(); + if (winShowWhenLocked != null) { + return winShowWhenLocked; + } + if (mLastShowWinWhenLocked != null && mLastShowWinWhenLocked.isOnScreen() + && mLastShowWinWhenLocked.isAnimatingLw() + && (mLastShowWinWhenLocked.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { + return mLastShowWinWhenLocked; + } + return null; + } + private boolean shouldForceHide(WindowState win) { final WindowState imeTarget = mService.mInputMethodTarget; final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() && ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0 || !mPolicy.canBeForceHidden(imeTarget, imeTarget.mAttrs)); - final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw(); + final WindowState winShowWhenLocked = getWinShowWhenLockedOrAnimating(); final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ? null : winShowWhenLocked.mAppToken; boolean allowWhenLocked = false; // Show IME over the keyguard if the target allows it allowWhenLocked |= (win.mIsImWindow || imeTarget == win) && showImeOverKeyguard; - // Show SHOW_WHEN_LOCKED windows - allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0; - // Show windows that are attached to SHOW_WHEN_LOCKED windows - allowWhenLocked |= win.mAttachedWindow != null - && (win.mAttachedWindow.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0; + // Show SHOW_WHEN_LOCKED windows that turn on the screen + allowWhenLocked |= (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && win.mTurnOnScreen; if (appShowWhenLocked != null) { allowWhenLocked |= appShowWhenLocked == win.mAppToken + // Show all SHOW_WHEN_LOCKED windows if some apps are shown over lockscreen + || (win.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 // Show error dialogs over apps that are shown on lockscreen || (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0; } @@ -556,6 +575,11 @@ public class WindowAnimator { mPostKeyguardExitAnimation = null; } } + + final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw(); + if (winShowWhenLocked != null) { + mLastShowWinWhenLocked = winShowWhenLocked; + } } private void updateWallpaperLocked(int displayId) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 4372deaf4425..707b13780c46 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -21,6 +21,7 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; import android.app.AppOpsManager; @@ -9192,7 +9193,7 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void setForcedDisplayDensity(int displayId, int density) { + public void setForcedDisplayDensityForUser(int displayId, int density, int userId) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.WRITE_SECURE_SETTINGS) != PackageManager.PERMISSION_GRANTED) { @@ -9202,16 +9203,20 @@ public class WindowManagerService extends IWindowManager.Stub if (displayId != Display.DEFAULT_DISPLAY) { throw new IllegalArgumentException("Can only set the default display"); } + + final int targetUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "setForcedDisplayDensityForUser", + null); final long ident = Binder.clearCallingIdentity(); try { synchronized(mWindowMap) { final DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent != null) { + if (displayContent != null && mCurrentUserId == targetUserId) { setForcedDisplayDensityLocked(displayContent, density); - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.DISPLAY_DENSITY_FORCED, - Integer.toString(density), mCurrentUserId); } + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.DISPLAY_DENSITY_FORCED, + Integer.toString(density), targetUserId); } } finally { Binder.restoreCallingIdentity(ident); @@ -9219,7 +9224,7 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public void clearForcedDisplayDensity(int displayId) { + public void clearForcedDisplayDensityForUser(int displayId, int userId) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.WRITE_SECURE_SETTINGS) != PackageManager.PERMISSION_GRANTED) { @@ -9229,16 +9234,20 @@ public class WindowManagerService extends IWindowManager.Stub if (displayId != Display.DEFAULT_DISPLAY) { throw new IllegalArgumentException("Can only set the default display"); } + + final int callingUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), + Binder.getCallingUid(), userId, false, true, "clearForcedDisplayDensityForUser", + null); final long ident = Binder.clearCallingIdentity(); try { synchronized(mWindowMap) { final DisplayContent displayContent = getDisplayContentLocked(displayId); - if (displayContent != null) { + if (displayContent != null && mCurrentUserId == callingUserId) { setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity); - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId); } + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.DISPLAY_DENSITY_FORCED, "", callingUserId); } } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 00f4a45ba9c5..0285f7075e95 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -228,8 +228,6 @@ class WindowStateAnimator { int mAttrType; static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100; - long mDeferTransactionUntilFrame = -1; - long mDeferTransactionTime = -1; boolean mForceScaleUntilResize; @@ -2055,35 +2053,11 @@ class WindowStateAnimator { if (!mWin.isChildWindow()) { return; } - mDeferTransactionUntilFrame = frameNumber; - mDeferTransactionTime = System.currentTimeMillis(); mSurfaceController.deferTransactionUntil( mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), frameNumber); } - // Defer the current transaction to the frame number of the last saved transaction. - // We do this to avoid shooting through an unsynchronized transaction while something is - // pending. This is generally fine, as either we will get in on the synchronization, - // or SurfaceFlinger will see that the frame has already occured. The only - // potential problem is in frame number resets so we reset things with a timeout - // every so often to be careful. - void deferToPendingTransaction() { - if (mDeferTransactionUntilFrame < 0) { - return; - } - long time = System.currentTimeMillis(); - if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) { - mDeferTransactionTime = -1; - mDeferTransactionUntilFrame = -1; - } else if (mWin.mAttachedWindow != null && - mWin.mAttachedWindow.mWinAnimator.hasSurface()) { - mSurfaceController.deferTransactionUntil( - mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), - mDeferTransactionUntilFrame); - } - } - /** * Sometimes we need to synchronize the first frame of animation with some external event. * To achieve this, we prolong the start of the animation and keep producing the first frame of diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index fa5e3cabeb44..5a79da938c60 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -742,10 +742,6 @@ class WindowSurfacePlacer { // Moved from updateWindowsAndWallpaperLocked(). if (w.mHasSurface) { - // If we have recently synchronized a previous transaction for this - // window ensure we don't push through an unsynchronized one now. - winAnimator.deferToPendingTransaction(); - // Take care of the window being ready to display. final boolean committed = winAnimator.commitFinishDrawingLocked(); if (isDefaultDisplay && committed) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 8d699436eb30..777c0b35e4be 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -525,6 +525,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { static class ActiveAdmin { private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; + private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin"; private static final String TAG_DISABLE_CAMERA = "disable-camera"; private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id"; private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search"; @@ -617,6 +618,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED; boolean encryptionRequested = false; + boolean testOnlyAdmin = false; boolean disableCamera = false; boolean disableCallerId = false; boolean disableContactsSearch = false; @@ -786,6 +788,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested)); out.endTag(null, TAG_ENCRYPTION_REQUESTED); } + if (testOnlyAdmin) { + out.startTag(null, TAG_TEST_ONLY_ADMIN); + out.attribute(null, ATTR_VALUE, Boolean.toString(testOnlyAdmin)); + out.endTag(null, TAG_TEST_ONLY_ADMIN); + } if (disableCamera) { out.startTag(null, TAG_DISABLE_CAMERA); out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera)); @@ -981,6 +988,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) { encryptionRequested = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) { + testOnlyAdmin = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); } else if (TAG_DISABLE_CAMERA.equals(tag)) { disableCamera = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_VALUE)); @@ -1179,6 +1189,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("uid="); pw.println(getUid()); + pw.print(prefix); pw.print("testOnlyAdmin="); + pw.println(testOnlyAdmin); pw.print(prefix); pw.println("policies:"); ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies(); if (pols != null) { @@ -2829,8 +2841,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { long ident = mInjector.binderClearCallingIdentity(); try { - if (!refreshing - && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { + final ActiveAdmin existingAdmin + = getActiveAdminUncheckedLocked(adminReceiver, userHandle); + if (!refreshing && existingAdmin != null) { throw new IllegalArgumentException("Admin is already added"); } if (policy.mRemovingAdmins.contains(adminReceiver)) { @@ -2838,6 +2851,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "Trying to set an admin which is being removed"); } ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false); + newAdmin.testOnlyAdmin = + (existingAdmin != null) ? existingAdmin.testOnlyAdmin + : isPackageTestOnly(adminReceiver.getPackageName(), userHandle); policy.mAdminMap.put(adminReceiver, newAdmin); int replaceIndex = -1; final int N = policy.mAdminList.size(); @@ -2949,12 +2965,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceShell("forceRemoveActiveAdmin"); long ident = mInjector.binderClearCallingIdentity(); try { - if (!isPackageTestOnly(adminReceiver.getPackageName(), userHandle)) { - throw new SecurityException("Attempt to remove non-test admin " - + adminReceiver + " " + userHandle); - } - // If admin is a device or profile owner tidy that up first. synchronized (this) { + if (!isAdminTestOnlyLocked(adminReceiver, userHandle)) { + throw new SecurityException("Attempt to remove non-test admin " + + adminReceiver + " " + userHandle); + } + + // If admin is a device or profile owner tidy that up first. if (isDeviceOwner(adminReceiver, userHandle)) { clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle); } @@ -2972,6 +2989,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Return if a given package has testOnly="true", in which case we'll relax certain rules + * for CTS. + * + * DO NOT use this method except in {@link #setActiveAdmin}. Use {@link #isAdminTestOnlyLocked} + * to check wehter an active admin is test-only or not. + * + * The system allows this flag to be changed when an app is updated, which is not good + * for us. So we persist the flag in {@link ActiveAdmin} when an admin is first installed, + * and used the persisted version in actual checks. (See b/31382361 and b/28928996) + */ private boolean isPackageTestOnly(String packageName, int userHandle) { final ApplicationInfo ai; try { @@ -2988,6 +3016,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return (ai.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0; } + /** + * See {@link #isPackageTestOnly}. + */ + private boolean isAdminTestOnlyLocked(ComponentName who, int userHandle) { + final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + return (admin != null) && admin.testOnlyAdmin; + } + private void enforceShell(String method) { final int callingUid = Binder.getCallingUid(); if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { @@ -6225,7 +6261,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * The profile owner can only be set before the user setup phase has completed, * except for: * - SYSTEM_UID - * - adb if there are no accounts. (But see {@link #hasIncompatibleAccounts}) + * - adb if there are no accounts. (But see {@link #hasIncompatibleAccountsLocked}) */ private void enforceCanSetProfileOwnerLocked(@Nullable ComponentName owner, int userHandle) { UserInfo info = getUserInfo(userHandle); @@ -6248,7 +6284,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int callingUid = mInjector.binderGetCallingUid(); if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) { if (hasUserSetupCompleted(userHandle) - && hasIncompatibleAccounts(userHandle, owner)) { + && hasIncompatibleAccountsLocked(userHandle, owner)) { throw new IllegalStateException("Not allowed to set the profile owner because " + "there are already some accounts on the profile"); } @@ -6272,7 +6308,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCanManageProfileAndDeviceOwners(); } - final int code = checkSetDeviceOwnerPreCondition(owner, userId, isAdb); + final int code = checkSetDeviceOwnerPreConditionLocked(owner, userId, isAdb); switch (code) { case CODE_OK: return; @@ -8489,7 +8525,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * The device owner can only be set before the setup phase of the primary user has completed, * except for adb command if no accounts or additional users are present on the device. */ - private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreCondition( + private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreConditionLocked( @Nullable ComponentName owner, int deviceOwnerUserId, boolean isAdb) { if (mOwners.hasDeviceOwner()) { return CODE_HAS_DEVICE_OWNER; @@ -8507,7 +8543,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (mUserManager.getUserCount() > 1) { return CODE_NONSYSTEM_USER_EXISTS; } - if (hasIncompatibleAccounts(UserHandle.USER_SYSTEM, owner)) { + if (hasIncompatibleAccountsLocked(UserHandle.USER_SYSTEM, owner)) { return CODE_ACCOUNTS_NOT_EMPTY; } } else { @@ -8533,8 +8569,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) { - return CODE_OK == checkSetDeviceOwnerPreCondition( - /* owner unknown */ null, deviceOwnerUserId, /* isAdb */ false); + synchronized (this) { + return CODE_OK == checkSetDeviceOwnerPreConditionLocked( + /* owner unknown */ null, deviceOwnerUserId, /* isAdb */ false); + } } private boolean hasFeatureManagedUsers() { @@ -9103,7 +9141,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * ..._DISALLOWED, return true. * - Otherwise return false. */ - private boolean hasIncompatibleAccounts(int userId, @Nullable ComponentName owner) { + private boolean hasIncompatibleAccountsLocked(int userId, @Nullable ComponentName owner) { final long token = mInjector.binderClearCallingIdentity(); try { final AccountManager am = AccountManager.get(mContext); @@ -9141,7 +9179,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Owner is unknown. Suppose it's not test-only compatible = false; log = "Only test-only device/profile owner can be installed with accounts"; - } else if (isPackageTestOnly(owner.getPackageName(), userId)) { + } else if (isAdminTestOnlyLocked(owner, userId)) { if (compatible) { log = "Installing test-only owner " + owner; } else { diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index 4bb0902f2ec0..4c7545240c23 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -19,6 +19,7 @@ package android.net.apf; import static android.system.OsConstants.*; import android.os.SystemClock; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkUtils; import android.net.apf.ApfGenerator; @@ -44,6 +45,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.IOException; import java.lang.Thread; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; @@ -171,8 +173,8 @@ public class ApfFilter { private static final int ETH_HEADER_LEN = 14; private static final int ETH_DEST_ADDR_OFFSET = 0; private static final int ETH_ETHERTYPE_OFFSET = 12; - private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{ - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; + private static final byte[] ETH_BROADCAST_MAC_ADDRESS = + {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN. private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6; // Endianness is not an issue for this constant because the APF interpreter always operates in @@ -181,6 +183,7 @@ public class ApfFilter { private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9; private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; private static final int IPV4_ANY_HOST_ADDRESS = 0; + private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255 private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6; private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8; @@ -188,7 +191,7 @@ public class ApfFilter { private static final int IPV6_HEADER_LEN = 40; // The IPv6 all nodes address ff02::1 private static final byte[] IPV6_ALL_NODES_ADDRESS = - new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; @@ -206,7 +209,7 @@ public class ApfFilter { private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6; private static final short ARP_OPCODE_REQUEST = 1; private static final short ARP_OPCODE_REPLY = 2; - private static final byte[] ARP_IPV4_HEADER = new byte[]{ + private static final byte[] ARP_IPV4_HEADER = { 0, 1, // Hardware type: Ethernet (1) 8, 0, // Protocol type: IP (0x0800) 6, // Hardware size: 6 @@ -229,6 +232,9 @@ public class ApfFilter { // Our IPv4 address, if we have just one, otherwise null. @GuardedBy("this") private byte[] mIPv4Address; + // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null. + @GuardedBy("this") + private int mIPv4PrefixLength; @VisibleForTesting ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface, @@ -364,26 +370,6 @@ public class ApfFilter { // Can't be static because it's in a non-static inner class. // TODO: Make this static once RA is its own class. - private int uint8(byte b) { - return b & 0xff; - } - - private int uint16(short s) { - return s & 0xffff; - } - - private long uint32(int i) { - return i & 0xffffffffL; - } - - private long getUint16(ByteBuffer buffer, int position) { - return uint16(buffer.getShort(position)); - } - - private long getUint32(ByteBuffer buffer, int position) { - return uint32(buffer.getInt(position)); - } - private void prefixOptionToString(StringBuffer sb, int offset) { String prefix = IPv6AddresstoString(offset + 16); int length = uint8(mPacket.get(offset + 2)); @@ -737,39 +723,57 @@ public class ApfFilter { // Here's a basic summary of what the IPv4 filter program does: // // if filtering multicast (i.e. multicast lock not held): - // if it's multicast: - // drop - // if it's not broadcast: + // if it's DHCP destined to our MAC: // pass - // if it's not DHCP destined to our MAC: + // if it's L2 broadcast: + // drop + // if it's IPv4 multicast: + // drop + // if it's IPv4 broadcast: // drop // pass if (mMulticastFilter) { - // Check for multicast destination address range - gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET); - gen.addAnd(0xf0); - gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL); + final String skipDhcpv4Filter = "skip_dhcp_v4_filter"; - // Drop all broadcasts besides DHCP addressed to us - // If not a broadcast packet, pass - gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); - gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); - // If not UDP, drop + // Pass DHCP addressed to us. + // Check it's UDP. gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET); - gen.addJumpIfR0NotEquals(IPPROTO_UDP, gen.DROP_LABEL); - // If fragment, drop. This matches the BPF filter installed by the DHCP client. + gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter); + // Check it's not a fragment. This matches the BPF filter installed by the DHCP client. gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET); - gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, gen.DROP_LABEL); - // If not to DHCP client port, drop + gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter); + // Check it's addressed to DHCP client port. gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET); - gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, gen.DROP_LABEL); - // If not DHCP to our MAC address, drop + gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter); + // Check it's DHCP to our MAC address. gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET); // NOTE: Relies on R1 containing IPv4 header offset. gen.addAddR1(); - gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, gen.DROP_LABEL); + gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter); + gen.addJump(gen.PASS_LABEL); + + // Drop all multicasts/broadcasts. + gen.defineLabel(skipDhcpv4Filter); + + // If IPv4 destination address is in multicast range, drop. + gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET); + gen.addAnd(0xf0); + gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL); + + // If IPv4 broadcast packet, drop regardless of L2 (b/30231088). + gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET); + gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL); + if (mIPv4Address != null && mIPv4PrefixLength < 31) { + int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength); + gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL); + } + + // If L2 broadcast packet, drop. + gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); + gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); + gen.addJump(gen.DROP_LABEL); } // Otherwise, pass @@ -1062,26 +1066,32 @@ public class ApfFilter { } } - // Find the single IPv4 address if there is one, otherwise return null. - private static byte[] findIPv4Address(LinkProperties lp) { - byte[] ipv4Address = null; - for (InetAddress inetAddr : lp.getAddresses()) { - byte[] addr = inetAddr.getAddress(); - if (addr.length != 4) continue; - // More than one IPv4 address, abort - if (ipv4Address != null && !Arrays.equals(ipv4Address, addr)) return null; - ipv4Address = addr; + /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */ + private static LinkAddress findIPv4LinkAddress(LinkProperties lp) { + LinkAddress ipv4Address = null; + for (LinkAddress address : lp.getLinkAddresses()) { + if (!(address.getAddress() instanceof Inet4Address)) { + continue; + } + if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) { + // More than one IPv4 address, abort. + return null; + } + ipv4Address = address; } return ipv4Address; } public synchronized void setLinkProperties(LinkProperties lp) { // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state. - byte[] ipv4Address = findIPv4Address(lp); - // If ipv4Address is the same as mIPv4Address, then there's no change, just return. - if (Arrays.equals(ipv4Address, mIPv4Address)) return; - // Otherwise update mIPv4Address and install new program. - mIPv4Address = ipv4Address; + final LinkAddress ipv4Address = findIPv4LinkAddress(lp); + final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null; + final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0; + if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) { + return; + } + mIPv4Address = addr; + mIPv4PrefixLength = prefix; installNewProgramLocked(); } @@ -1127,4 +1137,38 @@ public class ApfFilter { pw.decreaseIndent(); } } + + private static int uint8(byte b) { + return b & 0xff; + } + + private static int uint16(short s) { + return s & 0xffff; + } + + private static long uint32(int i) { + return i & 0xffffffffL; + } + + private static long getUint16(ByteBuffer buffer, int position) { + return uint16(buffer.getShort(position)); + } + + private static long getUint32(ByteBuffer buffer, int position) { + return uint32(buffer.getInt(position)); + } + + // TODO: move to android.net.NetworkUtils + @VisibleForTesting + public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) { + return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength); + } + + @VisibleForTesting + public static int bytesToInt(byte[] addrBytes) { + return (uint8(addrBytes[0]) << 24) + + (uint8(addrBytes[1]) << 16) + + (uint8(addrBytes[2]) << 8) + + (uint8(addrBytes[3])); + } } diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java index bd761180c2a4..f7c61d15bb5f 100644 --- a/services/tests/servicestests/src/android/net/apf/ApfTest.java +++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java @@ -20,6 +20,9 @@ import static android.system.OsConstants.*; import com.android.frameworks.servicestests.R; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkUtils; import android.net.apf.ApfCapabilities; import android.net.apf.ApfFilter; import android.net.apf.ApfGenerator; @@ -28,8 +31,6 @@ import android.net.apf.ApfGenerator.Register; import android.net.ip.IpManager; import android.net.metrics.IpConnectivityLog; import android.net.metrics.RaEvent; -import android.net.LinkAddress; -import android.net.LinkProperties; import android.os.ConditionVariable; import android.os.Parcelable; import android.system.ErrnoException; @@ -61,7 +62,7 @@ import libcore.io.Streams; * Tests for APF program generator and interpreter. * * Build, install and run with: - * runtest frameworks-services -c com.android.server.ApfTest + * runtest frameworks-services -c android.net.apf.ApfTest */ public class ApfTest extends AndroidTestCase { private static final int TIMEOUT_MS = 500; @@ -86,21 +87,45 @@ public class ApfTest extends AndroidTestCase { private final static boolean DROP_MULTICAST = true; private final static boolean ALLOW_MULTICAST = false; + private static String label(int code) { + switch (code) { + case PASS: return "PASS"; + case DROP: return "DROP"; + default: return "UNKNOWN"; + } + } + + private static void assertReturnCodesEqual(int expected, int got) { + assertEquals(label(expected), label(got)); + } + private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) { - assertEquals(expected, apfSimulate(program, packet, filterAge)); + assertReturnCodesEqual(expected, apfSimulate(program, packet, filterAge)); + } + + private void assertVerdict(int expected, byte[] program, byte[] packet) { + assertReturnCodesEqual(expected, apfSimulate(program, packet, 0)); } private void assertPass(byte[] program, byte[] packet, int filterAge) { assertVerdict(PASS, program, packet, filterAge); } + private void assertPass(byte[] program, byte[] packet) { + assertVerdict(PASS, program, packet); + } + private void assertDrop(byte[] program, byte[] packet, int filterAge) { assertVerdict(DROP, program, packet, filterAge); } + private void assertDrop(byte[] program, byte[] packet) { + assertVerdict(DROP, program, packet); + } + private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge) throws IllegalInstructionException { - assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge)); + assertReturnCodesEqual(expected, apfSimulate(gen.generate(), packet, filterAge)); } private void assertPass(ApfGenerator gen, byte[] packet, int filterAge) @@ -516,7 +541,7 @@ public class ApfTest extends AndroidTestCase { gen = new ApfGenerator(); gen.addLoadImmediate(Register.R0, 1); gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); - byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0}; + byte[] packet123 = {0,123,0,0,0,0,0,0,0,0,0,0,0,0,0}; assertPass(gen, packet123, 0); gen = new ApfGenerator(); gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL); @@ -524,7 +549,7 @@ public class ApfTest extends AndroidTestCase { gen = new ApfGenerator(); gen.addLoadImmediate(Register.R0, 1); gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL); - byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0}; + byte[] packet12345 = {0,1,2,3,4,5,0,0,0,0,0,0,0,0,0}; assertDrop(gen, packet12345, 0); gen = new ApfGenerator(); gen.addLoadImmediate(Register.R0, 1); @@ -575,12 +600,12 @@ public class ApfTest extends AndroidTestCase { } private static class TestApfFilter extends ApfFilter { - public final static byte[] MOCK_MAC_ADDR = new byte[]{1,2,3,4,5,6}; + public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6}; private FileDescriptor mWriteSocket; public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) throws Exception { - super(new ApfCapabilities(2, 1536, ARPHRD_ETHER), NetworkInterface.getByName("lo"), + super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"), ipManagerCallback, multicastFilter, log); } @@ -620,19 +645,21 @@ public class ApfTest extends AndroidTestCase { private static final int ETH_HEADER_LEN = 14; private static final int ETH_DEST_ADDR_OFFSET = 0; private static final int ETH_ETHERTYPE_OFFSET = 12; - private static final byte[] ETH_BROADCAST_MAC_ADDRESS = new byte[]{ - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; + private static final byte[] ETH_BROADCAST_MAC_ADDRESS = + {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0; private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9; private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; + private static final byte[] IPV4_BROADCAST_ADDRESS = + {(byte) 255, (byte) 255, (byte) 255, (byte) 255}; private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6; private static final int IPV6_HEADER_LEN = 40; private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24; // The IPv6 all nodes address ff02::1 private static final byte[] IPV6_ALL_NODES_ADDRESS = - new byte[]{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; + { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; @@ -670,14 +697,14 @@ public class ApfTest extends AndroidTestCase { private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 48; private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN; - private static final byte[] ARP_IPV4_REQUEST_HEADER = new byte[]{ + private static final byte[] ARP_IPV4_REQUEST_HEADER = { 0, 1, // Hardware type: Ethernet (1) 8, 0, // Protocol type: IP (0x0800) 6, // Hardware size: 6 4, // Protocol size: 4 0, 1 // Opcode: request (1) }; - private static final byte[] ARP_IPV4_REPLY_HEADER = new byte[]{ + private static final byte[] ARP_IPV4_REPLY_HEADER = { 0, 1, // Hardware type: Ethernet (1) 8, 0, // Protocol type: IP (0x0800) 6, // Hardware size: 6 @@ -686,38 +713,63 @@ public class ApfTest extends AndroidTestCase { }; private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24; - private static final byte[] MOCK_IPV4_ADDR = new byte[]{10, 0, 0, 1}; - private static final byte[] ANOTHER_IPV4_ADDR = new byte[]{10, 0, 0, 2}; - private static final byte[] IPV4_ANY_HOST_ADDR = new byte[]{0, 0, 0, 0}; + private static final byte[] MOCK_IPV4_ADDR = {10, 0, 0, 1}; + private static final byte[] MOCK_BROADCAST_IPV4_ADDR = {10, 0, 31, (byte) 255}; // prefix = 19 + private static final byte[] MOCK_MULTICAST_IPV4_ADDR = {(byte) 224, 0, 0, 1}; + private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2}; + private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0}; @LargeTest public void testApfFilterIPv4() throws Exception { MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); + LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19); + LinkProperties lp = new LinkProperties(); + lp.addLinkAddress(link); + ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); + apfFilter.setLinkProperties(lp); + byte[] program = ipManagerCallback.getApfProgram(); // Verify empty packet of 100 zero bytes is passed ByteBuffer packet = ByteBuffer.wrap(new byte[100]); - assertPass(program, packet.array(), 0); + assertPass(program, packet.array()); // Verify unicast IPv4 packet is passed + put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR); packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); - assertPass(program, packet.array(), 0); - - // Verify broadcast IPv4, not DHCP to us, is dropped - packet.put(ETH_BROADCAST_MAC_ADDRESS); - assertDrop(program, packet.array(), 0); + put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_IPV4_ADDR); + assertPass(program, packet.array()); + + // Verify L2 unicast to IPv4 broadcast addresses is dropped (b/30231088) + put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); + assertDrop(program, packet.array()); + put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR); + assertDrop(program, packet.array()); + + // Verify multicast/broadcast IPv4, not DHCP to us, is dropped + put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); + assertDrop(program, packet.array()); packet.put(IPV4_VERSION_IHL_OFFSET, (byte)0x45); - assertDrop(program, packet.array(), 0); + assertDrop(program, packet.array()); packet.put(IPV4_PROTOCOL_OFFSET, (byte)IPPROTO_UDP); - assertDrop(program, packet.array(), 0); + assertDrop(program, packet.array()); packet.putShort(UDP_DESTINATION_PORT_OFFSET, (short)DHCP_CLIENT_PORT); - assertDrop(program, packet.array(), 0); + assertDrop(program, packet.array()); + put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_MULTICAST_IPV4_ADDR); + assertDrop(program, packet.array()); + put(packet, IPV4_DEST_ADDR_OFFSET, MOCK_BROADCAST_IPV4_ADDR); + assertDrop(program, packet.array()); + put(packet, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); + assertDrop(program, packet.array()); // Verify broadcast IPv4 DHCP to us is passed - packet.position(DHCP_CLIENT_MAC_OFFSET); - packet.put(TestApfFilter.MOCK_MAC_ADDR); - assertPass(program, packet.array(), 0); + put(packet, DHCP_CLIENT_MAC_OFFSET, TestApfFilter.MOCK_MAC_ADDR); + assertPass(program, packet.array()); + + // Verify unicast IPv4 DHCP to us is passed + put(packet, ETH_DEST_ADDR_OFFSET, TestApfFilter.MOCK_MAC_ADDR); + assertPass(program, packet.array()); apfFilter.shutdown(); } @@ -731,82 +783,108 @@ public class ApfTest extends AndroidTestCase { // Verify empty IPv6 packet is passed ByteBuffer packet = ByteBuffer.wrap(new byte[100]); packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); - assertPass(program, packet.array(), 0); + assertPass(program, packet.array()); // Verify empty ICMPv6 packet is passed packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); - assertPass(program, packet.array(), 0); + assertPass(program, packet.array()); // Verify empty ICMPv6 NA packet is passed packet.put(ICMP6_TYPE_OFFSET, (byte)ICMP6_NEIGHBOR_ANNOUNCEMENT); - assertPass(program, packet.array(), 0); + assertPass(program, packet.array()); // Verify ICMPv6 NA to ff02::1 is dropped - packet.position(IPV6_DEST_ADDR_OFFSET); - packet.put(IPV6_ALL_NODES_ADDRESS); - assertDrop(program, packet.array(), 0); + put(packet, IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS); + assertDrop(program, packet.array()); apfFilter.shutdown(); } @LargeTest public void testApfFilterMulticast() throws Exception { + final byte[] unicastIpv4Addr = {(byte)192,0,2,63}; + final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255}; + final byte[] multicastIpv4Addr = {(byte)224,0,0,1}; + final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb}; + MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback(); + LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24); + LinkProperties lp = new LinkProperties(); + lp.addLinkAddress(link); + ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST, mLog); + apfFilter.setLinkProperties(lp); + byte[] program = ipManagerCallback.getApfProgram(); // Construct IPv4 and IPv6 multicast packets. ByteBuffer mcastv4packet = ByteBuffer.wrap(new byte[100]); mcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); - mcastv4packet.position(IPV4_DEST_ADDR_OFFSET); - mcastv4packet.put(new byte[]{(byte)224,0,0,1}); + put(mcastv4packet, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr); ByteBuffer mcastv6packet = ByteBuffer.wrap(new byte[100]); mcastv6packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6); mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_UDP); - mcastv6packet.position(IPV6_DEST_ADDR_OFFSET); - mcastv6packet.put(new byte[]{(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb}); + put(mcastv6packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr); // Construct IPv4 broadcast packet. - ByteBuffer bcastv4packet = ByteBuffer.wrap(new byte[100]); - bcastv4packet.put(ETH_BROADCAST_MAC_ADDRESS); - bcastv4packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); - bcastv4packet.position(IPV4_DEST_ADDR_OFFSET); - bcastv4packet.put(new byte[]{(byte)192,(byte)0,(byte)2,(byte)63}); + ByteBuffer bcastv4packet1 = ByteBuffer.wrap(new byte[100]); + bcastv4packet1.put(ETH_BROADCAST_MAC_ADDRESS); + bcastv4packet1.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); + put(bcastv4packet1, IPV4_DEST_ADDR_OFFSET, multicastIpv4Addr); + + ByteBuffer bcastv4packet2 = ByteBuffer.wrap(new byte[100]); + bcastv4packet2.put(ETH_BROADCAST_MAC_ADDRESS); + bcastv4packet2.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); + put(bcastv4packet2, IPV4_DEST_ADDR_OFFSET, IPV4_BROADCAST_ADDRESS); + + // Construct IPv4 broadcast with L2 unicast address packet (b/30231088). + ByteBuffer bcastv4unicastl2packet = ByteBuffer.wrap(new byte[100]); + bcastv4unicastl2packet.put(TestApfFilter.MOCK_MAC_ADDR); + bcastv4unicastl2packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IP); + put(bcastv4unicastl2packet, IPV4_DEST_ADDR_OFFSET, broadcastIpv4Addr); // Verify initially disabled multicast filter is off - assertPass(program, bcastv4packet.array(), 0); - assertPass(program, mcastv4packet.array(), 0); - assertPass(program, mcastv6packet.array(), 0); + assertPass(program, mcastv4packet.array()); + assertPass(program, mcastv6packet.array()); + assertPass(program, bcastv4packet1.array()); + assertPass(program, bcastv4packet2.array()); + assertPass(program, bcastv4unicastl2packet.array()); // Turn on multicast filter and verify it works ipManagerCallback.resetApfProgramWait(); apfFilter.setMulticastFilter(true); program = ipManagerCallback.getApfProgram(); - assertDrop(program, bcastv4packet.array(), 0); - assertDrop(program, mcastv4packet.array(), 0); - assertDrop(program, mcastv6packet.array(), 0); + assertDrop(program, mcastv4packet.array()); + assertDrop(program, mcastv6packet.array()); + assertDrop(program, bcastv4packet1.array()); + assertDrop(program, bcastv4packet2.array()); + assertDrop(program, bcastv4unicastl2packet.array()); // Turn off multicast filter and verify it's off ipManagerCallback.resetApfProgramWait(); apfFilter.setMulticastFilter(false); program = ipManagerCallback.getApfProgram(); - assertPass(program, bcastv4packet.array(), 0); - assertPass(program, mcastv4packet.array(), 0); - assertPass(program, mcastv6packet.array(), 0); + assertPass(program, mcastv4packet.array()); + assertPass(program, mcastv6packet.array()); + assertPass(program, bcastv4packet1.array()); + assertPass(program, bcastv4packet2.array()); + assertPass(program, bcastv4unicastl2packet.array()); // Verify it can be initialized to on ipManagerCallback.resetApfProgramWait(); apfFilter.shutdown(); apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST, mLog); + apfFilter.setLinkProperties(lp); program = ipManagerCallback.getApfProgram(); - assertDrop(program, bcastv4packet.array(), 0); - assertDrop(program, mcastv4packet.array(), 0); - assertDrop(program, mcastv6packet.array(), 0); + assertDrop(program, mcastv4packet.array()); + assertDrop(program, mcastv6packet.array()); + assertDrop(program, bcastv4packet1.array()); + assertDrop(program, bcastv4unicastl2packet.array()); // Verify that ICMPv6 multicast is not dropped. mcastv6packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6); - assertPass(program, mcastv6packet.array(), 0); + assertPass(program, mcastv6packet.array()); apfFilter.shutdown(); } @@ -819,17 +897,17 @@ public class ApfTest extends AndroidTestCase { private void verifyArpFilter(byte[] program, int filterResult) { // Verify ARP request packet - assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR), 0); - assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR), 0); - assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR), 0); + assertPass(program, arpRequestBroadcast(MOCK_IPV4_ADDR)); + assertVerdict(filterResult, program, arpRequestBroadcast(ANOTHER_IPV4_ADDR)); + assertDrop(program, arpRequestBroadcast(IPV4_ANY_HOST_ADDR)); // Verify unicast ARP reply packet is always accepted. - assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR), 0); - assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR), 0); - assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR), 0); + assertPass(program, arpReplyUnicast(MOCK_IPV4_ADDR)); + assertPass(program, arpReplyUnicast(ANOTHER_IPV4_ADDR)); + assertPass(program, arpReplyUnicast(IPV4_ANY_HOST_ADDR)); // Verify GARP reply packets are always filtered - assertDrop(program, garpReply(), 0); + assertDrop(program, garpReply()); } @LargeTest @@ -855,34 +933,26 @@ public class ApfTest extends AndroidTestCase { private static byte[] arpRequestBroadcast(byte[] tip) { ByteBuffer packet = ByteBuffer.wrap(new byte[100]); packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); - packet.position(ETH_DEST_ADDR_OFFSET); - packet.put(ETH_BROADCAST_MAC_ADDRESS); - packet.position(ARP_HEADER_OFFSET); - packet.put(ARP_IPV4_REQUEST_HEADER); - packet.position(ARP_TARGET_IP_ADDRESS_OFFSET); - packet.put(tip); + put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); + put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); + put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); return packet.array(); } private static byte[] arpReplyUnicast(byte[] tip) { ByteBuffer packet = ByteBuffer.wrap(new byte[100]); packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); - packet.position(ARP_HEADER_OFFSET); - packet.put(ARP_IPV4_REPLY_HEADER); - packet.position(ARP_TARGET_IP_ADDRESS_OFFSET); - packet.put(tip); + put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); + put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, tip); return packet.array(); } private static byte[] garpReply() { ByteBuffer packet = ByteBuffer.wrap(new byte[100]); packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_ARP); - packet.position(ETH_DEST_ADDR_OFFSET); - packet.put(ETH_BROADCAST_MAC_ADDRESS); - packet.position(ARP_HEADER_OFFSET); - packet.put(ARP_IPV4_REPLY_HEADER); - packet.position(ARP_TARGET_IP_ADDRESS_OFFSET); - packet.put(IPV4_ANY_HOST_ADDR); + put(packet, ETH_DEST_ADDR_OFFSET, ETH_BROADCAST_MAC_ADDRESS); + put(packet, ARP_HEADER_OFFSET, ARP_IPV4_REPLY_HEADER); + put(packet, ARP_TARGET_IP_ADDRESS_OFFSET, IPV4_ANY_HOST_ADDR); return packet.array(); } @@ -893,22 +963,22 @@ public class ApfTest extends AndroidTestCase { byte[] program = ipManagerCallback.getApfProgram(); // Verify new program should drop RA for 1/6th its lifetime - assertDrop(program, packet.array(), 0); + assertDrop(program, packet.array()); assertDrop(program, packet.array(), lifetime/6); assertPass(program, packet.array(), lifetime/6 + 1); assertPass(program, packet.array(), lifetime); // Verify RA checksum is ignored packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)12345); - assertDrop(program, packet.array(), 0); + assertDrop(program, packet.array()); packet.putShort(ICMP6_RA_CHECKSUM_OFFSET, (short)-12345); - assertDrop(program, packet.array(), 0); + assertDrop(program, packet.array()); // Verify other changes to RA make it not match filter packet.put(0, (byte)-1); - assertPass(program, packet.array(), 0); + assertPass(program, packet.array()); packet.put(0, (byte)0); - assertDrop(program, packet.array(), 0); + assertDrop(program, packet.array()); } // Test that when ApfFilter is shown the given packet, it generates a program to filter it @@ -973,7 +1043,7 @@ public class ApfTest extends AndroidTestCase { basePacket.putShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET, (short)1000); basePacket.position(IPV6_DEST_ADDR_OFFSET); basePacket.put(IPV6_ALL_NODES_ADDRESS); - assertPass(program, basePacket.array(), 0); + assertPass(program, basePacket.array()); testRaLifetime(apfFilter, ipManagerCallback, basePacket, 1000); verifyRaEvent(new RaEvent(1000, -1, -1, -1, -1, -1)); @@ -1069,6 +1139,13 @@ public class ApfTest extends AndroidTestCase { return file.getAbsolutePath(); } + private static void put(ByteBuffer buffer, int position, byte[] bytes) { + final int original = buffer.position(); + buffer.position(position); + buffer.put(bytes); + buffer.position(original); + } + /** * Call the APF interpreter the run {@code program} on {@code packet} pretending the * filter was installed {@code filter_age} seconds ago. @@ -1089,4 +1166,30 @@ public class ApfTest extends AndroidTestCase { */ private native static boolean compareBpfApf(String filter, String pcap_filename, byte[] apf_program); + + public void testBytesToInt() { + assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR)); + assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS)); + assertEquals(0x0a000001, ApfFilter.bytesToInt(MOCK_IPV4_ADDR)); + assertEquals(0x0a000002, ApfFilter.bytesToInt(ANOTHER_IPV4_ADDR)); + assertEquals(0x0a001fff, ApfFilter.bytesToInt(MOCK_BROADCAST_IPV4_ADDR)); + assertEquals(0xe0000001, ApfFilter.bytesToInt(MOCK_MULTICAST_IPV4_ADDR)); + } + + public void testBroadcastAddress() throws Exception { + assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0)); + assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32)); + assertEqualsIp("0.0.3.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 22)); + assertEqualsIp("0.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 8)); + + assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 0)); + assertEqualsIp("10.0.0.1", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 32)); + assertEqualsIp("10.0.0.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 24)); + assertEqualsIp("10.0.255.255", ApfFilter.ipv4BroadcastAddress(MOCK_IPV4_ADDR, 16)); + } + + public void assertEqualsIp(String expected, int got) throws Exception { + int want = ApfFilter.bytesToInt(InetAddress.getByName(expected).getAddress()); + assertEquals(want, got); + } } diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 59ccbd93f3fb..d52671ab8843 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -717,6 +717,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } public void tearDown() throws Exception { + setMobileDataAlwaysOn(false); if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); } if (mWiFiNetworkAgent != null) { mWiFiNetworkAgent.disconnect(); } mCellNetworkAgent = mWiFiNetworkAgent = null; @@ -1814,6 +1815,85 @@ public class ConnectivityServiceTest extends AndroidTestCase { mCm.unregisterNetworkCallback(cellNetworkCallback); } + private void setMobileDataAlwaysOn(boolean enable) { + ContentResolver cr = mServiceContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0); + mService.updateMobileDataAlwaysOn(); + mService.waitForIdle(); + } + + private boolean isForegroundNetwork(MockNetworkAgent network) { + NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork()); + assertNotNull(nc); + return nc.hasCapability(NET_CAPABILITY_FOREGROUND); + } + + @SmallTest + public void testBackgroundNetworks() throws Exception { + // Create a background request. We can't do this ourselves because ConnectivityService + // doesn't have an API for it. So just turn on mobile data always on. + setMobileDataAlwaysOn(true); + final NetworkRequest request = new NetworkRequest.Builder().build(); + final NetworkRequest fgRequest = new NetworkRequest.Builder() + .addCapability(NET_CAPABILITY_FOREGROUND).build(); + final TestNetworkCallback callback = new TestNetworkCallback(); + final TestNetworkCallback fgCallback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + mCm.registerNetworkCallback(fgRequest, fgCallback); + + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(true); + callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); + fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); + assertTrue(isForegroundNetwork(mCellNetworkAgent)); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + + // When wifi connects, cell lingers. + callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); + fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent); + callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); + fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent); + assertTrue(isForegroundNetwork(mCellNetworkAgent)); + assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + + // When lingering is complete, cell is still there but is now in the background. + fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, TEST_LINGER_DELAY_MS); + callback.assertNoCallback(); + assertFalse(isForegroundNetwork(mCellNetworkAgent)); + assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + + // File a cell request and check that cell comes into the foreground. + final NetworkRequest cellRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR).build(); + final TestNetworkCallback cellCallback = new TestNetworkCallback(); + mCm.requestNetwork(cellRequest, cellCallback); + cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); + fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); + callback.assertNoCallback(); // Because the network is already up. + assertTrue(isForegroundNetwork(mCellNetworkAgent)); + assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + + // Release the request. The network immediately goes into the background, since it was not + // lingering. + mCm.unregisterNetworkCallback(cellCallback); + fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); + callback.assertNoCallback(); + assertFalse(isForegroundNetwork(mCellNetworkAgent)); + assertTrue(isForegroundNetwork(mWiFiNetworkAgent)); + + // Disconnect wifi and check that cell is foreground again. + mWiFiNetworkAgent.disconnect(); + callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); + fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent); + assertTrue(isForegroundNetwork(mCellNetworkAgent)); + + mCm.unregisterNetworkCallback(callback); + mCm.unregisterNetworkCallback(fgCallback); + } + @SmallTest public void testRequestBenchmark() throws Exception { // Benchmarks connecting and switching performance in the presence of a large number of @@ -1919,8 +1999,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Turn on mobile data always on. The factory starts looking again. testFactory.expectAddRequests(1); - Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 1); - mService.updateMobileDataAlwaysOn(); + setMobileDataAlwaysOn(true); testFactory.waitForNetworkRequests(2); assertTrue(testFactory.getMyStartRequested()); @@ -1940,8 +2019,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Turn off mobile data always on and expect the request to disappear... testFactory.expectRemoveRequests(1); - Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 0); - mService.updateMobileDataAlwaysOn(); + setMobileDataAlwaysOn(false); testFactory.waitForNetworkRequests(1); // ... and cell data to be torn down. diff --git a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java index 7571f79ea1e3..984a484dadc2 100644 --- a/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java +++ b/services/tests/servicestests/src/com/android/server/am/TaskPersisterTest.java @@ -16,36 +16,19 @@ package com.android.server.am; -import android.app.ActivityManager; -import android.content.ContentResolver; -import android.content.pm.ActivityInfo; import android.content.pm.UserInfo; import android.os.Environment; -import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; -import android.provider.Settings; import android.test.AndroidTestCase; import android.util.Log; import android.util.SparseBooleanArray; -import android.util.Xml; -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.XmlUtils; import com.android.server.am.TaskPersister; import java.io.File; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; import java.util.Random; -import libcore.io.IoUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - public class TaskPersisterTest extends AndroidTestCase { private static final String TEST_USER_NAME = "AM-Test-User"; @@ -86,140 +69,6 @@ public class TaskPersisterTest extends AndroidTestCase { taskIdsOnFile.equals(newTaskIdsOnFile)); } - public void testActiveTimeMigration() { - // Simulate a migration scenario by setting the last write uptime to zero - ContentResolver cr = getContext().getContentResolver(); - Settings.Secure.putLong(cr, - Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, 0); - - // Create a dummy task record with an absolute time 1s before now - long pastOffset = 1000; - long activeTime = System.currentTimeMillis() - pastOffset; - TaskRecord tr0 = createDummyTaskRecordWithActiveTime(activeTime, activeTime); - - // Save and load the tasks with no last persist uptime (0) - String tr0XmlStr = serializeTaskRecordToXmlString(tr0); - TaskRecord xtr0 = unserializeTaskRecordFromXmlString(tr0XmlStr, 0); - - // Ensure that the absolute time has been migrated to be relative to the current elapsed - // time - assertTrue("Expected firstActiveTime to be migrated from: " + tr0.firstActiveTime + - " instead found: " + xtr0.firstActiveTime, - xtr0.firstActiveTime <= -pastOffset); - assertTrue("Expected lastActiveTime to be migrated from: " + tr0.lastActiveTime + - " instead found: " + xtr0.lastActiveTime, - xtr0.lastActiveTime <= -pastOffset); - - // Ensure that the last active uptime is not set so that SystemUI can migrate it itself - // assuming that the last persist time is zero - Settings.Secure.putLongForUser(cr, - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, 0, testUserId); - mTaskPersister.restoreTasksForUserLocked(testUserId); - long lastVisTaskActiveTime = Settings.Secure.getLongForUser(cr, - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, -1, testUserId); - assertTrue("Expected last visible task active time is zero", lastVisTaskActiveTime == 0); - } - - public void testActiveTimeOffsets() { - // Simulate a normal boot scenario by setting the last write uptime - long lastWritePastOffset = 1000; - long lastVisActivePastOffset = 500; - ContentResolver cr = getContext().getContentResolver(); - Settings.Secure.putLong(cr, - Settings.Secure.TASK_PERSISTER_LAST_WRITE_UPTIME, lastWritePastOffset); - - // Create a dummy task record with an absolute time 1s before now - long activeTime = 250; - TaskRecord tr0 = createDummyTaskRecordWithActiveTime(activeTime, activeTime); - - // Save and load the tasks with the last persist time - String tr0XmlStr = serializeTaskRecordToXmlString(tr0); - TaskRecord xtr0 = unserializeTaskRecordFromXmlString(tr0XmlStr, lastWritePastOffset); - - // Ensure that the prior elapsed time has been offset to be relative to the current boot - // time - assertTrue("Expected firstActiveTime to be offset from: " + tr0.firstActiveTime + - " instead found: " + xtr0.firstActiveTime, - xtr0.firstActiveTime <= (-lastWritePastOffset + activeTime)); - assertTrue("Expected lastActiveTime to be offset from: " + tr0.lastActiveTime + - " instead found: " + xtr0.lastActiveTime, - xtr0.lastActiveTime <= (-lastWritePastOffset + activeTime)); - - // Ensure that we update the last active uptime as well by simulating a restoreTasks call - Settings.Secure.putLongForUser(cr, - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, lastVisActivePastOffset, - testUserId); - mTaskPersister.restoreTasksForUserLocked(testUserId); - long lastVisTaskActiveTime = Settings.Secure.getLongForUser(cr, - Settings.Secure.OVERVIEW_LAST_VISIBLE_TASK_ACTIVE_UPTIME, Long.MAX_VALUE, - testUserId); - assertTrue("Expected last visible task active time to be offset", lastVisTaskActiveTime <= - (-lastWritePastOffset + lastVisActivePastOffset)); - } - - private TaskRecord createDummyTaskRecordWithActiveTime(long firstActiveTime, - long lastActiveTime) { - ActivityInfo info = createDummyActivityInfo(); - ActivityManager.TaskDescription td = new ActivityManager.TaskDescription(); - TaskRecord t = new TaskRecord(null, 0, info, null, td, null); - t.firstActiveTime = firstActiveTime; - t.lastActiveTime = lastActiveTime; - return t; - } - - private ActivityInfo createDummyActivityInfo() { - ActivityInfo info = new ActivityInfo(); - info.applicationInfo = getContext().getApplicationInfo(); - return info; - } - - private String serializeTaskRecordToXmlString(TaskRecord tr) { - StringWriter stringWriter = new StringWriter(); - - try { - final XmlSerializer xmlSerializer = new FastXmlSerializer(); - xmlSerializer.setOutput(stringWriter); - - xmlSerializer.startDocument(null, true); - xmlSerializer.startTag(null, TaskPersister.TAG_TASK); - tr.saveToXml(xmlSerializer); - xmlSerializer.endTag(null, TaskPersister.TAG_TASK); - xmlSerializer.endDocument(); - xmlSerializer.flush(); - } catch (Exception e) { - e.printStackTrace(); - } - - return stringWriter.toString(); - } - - private TaskRecord unserializeTaskRecordFromXmlString(String xmlStr, long lastPersistUptime) { - StringReader reader = null; - TaskRecord task = null; - try { - reader = new StringReader(xmlStr); - final XmlPullParser in = Xml.newPullParser(); - in.setInput(reader); - - int event; - while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && - event != XmlPullParser.END_TAG) { - final String name = in.getName(); - if (event == XmlPullParser.START_TAG) { - if (TaskPersister.TAG_TASK.equals(name)) { - task = TaskRecord.restoreFromXml(in, null, null, lastPersistUptime); - } - } - XmlUtils.skipCurrentTag(in); - } - } catch (Exception e) { - return null; - } finally { - IoUtils.closeQuietly(reader); - } - return task; - } - private int createUser(String name, int flags) { UserInfo user = mUserManager.createUser(name, flags); if (user == null) { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index d6a2ee3c2400..5081c25f2003 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -433,18 +433,11 @@ public class CarrierConfigManager { "disable_severe_when_extreme_disabled_bool"; /** - * The data call APN retry configuration for default type APN. + * The data call retry configuration for different types of APN. * @hide */ - public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING = - "carrier_data_call_retry_config_default_string"; - - /** - * The data call APN retry configuration for other type APNs. - * @hide - */ - public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING = - "carrier_data_call_retry_config_others_string"; + public static final String KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS = + "carrier_data_call_retry_config_strings"; /** * Delay between trying APN from the pool @@ -1022,11 +1015,12 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false); sDefaults.putBoolean(KEY_DISABLE_SEVERE_WHEN_EXTREME_DISABLED_BOOL, true); - sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_DEFAULT_STRING, - "default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000," - + "320000:5000,640000:5000,1280000:5000,1800000:5000"); - sDefaults.putString(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_OTHERS_STRING, - "max_retries=3, 5000, 5000, 5000"); + sDefaults.putStringArray(KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, new String[]{ + "default:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000," + + "320000:5000,640000:5000,1280000:5000,1800000:5000", + "mms:default_randomization=2000,5000,10000,20000,40000,80000:5000,160000:5000," + + "320000:5000,640000:5000,1280000:5000,1800000:5000", + "others:max_retries=3, 5000, 5000, 5000"}); sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000); sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000); sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml"); diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 03d6d2130ec0..7350eeced479 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -24,6 +24,7 @@ import com.android.i18n.phonenumbers.ShortNumberUtil; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.database.Cursor; import android.location.CountryDetector; import android.net.Uri; @@ -3021,4 +3022,79 @@ public class PhoneNumberUtils return SubscriptionManager.getDefaultVoiceSubscriptionId(); } //==== End of utility methods used only in compareStrictly() ===== + + + /* + * The config held calling number conversion map, expected to convert to emergency number. + */ + private static final String[] CONVERT_TO_EMERGENCY_MAP = Resources.getSystem().getStringArray( + com.android.internal.R.array.config_convert_to_emergency_number_map); + /** + * Check whether conversion to emergency number is enabled + * + * @return {@code true} when conversion to emergency numbers is enabled, + * {@code false} otherwise + * + * @hide + */ + public static boolean isConvertToEmergencyNumberEnabled() { + return CONVERT_TO_EMERGENCY_MAP != null && CONVERT_TO_EMERGENCY_MAP.length > 0; + } + + /** + * Converts to emergency number based on the conversion map. + * The conversion map is declared as config_convert_to_emergency_number_map. + * + * Make sure {@link #isConvertToEmergencyNumberEnabled} is true before calling + * this function. + * + * @return The converted emergency number if the number matches conversion map, + * otherwise original number. + * + * @hide + */ + public static String convertToEmergencyNumber(String number) { + if (TextUtils.isEmpty(number)) { + return number; + } + + String normalizedNumber = normalizeNumber(number); + + // The number is already emergency number. Skip conversion. + if (isEmergencyNumber(normalizedNumber)) { + return number; + } + + for (String convertMap : CONVERT_TO_EMERGENCY_MAP) { + if (DBG) log("convertToEmergencyNumber: " + convertMap); + String[] entry = null; + String[] filterNumbers = null; + String convertedNumber = null; + if (!TextUtils.isEmpty(convertMap)) { + entry = convertMap.split(":"); + } + if (entry != null && entry.length == 2) { + convertedNumber = entry[1]; + if (!TextUtils.isEmpty(entry[0])) { + filterNumbers = entry[0].split(","); + } + } + // Skip if the format of entry is invalid + if (TextUtils.isEmpty(convertedNumber) || filterNumbers == null + || filterNumbers.length == 0) { + continue; + } + + for (String filterNumber : filterNumbers) { + if (DBG) log("convertToEmergencyNumber: filterNumber = " + filterNumber + + ", convertedNumber = " + convertedNumber); + if (!TextUtils.isEmpty(filterNumber) && filterNumber.equals(normalizedNumber)) { + if (DBG) log("convertToEmergencyNumber: Matched. Successfully converted to: " + + convertedNumber); + return convertedNumber; + } + } + } + return number; + } } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 58df301b1cfc..76522f95fbd4 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -96,7 +96,7 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void clearForcedDisplayDensity(int displayId) throws RemoteException { + public void clearForcedDisplayDensityForUser(int displayId, int userId) throws RemoteException { // TODO Auto-generated method stub } @@ -397,7 +397,8 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public void setForcedDisplayDensity(int displayId, int density) throws RemoteException { + public void setForcedDisplayDensityForUser(int displayId, int density, int userId) + throws RemoteException { // TODO Auto-generated method stub } diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index 716f1d32ec84..3190ead48da0 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -286,6 +286,12 @@ public class WifiScanner { * {@hide} */ private int mBucketsScanned; + /** + * Indicates that the scan results received are as a result of a scan of all available + * channels. This should only be expected to function for single scans. + * {@hide} + */ + private boolean mAllChannelsScanned; /** all scan results discovered in this scan, sorted by timestamp in ascending order */ private ScanResult mResults[]; @@ -298,10 +304,12 @@ public class WifiScanner { } /** {@hide} */ - public ScanData(int id, int flags, int bucketsScanned, ScanResult[] results) { + public ScanData(int id, int flags, int bucketsScanned, boolean allChannelsScanned, + ScanResult[] results) { mId = id; mFlags = flags; mBucketsScanned = bucketsScanned; + mAllChannelsScanned = allChannelsScanned; mResults = results; } @@ -309,6 +317,7 @@ public class WifiScanner { mId = s.mId; mFlags = s.mFlags; mBucketsScanned = s.mBucketsScanned; + mAllChannelsScanned = s.mAllChannelsScanned; mResults = new ScanResult[s.mResults.length]; for (int i = 0; i < s.mResults.length; i++) { ScanResult result = s.mResults[i]; @@ -330,6 +339,11 @@ public class WifiScanner { return mBucketsScanned; } + /** {@hide} */ + public boolean isAllChannelsScanned() { + return mAllChannelsScanned; + } + public ScanResult[] getResults() { return mResults; } @@ -345,6 +359,7 @@ public class WifiScanner { dest.writeInt(mId); dest.writeInt(mFlags); dest.writeInt(mBucketsScanned); + dest.writeInt(mAllChannelsScanned ? 1 : 0); dest.writeInt(mResults.length); for (int i = 0; i < mResults.length; i++) { ScanResult result = mResults[i]; @@ -362,12 +377,13 @@ public class WifiScanner { int id = in.readInt(); int flags = in.readInt(); int bucketsScanned = in.readInt(); + boolean allChannelsScanned = in.readInt() != 0; int n = in.readInt(); ScanResult results[] = new ScanResult[n]; for (int i = 0; i < n; i++) { results[i] = ScanResult.CREATOR.createFromParcel(in); } - return new ScanData(id, flags, bucketsScanned, results); + return new ScanData(id, flags, bucketsScanned, allChannelsScanned, results); } public ScanData[] newArray(int size) { |