From 9ae68f467ec168e584821ddc0148d26e82bdd99d Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 8 Nov 2019 16:45:16 -0800 Subject: [PATCH 001/143] FocusRequester: fix NPE Fix NPE and potential race condition in FocusRequester.dispatchFocusResultFromExtPolicy where mFocusDispatcher was checked against null, but the method didn't return in that case. Bug: 142278598 Test: Android Auto with phone call and custom focus policy Change-Id: I88447a255132c94f8c2fbf97a1e3ee88f6d2e993 Merged-In: I88447a255132c94f8c2fbf97a1e3ee88f6d2e993 --- .../java/com/android/server/audio/FocusRequester.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java index db55138e446d..7578948adb14 100644 --- a/services/core/java/com/android/server/audio/FocusRequester.java +++ b/services/core/java/com/android/server/audio/FocusRequester.java @@ -416,7 +416,8 @@ public class FocusRequester { } int dispatchFocusChange(int focusChange) { - if (mFocusDispatcher == null) { + final IAudioFocusDispatcher fd = mFocusDispatcher; + if (fd == null) { if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); } return AudioManager.AUDIOFOCUS_REQUEST_FAILED; } @@ -436,7 +437,7 @@ public class FocusRequester { mFocusLossReceived = focusChange; } try { - mFocusDispatcher.dispatchAudioFocusChange(focusChange, mClientId); + fd.dispatchAudioFocusChange(focusChange, mClientId); } catch (android.os.RemoteException e) { Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e); return AudioManager.AUDIOFOCUS_REQUEST_FAILED; @@ -445,16 +446,18 @@ public class FocusRequester { } void dispatchFocusResultFromExtPolicy(int requestResult) { - if (mFocusDispatcher == null) { + final IAudioFocusDispatcher fd = mFocusDispatcher; + if (fd == null) { if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher"); } + return; } if (DEBUG) { Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId); } try { - mFocusDispatcher.dispatchFocusResultFromExtPolicy(requestResult, mClientId); + fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId); } catch (android.os.RemoteException e) { Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener" + mClientId, e); -- GitLab From b6dce0b74f88c396053527438a993091c7daca40 Mon Sep 17 00:00:00 2001 From: davidln Date: Mon, 17 Jun 2019 14:48:11 -0700 Subject: [PATCH 002/143] Concurrent collections for Bluetooth callbacks. This allows callback classes to remove themselves or add additional callbacks in response to state change dispatches. Bug: 129060225 Bug: 144357642 Test: build and deploy, pair multiple devices, switch users Change-Id: I8eed81bbc9c12321ec41b2491d006764e2e483d6 Merged-In: I8eed81bbc9c12321ec41b2491d006764e2e483d6 --- .../bluetooth/BluetoothEventManager.java | 109 +++++++----------- .../bluetooth/CachedBluetoothDevice.java | 17 +-- 2 files changed, 47 insertions(+), 79 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java index 402ce90d6ec5..df30c248c00c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java @@ -35,12 +35,12 @@ import androidx.annotation.VisibleForTesting; import com.android.settingslib.R; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; /** * BluetoothEventManager receives broadcasts and callbacks from the Bluetooth @@ -56,7 +56,7 @@ public class BluetoothEventManager { private final Map mHandlerMap; private final BroadcastReceiver mBroadcastReceiver = new BluetoothBroadcastReceiver(); private final BroadcastReceiver mProfileBroadcastReceiver = new BluetoothBroadcastReceiver(); - private final Collection mCallbacks = new ArrayList<>(); + private final Collection mCallbacks = new CopyOnWriteArrayList<>(); private final android.os.Handler mReceiverHandler; private final UserHandle mUserHandle; private final Context mContext; @@ -93,8 +93,10 @@ public class BluetoothEventManager { new ConnectionStateChangedHandler()); // Discovery broadcasts - addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true)); - addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false)); + addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, + new ScanningStateChangedHandler(true)); + addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, + new ScanningStateChangedHandler(false)); addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler()); addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler()); addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler()); @@ -128,16 +130,12 @@ public class BluetoothEventManager { /** Register to start receiving callbacks for Bluetooth events. */ public void registerCallback(BluetoothCallback callback) { - synchronized (mCallbacks) { - mCallbacks.add(callback); - } + mCallbacks.add(callback); } /** Unregister to stop receiving callbacks for Bluetooth events. */ public void unregisterCallback(BluetoothCallback callback) { - synchronized (mCallbacks) { - mCallbacks.remove(callback); - } + mCallbacks.remove(callback); } @VisibleForTesting @@ -189,63 +187,48 @@ public class BluetoothEventManager { } void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onDeviceAdded(cachedDevice); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onDeviceAdded(cachedDevice); } } void dispatchDeviceRemoved(CachedBluetoothDevice cachedDevice) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onDeviceDeleted(cachedDevice); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onDeviceDeleted(cachedDevice); } } void dispatchProfileConnectionStateChanged(CachedBluetoothDevice device, int state, int bluetoothProfile) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onProfileConnectionStateChanged(device, state, bluetoothProfile); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onProfileConnectionStateChanged(device, state, bluetoothProfile); } } private void dispatchConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onConnectionStateChanged(cachedDevice, state); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onConnectionStateChanged(cachedDevice, state); } } private void dispatchAudioModeChanged() { mDeviceManager.dispatchAudioModeChanged(); - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onAudioModeChanged(); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onAudioModeChanged(); } } private void dispatchActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { mDeviceManager.onActiveDeviceChanged(activeDevice, bluetoothProfile); - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onActiveDeviceChanged(activeDevice, bluetoothProfile); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onActiveDeviceChanged(activeDevice, bluetoothProfile); } } - private void dispatchAclStateChanged(CachedBluetoothDevice activeDevice, - int state) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onAclConnectionStateChanged(activeDevice, state); - } + private void dispatchAclStateChanged(CachedBluetoothDevice activeDevice, int state) { + for (BluetoothCallback callback : mCallbacks) { + callback.onAclConnectionStateChanged(activeDevice, state); } } @@ -270,17 +253,14 @@ public class BluetoothEventManager { } private class AdapterStateChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { + public void onReceive(Context context, Intent intent, BluetoothDevice device) { int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); // update local profiles and get paired devices mLocalAdapter.setBluetoothStateInt(state); // send callback to update UI and possibly start scanning - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onBluetoothStateChanged(state); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onBluetoothStateChanged(state); } // Inform CachedDeviceManager that the adapter state has changed mDeviceManager.onBluetoothStateChanged(state); @@ -293,12 +273,10 @@ public class BluetoothEventManager { ScanningStateChangedHandler(boolean started) { mStarted = started; } - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onScanningStateChanged(mStarted); - } + + public void onReceive(Context context, Intent intent, BluetoothDevice device) { + for (BluetoothCallback callback : mCallbacks) { + callback.onScanningStateChanged(mStarted); } mDeviceManager.onScanningStateChanged(mStarted); } @@ -317,7 +295,7 @@ public class BluetoothEventManager { Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: " + cachedDevice); } else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED - &&!cachedDevice.getDevice().isConnected()) { + && !cachedDevice.getDevice().isConnected()) { // Dispatch device add callback to show bonded but // not connected devices in discovery mode dispatchDeviceAdded(cachedDevice); @@ -350,8 +328,7 @@ public class BluetoothEventManager { } private class BondStateChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { + public void onReceive(Context context, Intent intent, BluetoothDevice device) { if (device == null) { Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE"); return; @@ -365,10 +342,8 @@ public class BluetoothEventManager { cachedDevice = mDeviceManager.addDevice(device); } - synchronized (mCallbacks) { - for (BluetoothCallback callback : mCallbacks) { - callback.onDeviceBondStateChanged(cachedDevice, bondState); - } + for (BluetoothCallback callback : mCallbacks) { + callback.onDeviceBondStateChanged(cachedDevice, bondState); } cachedDevice.onBondingStateChanged(bondState); @@ -388,12 +363,12 @@ public class BluetoothEventManager { * Called when we have reached the unbonded state. * * @param reason one of the error reasons from - * BluetoothDevice.UNBOND_REASON_* + * BluetoothDevice.UNBOND_REASON_* */ private void showUnbondMessage(Context context, String name, int reason) { int errorMsg; - switch(reason) { + switch (reason) { case BluetoothDevice.UNBOND_REASON_AUTH_FAILED: errorMsg = R.string.bluetooth_pairing_pin_error_message; break; @@ -410,7 +385,8 @@ public class BluetoothEventManager { errorMsg = R.string.bluetooth_pairing_error_message; break; default: - Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason); + Log.w(TAG, + "showUnbondMessage: Not displaying any message for reason: " + reason); return; } BluetoothUtils.showError(context, name, errorMsg); @@ -418,8 +394,7 @@ public class BluetoothEventManager { } private class ClassChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { + public void onReceive(Context context, Intent intent, BluetoothDevice device) { CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); if (cachedDevice != null) { cachedDevice.refresh(); @@ -428,8 +403,7 @@ public class BluetoothEventManager { } private class UuidChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { + public void onReceive(Context context, Intent intent, BluetoothDevice device) { CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); if (cachedDevice != null) { cachedDevice.onUuidChanged(); @@ -438,8 +412,7 @@ public class BluetoothEventManager { } private class BatteryLevelChangedHandler implements Handler { - public void onReceive(Context context, Intent intent, - BluetoothDevice device) { + public void onReceive(Context context, Intent intent, BluetoothDevice device) { CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); if (cachedDevice != null) { cachedDevice.refresh(); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 8f164f1592d3..98db7c8fb59c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * CachedBluetoothDevice represents a remote Bluetooth device. It contains @@ -75,7 +76,7 @@ public class CachedBluetoothDevice implements Comparable boolean mJustDiscovered; - private final Collection mCallbacks = new ArrayList<>(); + private final Collection mCallbacks = new CopyOnWriteArrayList<>(); /** * Last time a bt profile auto-connect was attempted. @@ -679,22 +680,16 @@ public class CachedBluetoothDevice implements Comparable } public void registerCallback(Callback callback) { - synchronized (mCallbacks) { - mCallbacks.add(callback); - } + mCallbacks.add(callback); } public void unregisterCallback(Callback callback) { - synchronized (mCallbacks) { - mCallbacks.remove(callback); - } + mCallbacks.remove(callback); } void dispatchAttributesChanged() { - synchronized (mCallbacks) { - for (Callback callback : mCallbacks) { - callback.onDeviceAttributesChanged(); - } + for (Callback callback : mCallbacks) { + callback.onDeviceAttributesChanged(); } } -- GitLab From de626c28d7abf02cdf9bd0ed4a3a82d96e4dd423 Mon Sep 17 00:00:00 2001 From: Patrick Baumann Date: Mon, 9 Dec 2019 14:22:32 -0800 Subject: [PATCH 003/143] DO NOT MERGE: Adds artificial package handler latency This change introduces a means of introducing an artificial long task to the package handler to help reproduce timing issues related to it. Bug: 141413692 Test: atest PackageManagerTest Change-Id: I61ddee1fe8b94f5803d981a77babb4bb19e31662 --- .../android/app/ActivityManagerInternal.java | 4 ++- .../content/pm/PackageManagerInternal.java | 12 +++++++++ core/java/android/os/IUserManager.aidl | 1 + .../server/am/ActivityManagerService.java | 22 +++++++++++++++- .../server/pm/PackageManagerService.java | 22 ++++++++++++++-- .../android/server/pm/UserManagerService.java | 25 +++++++++++++++++++ 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 8508c2c95666..f5f4afb21588 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -29,7 +29,6 @@ import android.content.pm.UserInfo; import android.os.Bundle; import android.os.IBinder; import android.os.TransactionTooLargeException; -import android.view.RemoteAnimationAdapter; import java.util.ArrayList; import java.util.List; @@ -356,4 +355,7 @@ public abstract class ActivityManagerInternal { * Unregisters the specified {@code processObserver}. */ public abstract void unregisterProcessObserver(IProcessObserver processObserver); + + /** Returns true if the given UID is registered as an active instrumentation. */ + public abstract boolean isActiveInstrumentation(int uid); } diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 672994e79134..3e880f03b222 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -999,4 +999,16 @@ public abstract class PackageManagerInternal { * Migrates legacy obb data to its new location. */ public abstract void migrateLegacyObbData(); + + /** + * Ensures that we block deletion of unused packages on user removal. This is purely for the + * purpose of ensuring that b/141413692 is not reproducible on Q. + */ + public abstract void notifyingOnNextUserRemovalForTest(); + + /** + * Notifies PackageManager of the removal of a user. This is purely for the purpose of ensuring + * that b/141413692 is not reproducible on Q. + */ + public abstract void userRemovedForTest(); } diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 63641e538b8e..880416abc4f3 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -104,4 +104,5 @@ interface IUserManager { String getUserName(); long getUserStartRealtime(); long getUserUnlockRealtime(); + void notifyOnNextUserRemoveForTest(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 88c29987d1df..c6cae530e795 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -271,8 +271,8 @@ import android.os.WorkSource; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.DeviceConfig; -import android.provider.Settings; import android.provider.DeviceConfig.Properties; +import android.provider.Settings; import android.server.ServerProtoEnums; import android.sysprop.VoldProperties; import android.text.TextUtils; @@ -8256,6 +8256,21 @@ public class ActivityManagerService extends IActivityManager.Stub } } + private boolean isActiveInstrumentation(int uid) { + synchronized (ActivityManagerService.this) { + for (int i = mActiveInstrumentation.size() - 1; i >= 0; i--) { + final ActiveInstrumentation instrumentation = mActiveInstrumentation.get(i); + for (int j = instrumentation.mRunningProcesses.size() - 1; j >= 0; j--) { + final ProcessRecord process = instrumentation.mRunningProcesses.get(j); + if (process.uid == uid) { + return true; + } + } + } + } + return false; + } + @Override public int getUidProcessState(int uid, String callingPackage) { if (!hasUsageStatsPermission(callingPackage)) { @@ -18507,6 +18522,11 @@ public class ActivityManagerService extends IActivityManager.Stub public void unregisterProcessObserver(IProcessObserver processObserver) { ActivityManagerService.this.unregisterProcessObserver(processObserver); } + + @Override + public boolean isActiveInstrumentation(int uid) { + return ActivityManagerService.this.isActiveInstrumentation(uid); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0a2951d147c9..47774b2a13fa 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -208,6 +208,7 @@ import android.os.AsyncTask; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.Debug; import android.os.Environment; import android.os.FileUtils; @@ -978,6 +979,8 @@ public class PackageManagerService extends IPackageManager.Stub private Future mPrepareAppDataFuture; + private final ConditionVariable mBlockDeleteOnUserRemoveForTest = new ConditionVariable(true); + private static class IFVerificationParams { PackageParser.Package pkg; boolean replacing; @@ -23652,8 +23655,13 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, " Removing package " + packageName); } //end run - mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, - userHandle, 0)); + mHandler.post(() -> { + if (!mBlockDeleteOnUserRemoveForTest.block(30000 /* 30 seconds*/)) { + mBlockDeleteOnUserRemoveForTest.open(); + } + deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST, + userHandle, 0); + }); } } } @@ -25008,6 +25016,16 @@ public class PackageManagerService extends IPackageManager.Stub Slog.wtf(TAG, e); } } + + @Override + public void notifyingOnNextUserRemovalForTest() { + mBlockDeleteOnUserRemoveForTest.close(); + } + + @Override + public void userRemovedForTest() { + mBlockDeleteOnUserRemoveForTest.open(); + } } @GuardedBy("mPackages") diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 204f186f9e13..e2ebd7336124 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import static android.Manifest.permission.INJECT_EVENTS; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -39,6 +40,7 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.res.Resources; @@ -124,6 +126,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; /** * Service for {@link UserManager}. @@ -246,6 +249,7 @@ public class UserManagerService extends IUserManager.Stub { private final File mUserListFile; private static final IBinder mUserRestriconToken = new Binder(); + private final AtomicBoolean mNotifyPackageManagerOnUserRemoval = new AtomicBoolean(false); /** * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps. @@ -3134,6 +3138,11 @@ public class UserManagerService extends IUserManager.Stub { mRemovingUserIds.delete(userHandle); } } + if (mNotifyPackageManagerOnUserRemoval.getAndSet(false)) { + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + pmInternal.userRemovedForTest(); + } } private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) { @@ -4210,4 +4219,20 @@ public class UserManagerService extends IUserManager.Stub { + " does not match the calling uid " + callingUid); } } + + @Override + public void notifyOnNextUserRemoveForTest() { + mContext.enforceCallingOrSelfPermission(INJECT_EVENTS, "notifyOnNextUserRemoveForTest"); + final ActivityManagerInternal amInternal = + LocalServices.getService(ActivityManagerInternal.class); + if (!amInternal.isActiveInstrumentation(Binder.getCallingUid())) { + return; + } + + this.mNotifyPackageManagerOnUserRemoval.set(true); + + final PackageManagerInternal pmInternal = + LocalServices.getService(PackageManagerInternal.class); + pmInternal.notifyingOnNextUserRemovalForTest(); + } } -- GitLab From c594d702685a5e2a5ef3906c7a484a24c33666bb Mon Sep 17 00:00:00 2001 From: Jim Kaye Date: Tue, 3 Dec 2019 10:14:23 -0800 Subject: [PATCH 004/143] [DO NOT MERGE] Add a configuration to allow disabling auto-suspend If a platform needs to control suspension explicitly, it can set 'config_enableAutoSuspend' to false to disable auto-suspend. Auto-suspend is enabled by default. This is only for Q. Autosuspend is done differently in R. Bug: 143203434 Test: Verified on desktop Automotive hardware Change-Id: Iac17a7d753b8cd5c0259059713fae29d6e5e6fb0 --- core/res/res/values/config.xml | 3 +++ core/res/res/values/symbols.xml | 1 + .../com/android/server/power/PowerManagerService.java | 9 +++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 4a464656a63a..54684dd3f5d3 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4268,4 +4268,7 @@ false + + true diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index aff7f611f339..09d927401548 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3854,4 +3854,5 @@ + diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index e1b3e4d6fbcf..1cb7880ff81d 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -421,6 +421,8 @@ public final class PowerManagerService extends SystemService // True if doze should not be started until after the screen off transition. private boolean mDozeAfterScreenOff; + private boolean mEnableAutoSuspendConfig; + // The minimum screen off timeout, in milliseconds. private long mMinimumScreenOffTimeoutConfig; @@ -954,6 +956,8 @@ public final class PowerManagerService extends SystemService com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay); mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean( com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay); + mEnableAutoSuspendConfig = resources.getBoolean( + com.android.internal.R.bool.config_enableAutoSuspend); mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig = resources.getBoolean( @@ -2625,7 +2629,8 @@ public final class PowerManagerService extends SystemService if (!mDecoupleHalInteractiveModeFromDisplayConfig) { setHalInteractiveModeLocked(false); } - if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) { + if (mEnableAutoSuspendConfig + && !mDecoupleHalAutoSuspendModeFromDisplayConfig) { setHalAutoSuspendModeLocked(true); } } else { @@ -2670,7 +2675,7 @@ public final class PowerManagerService extends SystemService private void updateSuspendBlockerLocked() { final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0); final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked(); - final boolean autoSuspend = !needDisplaySuspendBlocker; + final boolean autoSuspend = mEnableAutoSuspendConfig && !needDisplaySuspendBlocker; final boolean interactive = mDisplayPowerRequest.isBrightOrDim(); // Disable auto-suspend if needed. -- GitLab From ce22265eeda3a96613b9a7bb7dd898c69d295964 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Tue, 17 Dec 2019 11:21:02 -0800 Subject: [PATCH 005/143] Revoke 'always' web handler status when not autoverifying If an app has previously used autoVerify to make claims about its status re handling web navigation intents, but is updated such that it no longer makes those claims, step down its "official handler" status as though it had never invoked autoVerify in the first place. Bug: 146204120 Test: manual: as described in bug; observe policy before/after via 'adb shell dumpsys package d' Test: atest CtsOsHostTestCases Change-Id: I58502d1b32d793aba9aa772fa2ad5ac38acca48a Merged-In: I58502d1b32d793aba9aa772fa2ad5ac38acca48a --- .../server/pm/PackageManagerService.java | 44 ++++++++++++++----- .../java/com/android/server/pm/Settings.java | 1 + 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 033c62bf0fc2..5a6168596369 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17725,36 +17725,48 @@ public class PackageManagerService extends IPackageManager.Stub int count = 0; final String packageName = pkg.packageName; + boolean handlesWebUris = false; + final boolean alreadyVerified; synchronized (mPackages) { // If this is a new install and we see that we've already run verification for this // package, we have nothing to do: it means the state was restored from backup. - if (!replacing) { - IntentFilterVerificationInfo ivi = - mSettings.getIntentFilterVerificationLPr(packageName); - if (ivi != null) { - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, "Package " + packageName+ " already verified: status=" - + ivi.getStatusString()); - } - return; + final IntentFilterVerificationInfo ivi = + mSettings.getIntentFilterVerificationLPr(packageName); + alreadyVerified = (ivi != null); + if (!replacing && alreadyVerified) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Package " + packageName + " already verified: status=" + + ivi.getStatusString()); } + return; } - // If any filters need to be verified, then all need to be. + // If any filters need to be verified, then all need to be. In addition, we need to + // know whether an updating app has any web navigation intent filters, to re- + // examine handling policy even if not re-verifying. boolean needToVerify = false; for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { + if (filter.handlesWebUris(true)) { + handlesWebUris = true; + } if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Intent filter needs verification, so processing all filters"); } needToVerify = true; + // It's safe to break out here because filter.needsVerification() + // can only be true if filter.handlesWebUris(true) returns true, so + // we've already noted that. break; } } } + // Note whether this app publishes any web navigation handling support at all, + // and whether there are any web-nav filters that fit the profile for running + // a verification pass now. if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; for (PackageParser.Activity a : pkg.activities) { @@ -17772,13 +17784,23 @@ public class PackageManagerService extends IPackageManager.Stub } if (count > 0) { + // count > 0 means that we're running a full verification pass if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count + " IntentFilter verification" + (count > 1 ? "s" : "") + " for userId:" + userId); mIntentFilterVerifier.startVerifications(userId); + } else if (alreadyVerified && handlesWebUris) { + // App used autoVerify in the past, no longer does, but still handles web + // navigation starts. + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy"); + } + synchronized (mPackages) { + clearIntentFilterVerificationsLPw(packageName, userId); + } } else { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "No filters or not all autoVerify for " + packageName); + Slog.d(TAG, "No web filters or no prior verify policy for " + packageName); } } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index a7e38301bb40..6036e7d75433 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1319,6 +1319,7 @@ public final class Settings { return false; } ps.clearDomainVerificationStatusForUser(userId); + ps.setIntentFilterVerificationInfo(null); return true; } -- GitLab From a8fb6dc1671c93b8063c9888339959d9cd9728e9 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Tue, 17 Dec 2019 11:21:02 -0800 Subject: [PATCH 006/143] Revoke 'always' web handler status when not autoverifying If an app has previously used autoVerify to make claims about its status re handling web navigation intents, but is updated such that it no longer makes those claims, step down its "official handler" status as though it had never invoked autoVerify in the first place. Bug: 146204120 Test: manual: as described in bug; observe policy before/after via 'adb shell dumpsys package d' Test: atest CtsOsHostTestCases Change-Id: I58502d1b32d793aba9aa772fa2ad5ac38acca48a Merged-In: I58502d1b32d793aba9aa772fa2ad5ac38acca48a --- .../server/pm/PackageManagerService.java | 44 ++++++++++++++----- .../java/com/android/server/pm/Settings.java | 1 + 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0a2951d147c9..028c2ed11378 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18078,36 +18078,48 @@ public class PackageManagerService extends IPackageManager.Stub int count = 0; final String packageName = pkg.packageName; + boolean handlesWebUris = false; + final boolean alreadyVerified; synchronized (mPackages) { // If this is a new install and we see that we've already run verification for this // package, we have nothing to do: it means the state was restored from backup. - if (!replacing) { - IntentFilterVerificationInfo ivi = - mSettings.getIntentFilterVerificationLPr(packageName); - if (ivi != null) { - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, "Package " + packageName+ " already verified: status=" - + ivi.getStatusString()); - } - return; + final IntentFilterVerificationInfo ivi = + mSettings.getIntentFilterVerificationLPr(packageName); + alreadyVerified = (ivi != null); + if (!replacing && alreadyVerified) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Package " + packageName + " already verified: status=" + + ivi.getStatusString()); } + return; } - // If any filters need to be verified, then all need to be. + // If any filters need to be verified, then all need to be. In addition, we need to + // know whether an updating app has any web navigation intent filters, to re- + // examine handling policy even if not re-verifying. boolean needToVerify = false; for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { + if (filter.handlesWebUris(true)) { + handlesWebUris = true; + } if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Intent filter needs verification, so processing all filters"); } needToVerify = true; + // It's safe to break out here because filter.needsVerification() + // can only be true if filter.handlesWebUris(true) returns true, so + // we've already noted that. break; } } } + // Note whether this app publishes any web navigation handling support at all, + // and whether there are any web-nav filters that fit the profile for running + // a verification pass now. if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; for (PackageParser.Activity a : pkg.activities) { @@ -18125,13 +18137,23 @@ public class PackageManagerService extends IPackageManager.Stub } if (count > 0) { + // count > 0 means that we're running a full verification pass if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count + " IntentFilter verification" + (count > 1 ? "s" : "") + " for userId:" + userId); mIntentFilterVerifier.startVerifications(userId); + } else if (alreadyVerified && handlesWebUris) { + // App used autoVerify in the past, no longer does, but still handles web + // navigation starts. + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy"); + } + synchronized (mPackages) { + clearIntentFilterVerificationsLPw(packageName, userId); + } } else { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "No filters or not all autoVerify for " + packageName); + Slog.d(TAG, "No web filters or no prior verify policy for " + packageName); } } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 11a8f4b895f5..46485b5550a6 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1252,6 +1252,7 @@ public final class Settings { return false; } ps.clearDomainVerificationStatusForUser(userId); + ps.setIntentFilterVerificationInfo(null); return true; } -- GitLab From 6cf5f92825df545bd011b7163418f2ea0b337af3 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Tue, 17 Dec 2019 11:21:02 -0800 Subject: [PATCH 007/143] Revoke 'always' web handler status when not autoverifying If an app has previously used autoVerify to make claims about its status re handling web navigation intents, but is updated such that it no longer makes those claims, step down its "official handler" status as though it had never invoked autoVerify in the first place. Bug: 146204120 Test: manual: as described in bug; observe policy before/after via 'adb shell dumpsys package d' Test: atest CtsOsHostTestCases Change-Id: I58502d1b32d793aba9aa772fa2ad5ac38acca48a Merged-In: I58502d1b32d793aba9aa772fa2ad5ac38acca48a --- .../server/pm/PackageManagerService.java | 44 ++++++++++++++----- .../java/com/android/server/pm/Settings.java | 1 + 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ab6c956c6924..efc7fabc0a85 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18437,35 +18437,47 @@ public class PackageManagerService extends IPackageManager.Stub int count = 0; final String packageName = pkg.packageName; + boolean handlesWebUris = false; + final boolean alreadyVerified; synchronized (mPackages) { // If this is a new install and we see that we've already run verification for this // package, we have nothing to do: it means the state was restored from backup. - if (!replacing) { - IntentFilterVerificationInfo ivi = - mSettings.getIntentFilterVerificationLPr(packageName); - if (ivi != null) { - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, "Package " + packageName+ " already verified: status=" - + ivi.getStatusString()); - } - return; + final IntentFilterVerificationInfo ivi = + mSettings.getIntentFilterVerificationLPr(packageName); + alreadyVerified = (ivi != null); + if (!replacing && alreadyVerified) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Package " + packageName + " already verified: status=" + + ivi.getStatusString()); } + return; } - // If any filters need to be verified, then all need to be. + // If any filters need to be verified, then all need to be. In addition, we need to + // know whether an updating app has any web navigation intent filters, to re- + // examine handling policy even if not re-verifying. boolean needToVerify = false; for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { + if (filter.handlesWebUris(true)) { + handlesWebUris = true; + } if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Intent filter needs verification, so processing all filters"); } needToVerify = true; + // It's safe to break out here because filter.needsVerification() + // can only be true if filter.handlesWebUris(true) returns true, so + // we've already noted that. break; } } } + // Note whether this app publishes any web navigation handling support at all, + // and whether there are any web-nav filters that fit the profile for running + // a verification pass now. if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; for (PackageParser.Activity a : pkg.activities) { @@ -18483,13 +18495,23 @@ public class PackageManagerService extends IPackageManager.Stub } if (count > 0) { + // count > 0 means that we're running a full verification pass if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count + " IntentFilter verification" + (count > 1 ? "s" : "") + " for userId:" + userId); mIntentFilterVerifier.startVerifications(userId); + } else if (alreadyVerified && handlesWebUris) { + // App used autoVerify in the past, no longer does, but still handles web + // navigation starts. + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy"); + } + synchronized (mPackages) { + clearIntentFilterVerificationsLPw(packageName, userId); + } } else { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "No filters or not all autoVerify for " + packageName); + Slog.d(TAG, "No web filters or no prior verify policy for " + packageName); } } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 45d0c585627b..5ab97a4e9f35 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1377,6 +1377,7 @@ final class Settings { return false; } ps.clearDomainVerificationStatusForUser(userId); + ps.setIntentFilterVerificationInfo(null); return true; } -- GitLab From 9dfd9a5f3333a5d1f176bde97d1fa61cdae1956f Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Mon, 25 Nov 2019 22:44:12 +0800 Subject: [PATCH 008/143] Supplementary Services(SS) gray out when airplane mode on in Call Settings menu. add carrier config "KEY_SS_DISABLE_WHEN_AIRPLANE_MODE_BOOL". Bug: 141284019 Test: when airplane mode on, all of SS UIs are gray out. Change-Id: I869a267fa5aaebf3b48f20bc70d21d612cd84586 (cherry picked from commit 08972c5b2b8bcb748e5a9b856e589b3d43e1fc69) Merged-In: I869a267fa5aaebf3b48f20bc70d21d612cd84586 --- .../java/android/telephony/CarrierConfigManager.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index b646a93e43f1..1994ccc74b74 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -99,6 +99,17 @@ public class CarrierConfigManager { public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; + /** + * Boolean indicating the Supplementary Services(SS) is disable when airplane mode on in the + * Call Settings menu. + * {@code true}: SS is disable when airplane mode on. + * {@code false}: SS is enable when airplane mode on. + * The default value for this key is {@code false} + * @hide + */ + public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = + "disable_supplementary_services_in_airplane_mode_bool"; + /** * Boolean indicating if the "Call forwarding" item is visible in the Call Settings menu. * true means visible. false means gone. @@ -3255,6 +3266,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true); sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALLER_ID_VISIBILITY_BOOL, true); sDefaults.putBoolean(KEY_ADDITIONAL_SETTINGS_CALL_WAITING_VISIBILITY_BOOL, true); + sDefaults.putBoolean(KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL, false); sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false); sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false); sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true); -- GitLab From ef5220e5b2a4b90d4260eb058475fdcdf30d861d Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Tue, 17 Dec 2019 11:21:02 -0800 Subject: [PATCH 009/143] Revoke 'always' web handler status when not autoverifying If an app has previously used autoVerify to make claims about its status re handling web navigation intents, but is updated such that it no longer makes those claims, step down its "official handler" status as though it had never invoked autoVerify in the first place. Bug: 146204120 Test: manual: as described in bug; observe policy before/after via 'adb shell dumpsys package d' Test: atest CtsOsHostTestCases Change-Id: I58502d1b32d793aba9aa772fa2ad5ac38acca48a Merged-In: I58502d1b32d793aba9aa772fa2ad5ac38acca48a --- .../server/pm/PackageManagerService.java | 44 ++++++++++++++----- .../java/com/android/server/pm/Settings.java | 1 + 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bf1da5625857..599753b024ce 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -19061,35 +19061,47 @@ public class PackageManagerService extends IPackageManager.Stub int count = 0; final String packageName = pkg.packageName; + boolean handlesWebUris = false; + final boolean alreadyVerified; synchronized (mPackages) { // If this is a new install and we see that we've already run verification for this // package, we have nothing to do: it means the state was restored from backup. - if (!replacing) { - IntentFilterVerificationInfo ivi = - mSettings.getIntentFilterVerificationLPr(packageName); - if (ivi != null) { - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, "Package " + packageName+ " already verified: status=" - + ivi.getStatusString()); - } - return; + final IntentFilterVerificationInfo ivi = + mSettings.getIntentFilterVerificationLPr(packageName); + alreadyVerified = (ivi != null); + if (!replacing && alreadyVerified) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Package " + packageName + " already verified: status=" + + ivi.getStatusString()); } + return; } - // If any filters need to be verified, then all need to be. + // If any filters need to be verified, then all need to be. In addition, we need to + // know whether an updating app has any web navigation intent filters, to re- + // examine handling policy even if not re-verifying. boolean needToVerify = false; for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { + if (filter.handlesWebUris(true)) { + handlesWebUris = true; + } if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Intent filter needs verification, so processing all filters"); } needToVerify = true; + // It's safe to break out here because filter.needsVerification() + // can only be true if filter.handlesWebUris(true) returns true, so + // we've already noted that. break; } } } + // Note whether this app publishes any web navigation handling support at all, + // and whether there are any web-nav filters that fit the profile for running + // a verification pass now. if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; for (PackageParser.Activity a : pkg.activities) { @@ -19107,13 +19119,23 @@ public class PackageManagerService extends IPackageManager.Stub } if (count > 0) { + // count > 0 means that we're running a full verification pass if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count + " IntentFilter verification" + (count > 1 ? "s" : "") + " for userId:" + userId); mIntentFilterVerifier.startVerifications(userId); + } else if (alreadyVerified && handlesWebUris) { + // App used autoVerify in the past, no longer does, but still handles web + // navigation starts. + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy"); + } + synchronized (mPackages) { + clearIntentFilterVerificationsLPw(packageName, userId); + } } else { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "No filters or not all autoVerify for " + packageName); + Slog.d(TAG, "No web filters or no prior verify policy for " + packageName); } } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 56835f69a3c7..0e1f3c295784 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1380,6 +1380,7 @@ final class Settings { return false; } ps.clearDomainVerificationStatusForUser(userId); + ps.setIntentFilterVerificationInfo(null); return true; } -- GitLab From d2a71cc4b8f11688f85f33507b75d00041c14852 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Tue, 17 Dec 2019 11:21:02 -0800 Subject: [PATCH 010/143] Revoke 'always' web handler status when not autoverifying If an app has previously used autoVerify to make claims about its status re handling web navigation intents, but is updated such that it no longer makes those claims, step down its "official handler" status as though it had never invoked autoVerify in the first place. Bug: 146204120 Test: manual: as described in bug; observe policy before/after via 'adb shell dumpsys package d' Test: atest CtsOsHostTestCases Change-Id: I58502d1b32d793aba9aa772fa2ad5ac38acca48a Merged-In: I58502d1b32d793aba9aa772fa2ad5ac38acca48a --- .../server/pm/PackageManagerService.java | 44 ++++++++++++++----- .../java/com/android/server/pm/Settings.java | 1 + 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 04cebb309216..9afaae11b39a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18094,36 +18094,48 @@ public class PackageManagerService extends IPackageManager.Stub int count = 0; final String packageName = pkg.packageName; + boolean handlesWebUris = false; + final boolean alreadyVerified; synchronized (mPackages) { // If this is a new install and we see that we've already run verification for this // package, we have nothing to do: it means the state was restored from backup. - if (!replacing) { - IntentFilterVerificationInfo ivi = - mSettings.getIntentFilterVerificationLPr(packageName); - if (ivi != null) { - if (DEBUG_DOMAIN_VERIFICATION) { - Slog.i(TAG, "Package " + packageName+ " already verified: status=" - + ivi.getStatusString()); - } - return; + final IntentFilterVerificationInfo ivi = + mSettings.getIntentFilterVerificationLPr(packageName); + alreadyVerified = (ivi != null); + if (!replacing && alreadyVerified) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, "Package " + packageName + " already verified: status=" + + ivi.getStatusString()); } + return; } - // If any filters need to be verified, then all need to be. + // If any filters need to be verified, then all need to be. In addition, we need to + // know whether an updating app has any web navigation intent filters, to re- + // examine handling policy even if not re-verifying. boolean needToVerify = false; for (PackageParser.Activity a : pkg.activities) { for (ActivityIntentInfo filter : a.intents) { + if (filter.handlesWebUris(true)) { + handlesWebUris = true; + } if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Intent filter needs verification, so processing all filters"); } needToVerify = true; + // It's safe to break out here because filter.needsVerification() + // can only be true if filter.handlesWebUris(true) returns true, so + // we've already noted that. break; } } } + // Note whether this app publishes any web navigation handling support at all, + // and whether there are any web-nav filters that fit the profile for running + // a verification pass now. if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; for (PackageParser.Activity a : pkg.activities) { @@ -18141,13 +18153,23 @@ public class PackageManagerService extends IPackageManager.Stub } if (count > 0) { + // count > 0 means that we're running a full verification pass if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Starting " + count + " IntentFilter verification" + (count > 1 ? "s" : "") + " for userId:" + userId); mIntentFilterVerifier.startVerifications(userId); + } else if (alreadyVerified && handlesWebUris) { + // App used autoVerify in the past, no longer does, but still handles web + // navigation starts. + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.d(TAG, "App changed web filters but no longer verifying - resetting policy"); + } + synchronized (mPackages) { + clearIntentFilterVerificationsLPw(packageName, userId); + } } else { if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "No filters or not all autoVerify for " + packageName); + Slog.d(TAG, "No web filters or no prior verify policy for " + packageName); } } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index d9e4db29de07..169f8cb91e80 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1252,6 +1252,7 @@ public final class Settings { return false; } ps.clearDomainVerificationStatusForUser(userId); + ps.setIntentFilterVerificationInfo(null); return true; } -- GitLab From 611bad95564695d6b5fa87efa89c9a4e1979dc80 Mon Sep 17 00:00:00 2001 From: Christophe Koessler Date: Tue, 17 Dec 2019 16:40:47 -0800 Subject: [PATCH 011/143] Refactor CountryDetectorService Clean-up the test to use Mockito instead of the deprecated AndroidTestCase, also getting rid of 1.5s of Thread.sleep. No logic change. Bug: 141626568 Test: atest CountryDetectorServiceTest Merged-in: Ic0782b1ffcd1dcb30b9f1d91b37521d1f9887f03 Change-Id: Ic0782b1ffcd1dcb30b9f1d91b37521d1f9887f03 (cherry picked from commit 50361687ba6bc20877af43eb5367a5ba3a2911df) --- .../server/CountryDetectorService.java | 76 +++++----- services/tests/servicestests/Android.bp | 1 + .../server/CountryDetectorServiceTest.java | 143 ++++++++++++------ 3 files changed, 129 insertions(+), 91 deletions(-) diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java index d8a2fe35c7e8..861c731c69e0 100644 --- a/services/core/java/com/android/server/CountryDetectorService.java +++ b/services/core/java/com/android/server/CountryDetectorService.java @@ -16,14 +16,6 @@ package com.android.server; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.HashMap; - -import com.android.internal.os.BackgroundThread; -import com.android.internal.util.DumpUtils; -import com.android.server.location.ComprehensiveCountryDetector; - import android.content.Context; import android.location.Country; import android.location.CountryListener; @@ -36,17 +28,25 @@ import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.DumpUtils; +import com.android.server.location.ComprehensiveCountryDetector; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashMap; + /** - * This class detects the country that the user is in through - * {@link ComprehensiveCountryDetector}. + * This class detects the country that the user is in through {@link ComprehensiveCountryDetector}. * * @hide */ -public class CountryDetectorService extends ICountryDetector.Stub implements Runnable { +public class CountryDetectorService extends ICountryDetector.Stub { /** - * The class represents the remote listener, it will also removes itself - * from listener list when the remote process was died. + * The class represents the remote listener, it will also removes itself from listener list when + * the remote process was died. */ private final class Receiver implements IBinder.DeathRecipient { private final ICountryListener mListener; @@ -79,9 +79,11 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run } } - private final static String TAG = "CountryDetector"; + private static final String TAG = "CountryDetector"; - /** Whether to dump the state of the country detector service to bugreports */ + /** + * Whether to dump the state of the country detector service to bugreports + */ private static final boolean DEBUG = false; private final HashMap mReceivers; @@ -92,15 +94,21 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run private CountryListener mLocationBasedDetectorListener; public CountryDetectorService(Context context) { + this(context, BackgroundThread.getHandler()); + } + + @VisibleForTesting + CountryDetectorService(Context context, Handler handler) { super(); - mReceivers = new HashMap(); + mReceivers = new HashMap<>(); mContext = context; + mHandler = handler; } @Override public Country detectCountry() { if (!mSystemReady) { - return null; // server not yet active + return null; // server not yet active } else { return mCountryDetector.detectCountry(); } @@ -154,9 +162,8 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run } } - protected void notifyReceivers(Country country) { - synchronized(mReceivers) { + synchronized (mReceivers) { for (Receiver receiver : mReceivers.values()) { try { receiver.getListener().onCountryDetected(country); @@ -170,38 +177,23 @@ public class CountryDetectorService extends ICountryDetector.Stub implements Run void systemRunning() { // Shall we wait for the initialization finish. - BackgroundThread.getHandler().post(this); + mHandler.post( + () -> { + initialize(); + mSystemReady = true; + }); } private void initialize() { mCountryDetector = new ComprehensiveCountryDetector(mContext); - mLocationBasedDetectorListener = new CountryListener() { - public void onCountryDetected(final Country country) { - mHandler.post(new Runnable() { - public void run() { - notifyReceivers(country); - } - }); - } - }; - } - - public void run() { - mHandler = new Handler(); - initialize(); - mSystemReady = true; + mLocationBasedDetectorListener = country -> mHandler.post(() -> notifyReceivers(country)); } protected void setCountryListener(final CountryListener listener) { - mHandler.post(new Runnable() { - @Override - public void run() { - mCountryDetector.setCountryListener(listener); - } - }); + mHandler.post(() -> mCountryDetector.setCountryListener(listener)); } - // For testing + @VisibleForTesting boolean isSystemReady() { return mSystemReady; } diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 3edbd7ee6eed..d42042d3641d 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -28,6 +28,7 @@ android_test { "services.net", "services.usage", "guava", + "androidx.test.core", "androidx.test.runner", "androidx.test.rules", "mockito-target-minus-junit4", diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java index 192c50c7dc19..e9c5ce7127de 100644 --- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,28 +11,48 @@ * 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 + * limitations under the License. */ package com.android.server; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doAnswer; + import android.content.Context; import android.location.Country; import android.location.CountryListener; import android.location.ICountryListener; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.RemoteException; -import android.test.AndroidTestCase; -public class CountryDetectorServiceTest extends AndroidTestCase { - private class CountryListenerTester extends ICountryListener.Stub { +import androidx.test.core.app.ApplicationProvider; + +import com.google.common.truth.Expect; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class CountryDetectorServiceTest { + + private static class CountryListenerTester extends ICountryListener.Stub { private Country mCountry; @Override - public void onCountryDetected(Country country) throws RemoteException { + public void onCountryDetected(Country country) { mCountry = country; } - public Country getCountry() { + Country getCountry() { return mCountry; } @@ -41,12 +61,11 @@ public class CountryDetectorServiceTest extends AndroidTestCase { } } - private class CountryDetectorServiceTester extends CountryDetectorService { - + private static class CountryDetectorServiceTester extends CountryDetectorService { private CountryListener mListener; - public CountryDetectorServiceTester(Context context) { - super(context); + CountryDetectorServiceTester(Context context, Handler handler) { + super(context, handler); } @Override @@ -59,51 +78,77 @@ public class CountryDetectorServiceTest extends AndroidTestCase { mListener = listener; } - public boolean isListenerSet() { + boolean isListenerSet() { return mListener != null; } } - public void testAddRemoveListener() throws RemoteException { - CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext()); - serviceTester.systemRunning(); - waitForSystemReady(serviceTester); - CountryListenerTester listenerTester = new CountryListenerTester(); - serviceTester.addCountryListener(listenerTester); - assertTrue(serviceTester.isListenerSet()); - serviceTester.removeCountryListener(listenerTester); - assertFalse(serviceTester.isListenerSet()); + @Rule + public final Expect expect = Expect.create(); + @Spy + private Context mContext = ApplicationProvider.getApplicationContext(); + @Spy + private Handler mHandler = new Handler(Looper.myLooper()); + private CountryDetectorServiceTester mCountryDetectorService; + + @BeforeClass + public static void oneTimeInitialization() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } } - public void testNotifyListeners() throws RemoteException { - CountryDetectorServiceTester serviceTester = new CountryDetectorServiceTester(getContext()); - CountryListenerTester listenerTesterA = new CountryListenerTester(); - CountryListenerTester listenerTesterB = new CountryListenerTester(); - Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK); - serviceTester.systemRunning(); - waitForSystemReady(serviceTester); - serviceTester.addCountryListener(listenerTesterA); - serviceTester.addCountryListener(listenerTesterB); - serviceTester.notifyReceivers(country); - assertTrue(serviceTester.isListenerSet()); - assertTrue(listenerTesterA.isNotified()); - assertTrue(listenerTesterB.isNotified()); - serviceTester.removeCountryListener(listenerTesterA); - serviceTester.removeCountryListener(listenerTesterB); - assertFalse(serviceTester.isListenerSet()); + @Before + public void setUp() { + mCountryDetectorService = new CountryDetectorServiceTester(mContext, mHandler); + + // Immediately invoke run on the Runnable posted to the handler + doAnswer(invocation -> { + Message message = invocation.getArgument(0); + message.getCallback().run(); + return true; + }).when(mHandler).sendMessageAtTime(any(Message.class), anyLong()); } - private void waitForSystemReady(CountryDetectorService service) { - int count = 5; - while (count-- > 0) { - try { - Thread.sleep(500); - } catch (Exception e) { - } - if (service.isSystemReady()) { - return; - } - } - throw new RuntimeException("Wait System Ready timeout"); + @Test + public void countryListener_add_successful() throws RemoteException { + CountryListenerTester countryListener = new CountryListenerTester(); + + mCountryDetectorService.systemRunning(); + expect.that(mCountryDetectorService.isListenerSet()).isFalse(); + mCountryDetectorService.addCountryListener(countryListener); + + expect.that(mCountryDetectorService.isListenerSet()).isTrue(); + } + + @Test + public void countryListener_remove_successful() throws RemoteException { + CountryListenerTester countryListener = new CountryListenerTester(); + + mCountryDetectorService.systemRunning(); + mCountryDetectorService.addCountryListener(countryListener); + expect.that(mCountryDetectorService.isListenerSet()).isTrue(); + mCountryDetectorService.removeCountryListener(countryListener); + + expect.that(mCountryDetectorService.isListenerSet()).isFalse(); + } + + @Test + public void countryListener_notify_successful() throws RemoteException { + CountryListenerTester countryListenerA = new CountryListenerTester(); + CountryListenerTester countryListenerB = new CountryListenerTester(); + Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK); + + mCountryDetectorService.systemRunning(); + mCountryDetectorService.addCountryListener(countryListenerA); + mCountryDetectorService.addCountryListener(countryListenerB); + expect.that(countryListenerA.isNotified()).isFalse(); + expect.that(countryListenerB.isNotified()).isFalse(); + mCountryDetectorService.notifyReceivers(country); + + expect.that(countryListenerA.isNotified()).isTrue(); + expect.that(countryListenerB.isNotified()).isTrue(); + expect.that(countryListenerA.getCountry().equalsIgnoreSource(country)).isTrue(); + expect.that(countryListenerB.getCountry().equalsIgnoreSource(country)).isTrue(); } } -- GitLab From 3dd716a1303dae79405e2f59e6121bb907f10de0 Mon Sep 17 00:00:00 2001 From: Mohammad Samiul Islam Date: Mon, 16 Sep 2019 11:09:38 +0100 Subject: [PATCH 012/143] Fix ModuleInfoProviderTest by passing correct flag Bug: 140941633 Bug: 147476459 Test: atest ModuleInfoProviderTest Change-Id: Icf93ca7dcf4fc2d7625fe7f9175c59200ae600b6 Merged-In: Icf93ca7dcf4fc2d7625fe7f9175c59200ae600b6 --- .../com/android/server/pm/ModuleInfoProviderTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java index bd3d9ab2220d..3852b9fec001 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.content.Context; import android.content.pm.ModuleInfo; +import android.content.pm.PackageManager; import android.test.InstrumentationTestCase; import com.android.frameworks.servicestests.R; @@ -28,7 +29,7 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { public void testSuccessfulParse() { ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata); - List mi = provider.getInstalledModules(0); + List mi = provider.getInstalledModules(PackageManager.MATCH_ALL); assertEquals(2, mi.size()); Collections.sort(mi, (ModuleInfo m1, ModuleInfo m2) -> @@ -49,18 +50,18 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { public void testParseFailure_incorrectTopLevelElement() { ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata1); - assertEquals(0, provider.getInstalledModules(0).size()); + assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size()); } public void testParseFailure_incorrectModuleElement() { ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata2); - assertEquals(0, provider.getInstalledModules(0).size()); + assertEquals(0, provider.getInstalledModules(PackageManager.MATCH_ALL).size()); } public void testParse_unknownAttributesIgnored() { ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata); - List mi = provider.getInstalledModules(0); + List mi = provider.getInstalledModules(PackageManager.MATCH_ALL); assertEquals(2, mi.size()); ModuleInfo mi1 = provider.getModuleInfo("com.android.module1", 0); -- GitLab From 17b30481453806548160538dd635b00dbe5eff5b Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sun, 12 Jan 2020 11:33:33 -0800 Subject: [PATCH 013/143] Import translations. DO NOT MERGE Change-Id: I090f0dab1bf477e98afb7146f5fcd4971976b847 Auto-generated-cl: translation import --- packages/PackageInstaller/res/values-ky/strings.xml | 10 +++++----- packages/PackageInstaller/res/values-pl/strings.xml | 2 +- packages/PackageInstaller/res/values-sl/strings.xml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/PackageInstaller/res/values-ky/strings.xml b/packages/PackageInstaller/res/values-ky/strings.xml index ae47ab14b0cb..8f3f049fcdc3 100644 --- a/packages/PackageInstaller/res/values-ky/strings.xml +++ b/packages/PackageInstaller/res/values-ky/strings.xml @@ -24,8 +24,8 @@ "%1$s орнотулууда…" "Колдонмо орнотулду." "Бул колдонмону орнотоюн деп жатасызбы?" - "Учурдагы колдонмону жаңыртканы жатасызбы? Буга чейин сакталган дайындарыңыз өчүрүлбөйт." - "Учурдагы алдын ала орнотулган колдонмону жаңыртканы жатасызбы? Буга чейин сакталган дайындарыңыз өчүрүлбөйт." + "Учурдагы колдонмону жаңыртканы жатасызбы? Буга чейин сакталган дайын-даректериңиз өчүрүлбөйт." + "Учурдагы алдын ала орнотулган колдонмону жаңыртканы жатасызбы? Буга чейин сакталган дайын-даректериңиз өчүрүлбөйт." "Колдонмо орнотулган жок." "Топтомду орнотууга болбойт." "Башка топтом менен дал келбегендиктен колдонмо орнотулган жок." @@ -83,9 +83,9 @@ "Коопсуздукту сактоо максатында, планшетиңизге бул булактан колдонмолорду орнотууга уруксат жок." "Коопсуздукту сактоо максатында, сыналгыңызга бул булактан колдонмолорду орнотууга уруксат жок." "Коопсуздукту сактоо максатында, телефонуңузга бул булактан колдонмолорду орнотууга уруксат жок." - "Телефонуңуз жана жеке дайындарыңыз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам телефонуңузга кандайдыр бир зыян келтирилсе же дайындарыңызды жоготуп алсаңыз, өзүңүз жооптуу болосуз." - "Планшетиңиз жана жеке дайындарыңыз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам планшетиңизге кандайдыр бир зыян келтирилсе же дайындарыңызды жоготуп алсаңыз, өзүңүз жооптуу болосуз." - "Сыналгыңыз жана жеке дайындарыңыз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам сыналгыңызга кандайдыр бир зыян келтирилсе же дайындарыңызды жоготуп алсаңыз, өзүңүз жооптуу болосуз." + "Телефонуңуз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам телефонуңузга кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз." + "Планшетиңиз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам планшетиңизге кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз." + "Сыналгыңыз жана жеке дайын-даректериңиз белгисиз колдонмолордон зыян тартып калышы мүмкүн. Бул колдонмону орнотуп, аны пайдалануудан улам сыналгыңызга кандайдыр бир зыян келтирилсе же дайын-даректериңизды жоготуп алсаңыз, өзүңүз жооптуу болосуз." "Улантуу" "Жөндөөлөр" "Тагынма колдонмолорду орнотуу/чыгаруу" diff --git a/packages/PackageInstaller/res/values-pl/strings.xml b/packages/PackageInstaller/res/values-pl/strings.xml index b08dc559358e..d2426c6c7fa8 100644 --- a/packages/PackageInstaller/res/values-pl/strings.xml +++ b/packages/PackageInstaller/res/values-pl/strings.xml @@ -62,7 +62,7 @@ "Aktywne odinstalowania" "Nieudane odinstalowania" "Odinstalowuję…" - "Odinstalowuję pakiet %1$s…" + "Odinstalowuję %1$s…" "Odinstalowywanie zakończone." "Odinstalowano pakiet %1$s" "Nie udało się odinstalować." diff --git a/packages/PackageInstaller/res/values-sl/strings.xml b/packages/PackageInstaller/res/values-sl/strings.xml index d535dc048cc3..354ce9938bae 100644 --- a/packages/PackageInstaller/res/values-sl/strings.xml +++ b/packages/PackageInstaller/res/values-sl/strings.xml @@ -53,7 +53,7 @@ "Odstrani aplikacijo" "Odstrani posodobitev" "%1$s je del te aplikacije:" - "Ali želite odstraniti to aplikacijo?" + "Ali želite odmestiti to aplikacijo?" "Ali želite odstraniti aplikacijo za ""vse"" uporabnike? Aplikacija in njeni podatki bodo odstranjeni iz ""vseh"" uporabnikov v napravi." "Ali želite to aplikacijo odstraniti za uporabnika %1$s?" "Želite to aplikacijo nadomestiti s tovarniško različico? Odstranjeni bodo vsi podatki." @@ -62,11 +62,11 @@ "Odstranitve v teku" "Neuspele odstranitve" "Odstranjevanje …" - "Odstranjevanje aplikacije %1$s …" + "Odmeščanje aplikacije %1$s …" "Odstranitev je končana." "Aplikacija %1$s je bila odstranjena" "Odstranitev ni uspela." - "Odstranjevanje aplikacije %1$s ni uspelo." + "Odmeščanje aplikacije %1$s ni uspelo." "Aktivne skrbniške aplikacije naprave ni mogoče odstraniti" "Aktivne skrbniške aplikacije za uporabnika %1$s ni mogoče odstraniti" "Aplikacija je obvezna za nekatere uporabnike/profile in je odstranjena za druge." -- GitLab From 27d20fbd19a4df574c1b4ecc0fc777d3e4d87c33 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sun, 12 Jan 2020 11:49:34 -0800 Subject: [PATCH 014/143] Import translations. DO NOT MERGE Change-Id: I193e7ea38b7b5257ac090d593f692dc80795b9ae Auto-generated-cl: translation import --- packages/PrintSpooler/res/values-eu/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/PrintSpooler/res/values-eu/strings.xml b/packages/PrintSpooler/res/values-eu/strings.xml index 459b4d3093ab..7ccccc9ff261 100644 --- a/packages/PrintSpooler/res/values-eu/strings.xml +++ b/packages/PrintSpooler/res/values-eu/strings.xml @@ -32,7 +32,7 @@ "%1$s orriko tartea" "adib., 1-5, 8,11-13" "Inprimatze-aurrebista" - "Aurrebista ikusteko, instalatu PDF ikustailea" + "Aurrebista ikusteko, instalatu PDF dokumentuen ikustailea" "Inprimatzeko aplikazioak matxura izan du" "Inprimatze-lana sortzen" "Gorde PDF gisa" -- GitLab From 4452bafb9352aa89dbae33789fa6566d88cab0b3 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sun, 12 Jan 2020 16:29:37 -0800 Subject: [PATCH 015/143] Import translations. DO NOT MERGE Change-Id: I77ed89b08ff7a8d1fabdbf3071da3b754ce7d06e Auto-generated-cl: translation import --- .../res-keyguard/values-ar/strings.xml | 66 +++++++++---------- packages/SystemUI/res/values-ar/strings.xml | 8 +-- packages/SystemUI/res/values-bn/strings.xml | 2 +- .../SystemUI/res/values-en-rAU/strings.xml | 2 +- .../SystemUI/res/values-en-rCA/strings.xml | 2 +- .../SystemUI/res/values-en-rGB/strings.xml | 2 +- .../SystemUI/res/values-en-rIN/strings.xml | 2 +- packages/SystemUI/res/values-es/strings.xml | 4 +- packages/SystemUI/res/values-eu/strings.xml | 6 +- packages/SystemUI/res/values-fr/strings.xml | 2 +- packages/SystemUI/res/values-hi/strings.xml | 2 +- .../SystemUI/res/values-pt-rPT/strings.xml | 6 +- 12 files changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index 98f6de739315..414317ff7b52 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -50,7 +50,7 @@ "‏تم إيقاف شريحة SIM بشكل دائم.\n اتصل بمقدم خدمة اللاسلكي للحصول على شريحة SIM أخرى." "‏شريحة SIM مؤمّنة." "‏شريحة SIM مؤمّنة برمز PUK." - "‏جارٍ إلغاء تأمين شريحة SIM…" + "‏جارٍ فتح قفل شريحة SIM…" "منطقة رقم التعريف الشخصي" "كلمة مرور الجهاز" "‏منطقة رقم التعريف الشخصي لشريحة SIM" @@ -76,14 +76,14 @@ "ارسم نقشك" "‏أدخل رقم التعريف الشخصي لشريحة SIM." "‏أدخل رقم التعريف الشخصي لشريحة SIM التابعة للمشغّل \"%1$s\"." - "‏%1$s يجب إيقاف eSIM لاستخدام الجهاز دون خدمة جوّال." + "‏%1$s يجب إيقاف eSIM لاستخدام الجهاز بدون خدمة الأجهزة الجوّالة." "أدخل رقم التعريف الشخصي" "أدخل كلمة المرور" "‏شريحة SIM غير مفعّلة الآن. أدخل رمز PUK للمتابعة. اتصل بمشغل شبكة الجوّال للاطلاع على التفاصيل." "‏SIM \"%1$s\" غير مفعّلة الآن. أدخل رمز PUK للمتابعة. واتصل بمشغل شبكة الجوّال لمعرفة التفاصيل." "أدخل رمز رقم التعريف الشخصي المطلوب" "تأكيد رمز رقم التعريف الشخصي المطلوب" - "‏جارٍ إلغاء تأمين شريحة SIM…" + "‏جارٍ فتح قفل شريحة SIM…" "اكتب رمز رقم التعريف الشخصي المكوّن من ٤ إلى ٨ أرقام." "‏يجب أن يتضمن رمز PUK‏ ۸ أرقام أو أكثر." "‏أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى إيقاف شريحة SIM نهائيًا." @@ -92,18 +92,18 @@ "لقد كتبت رقم التعريف الشخصي بشكل غير صحيح %1$d مرة. \n\nأعد المحاولة خلال %2$d ثانية." "لقد كتبت كلمة المرور بشكل غير صحيح %1$d مرة. \n\nأعد المحاولة خلال %2$d ثانية." "لقد رسمت نقش فتح القفل بطريقة غير صحيحة %1$d مرة. \n\nأعد المحاولة خلال %2$d ثانية." - "أخطأت في محاولة إلغاء قفل الجهاز اللوحي %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته." - "أخطأت في محاولة إلغاء قفل الهاتف %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته." - "أخطأت في محاولة إلغاء قفل الجهاز اللوحي %d مرة. ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته." - "أخطأت في محاولة إلغاء قفل الهاتف %d مرة. ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته." - "أخطأت في محاولة إلغاء قفل الجهاز اللوحي %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم." - "أخطأت في محاولة إلغاء قفل الهاتف %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم." - "أخطأت في محاولة إلغاء قفل الجهاز اللوحي %d مرة. ستتم إزالة المستخدم، ومن ثم يتم حذف جميع بياناته." - "أخطأت في محاولة إلغاء قفل الهاتف %d مرة. ستتم إزالة المستخدم، ومن ثم يتم حذف جميع بياناته." - "أخطأت في محاولة إلغاء قفل الجهاز اللوحي %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بيانات الملف الشخصي." - "أخطأت في محاولة إلغاء قفل الهاتف %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بيانات الملف الشخصي." - "أخطأت في محاولة إلغاء قفل الجهاز اللوحي %d مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته." - "أخطأت في محاولة إلغاء قفل الهاتف %d مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الجهاز اللوحي %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الهاتف %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الجهاز اللوحي %d مرة. ستتم إعادة تعيين هذا الجهاز، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الهاتف %d مرة. ستتم إعادة تعيين هذا الهاتف، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الجهاز اللوحي %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم." + "أخطأت في محاولة فتح قفل الهاتف %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة هذا المستخدم، ومن ثم يتم حذف جميع بيانات المستخدم." + "أخطأت في محاولة فتح قفل الجهاز اللوحي %d مرة. ستتم إزالة المستخدم، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الهاتف %d مرة. ستتم إزالة المستخدم، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الجهاز اللوحي %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بيانات الملف الشخصي." + "أخطأت في محاولة فتح قفل الهاتف %1$d مرة. بعد %2$d محاولة غير ناجحة أخرى، ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بيانات الملف الشخصي." + "أخطأت في محاولة فتح قفل الجهاز اللوحي %d مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته." + "أخطأت في محاولة فتح قفل الهاتف %d مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته." "لقد رسمت نقش فتح القفل بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال %3$d ثانية." "لقد رسمت نقش فتح القفل بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال %3$d ثانية." "‏رمز \"رقم التعريف الشخصي\" لشريحة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز." @@ -142,28 +142,28 @@ "اختار المشرف قفل الجهاز" "تم حظر الجهاز يدويًا" - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد النقش. - لم يتم إلغاء تأمين الجهاز لمدة ساعتين (%d). تأكيد النقش. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعات. تأكيد النقش. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد النقش. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد النقش. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد النقش. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد النقش. + لم يتم فتح قفل الجهاز لمدة ساعتين (%d). تأكيد النقش. + لم يتم فتح قفل الجهاز لمدة %d ساعات. تأكيد النقش. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد النقش. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد النقش. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد النقش. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. - لم يتم إلغاء تأمين الجهاز لمدة ساعتين (%d). تأكيد رقم التعريف الشخصي. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. + لم يتم فتح قفل الجهاز لمدة ساعتين (%d). تأكيد رقم التعريف الشخصي. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد رقم التعريف الشخصي. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد كلمة المرور. - لم يتم إلغاء تأمين الجهاز لمدة ساعتين (%d). تأكيد كلمة المرور. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعات. تأكيد كلمة المرور. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد كلمة المرور. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد كلمة المرور. - لم يتم إلغاء تأمين الجهاز لمدة %d ساعة. تأكيد كلمة المرور. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد كلمة المرور. + لم يتم فتح قفل الجهاز لمدة ساعتين (%d). تأكيد كلمة المرور. + لم يتم فتح قفل الجهاز لمدة %d ساعات. تأكيد كلمة المرور. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد كلمة المرور. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد كلمة المرور. + لم يتم فتح قفل الجهاز لمدة %d ساعة. تأكيد كلمة المرور. "لم يتم التعرف عليها." "لم يتم التعرّف عليه." diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 1ec9c7283238..5998c56c33b0 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -107,7 +107,7 @@ "الكاميرا" "الهاتف" "المساعد الصوتي" - "إلغاء القفل" + "فتح القفل" "في انتظار بصمة الإصبع" "فتح القفل بدون استخدام بصمة إصبعك" "مسح الوجه" @@ -536,10 +536,10 @@ "أنت متصل بـ %1$s، الذي يمكنه مراقبة أنشطتك الشخصية على الشبكة، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب." "يخضع الملف الشخصي للعمل لإدارة %1$s. تم ربط الملف الشخصي بـ %2$s، الذي يمكنه مراقبة أنشطة شبكتك، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nيمكنك الاتصال بالمشرف للحصول على مزيد من المعلومات." "يخضع الملف الشخصي للعمل لإدارة %1$s. تم ربط هذا الملف الشخصي بـ %2$s، الذي يمكنه مراقبة أنشطة شبكتك، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nتم ربطك بـ %3$s، الذي يمكنه مراقبة أنشطة شبكتك الشخصية." - "‏إلغاء القفل باستمرار بواسطة TrustAgent" - "سيظل الجهاز مقفلاً إلى أن يتم إلغاء قفله يدويًا" + "‏فتح القفل باستمرار بواسطة TrustAgent" + "سيظل الجهاز مقفلاً إلى أن يتم فتح قفله يدويًا" "الحصول على الإشعارات بشكل أسرع" - "الاطّلاع عليها قبل إلغاء القفل" + "الاطّلاع عليها قبل فتح القفل" "لا، شكرًا" "إعداد" "%1$s. %2$s" diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 6dbd11266805..62d0007b6410 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -876,7 +876,7 @@ "সাধারণ বার্তাগুলি" "স্টোরেজ" "হিন্ট" - "ঝটপট অ্যাপ" + "ইনস্ট্যান্ট অ্যাপ" "%1$s চলছে" "অ্যাপটি ইনস্টল না করে চালু করা হয়েছে।" "অ্যাপটি ইনস্টল না করে চালু করা হয়েছে। আরও জানতে ট্যাপ করুন।" diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index ac9bd2ac82ef..38837ca6824a 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -509,7 +509,7 @@ "%1$s uses %2$s to manage your device." "Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information." " " - "Find out more" + "Learn more" "You\'re connected to %1$s, which can monitor your network activity, including emails, apps and websites." " " "Open VPN settings" diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 31bc5004810d..ba7c60948f3e 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -509,7 +509,7 @@ "%1$s uses %2$s to manage your device." "Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information." " " - "Find out more" + "Learn more" "You\'re connected to %1$s, which can monitor your network activity, including emails, apps and websites." " " "Open VPN settings" diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index ac9bd2ac82ef..38837ca6824a 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -509,7 +509,7 @@ "%1$s uses %2$s to manage your device." "Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information." " " - "Find out more" + "Learn more" "You\'re connected to %1$s, which can monitor your network activity, including emails, apps and websites." " " "Open VPN settings" diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index ac9bd2ac82ef..38837ca6824a 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -509,7 +509,7 @@ "%1$s uses %2$s to manage your device." "Your admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information." " " - "Find out more" + "Learn more" "You\'re connected to %1$s, which can monitor your network activity, including emails, apps and websites." " " "Open VPN settings" diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 4d3240d6a5c9..01200b782b21 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -381,8 +381,8 @@ "Al anochecer" "Hasta el amanecer" "NFC" - "La conexión NFC está inhabilitada" - "La conexión NFC está habilitada" + "El NFC está desactivado" + "El NFC está activado" "Desliza el dedo hacia arriba para cambiar de aplicación" "Arrastra hacia la derecha para cambiar rápidamente de aplicación" "Mostrar u ocultar aplicaciones recientes" diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index aa60d420f79f..4362e8d5b56d 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -55,12 +55,12 @@ "Ikusi" "Ireki %1$s %2$s konektatzen den guztietan" "Ireki %1$s %2$s konektatzen den guztietan" - "USB arazketa onartu?" + "USB bidezko arazketa onartu?" "Ordenagailuaren RSA gakoaren erreferentzia-gako digitala hau da:\n%1$s" "Eman beti ordenagailu honetatik arazteko baimena" "Baimendu" - "Ez da onartzen USB arazketa" - "Gailu honetan saioa hasita daukan erabiltzaileak ezin du aktibatu USB arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira." + "Ez da onartzen USB bidezko arazketa" + "Gailu honetan saioa hasita daukan erabiltzaileak ezin du aktibatu USB bidezko arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira." "Desgaitu egin da USB ataka" "USB ataka desgaitu egin da gailua likido edo zikinkeriengandik babesteko, eta ez du hautemango osagarririk.\n\nJakinarazpen bat jasoko duzu USB ataka berriz erabiltzeko moduan dagoenean." "USB ataka gaitu da kargagailuak eta osagarriak hautemateko" diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 387d57ef2122..39b3a9179922 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -381,7 +381,7 @@ "Activé la nuit" "Jusqu\'à l\'aube" "NFC" - "La technologie NFC est désactivée" + "NFC désactivée" "La technologie NFC est activée" "Balayer l\'écran vers le haut pour changer d\'application" "Déplacer vers la droite pour changer rapidement d\'application" diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index a90c2e50fef9..9e35f99dbc50 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -876,7 +876,7 @@ "सामान्य संदेश" "जगह" "संकेत" - "इंस्टेंट ऐप" + "झटपट ऐप्लिकेशन" "%1$s चल रहा है" "ऐप्लिकेशन इंस्टॉल किए बिना ही खुल गया है." "ऐप्लिकेशन इंस्टॉल किए बिना ही खुल गया है. ज़्यादा जानने के लिए टैप करें." diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index ca660d76961b..0acd0e56f1c9 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -550,7 +550,7 @@ "Para soltar este ecrã, toque sem soltar nos botões Anterior e Vista geral." "Para soltar este ecrã, toque sem soltar nos botões Anterior e Página inicial." "Para soltar este ecrã, deslize rapidamente para cima sem soltar." - "Compreendi" + "OK" "Não, obrigado" "Ecrã fixo" "Ecrã solto" @@ -614,7 +614,7 @@ "Diversão para alguns, mas não para todos" "O Sintonizador da interface do sistema disponibiliza-lhe formas adicionais ajustar e personalizar a interface do utilizador do Android. Estas funcionalidades experimentais podem ser alteradas, deixar de funcionar ou desaparecer em versões futuras. Prossiga com cuidado." "Estas funcionalidades experimentais podem ser alteradas, deixar de funcionar ou desaparecer em versões futuras. Prossiga com cuidado." - "Compreendi" + "OK" "Parabéns! O Sintonizador da interface do sistema foi adicionado às Definições" "Remover das Definições" "Pretende remover o Sintonizador da interface do sistema das Definições e deixar de utilizar todas as respetivas funcionalidades?" @@ -912,7 +912,7 @@ "Poupança de bateria agendada ativada" "A Poupança de bateria é ativada automaticamente quando o nível de bateria está abaixo de %d%%." "Definições" - "Compreendi" + "OK" "Despejar pilha SysUI" "A aplicação %1$s está a utilizar o(a) %2$s." "As aplicações estão a utilizar o(a) %s." -- GitLab From 0bba8d5ff999a135b7286f6c349ae68d8f9c6053 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Tue, 9 Apr 2019 13:38:07 -0700 Subject: [PATCH 016/143] DO NOT MERGE SetMode: Don't call into PM with AppOps lock held In the setmode paths do not call into package manager with the app-ops lock held. Otherwise we might get dead-locks then someone calls into app-ops manager with the package manager lock held. Test: Booted and saw no errors from the changed code Bug: 124731615 Bug: 146463528 Bug: 146590200 Bug: 147649036 Change-Id: If074bed1bd246a81791a7d9fd656f42f1a755495 (cherry picked from commit ec142a52fe6da0a18a1274249ae452cc5a8669fa) --- .../android/server/appop/AppOpsService.java | 241 +++++++++++------- 1 file changed, 146 insertions(+), 95 deletions(-) diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 3ba31e9ef97a..2949099e305e 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1105,8 +1105,8 @@ public class AppOpsService extends IAppOpsService.Stub { return Collections.emptyList(); } synchronized (this) { - Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */, - false /* uidMismatchExpected */); + Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */, + false /* edit */); if (pkgOps == null) { return null; } @@ -1203,8 +1203,7 @@ public class AppOpsService extends IAppOpsService.Stub { private void pruneOp(Op op, int uid, String packageName) { if (!op.hasAnyTime()) { - Ops ops = getOpsRawLocked(uid, packageName, false /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */); if (ops != null) { ops.remove(op.op); if (ops.size() <= 0) { @@ -1404,11 +1403,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } - @Override - public void setMode(int code, int uid, String packageName, int mode) { - setMode(code, uid, packageName, mode, true, false); - } - /** * Sets the mode for a certain op and uid. * @@ -1416,19 +1410,25 @@ public class AppOpsService extends IAppOpsService.Stub { * @param uid The UID for which to set * @param packageName The package for which to set * @param mode The new mode to set - * @param verifyUid Iff {@code true}, check that the package name belongs to the uid - * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid == - * false}) */ - private void setMode(int code, int uid, @NonNull String packageName, int mode, - boolean verifyUid, boolean isPrivileged) { + @Override + public void setMode(int code, int uid, @NonNull String packageName, int mode) { enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); verifyIncomingOp(code); ArraySet repCbs = null; code = AppOpsManager.opToSwitch(code); + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot setMode", e); + return; + } + synchronized (this) { UidState uidState = getUidStateLocked(uid, false); - Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged); + Op op = getOpLocked(code, uid, packageName, isPrivileged, true); if (op != null) { if (op.mode != mode) { op.mode = mode; @@ -1817,11 +1817,19 @@ public class AppOpsService extends IAppOpsService.Stub { if (isOpRestrictedDueToSuspend(code, packageName, uid)) { return AppOpsManager.MODE_IGNORED; } - synchronized (this) { + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (Exception e) { if (verify) { - checkPackage(uid, packageName); + throw e; } - if (isOpRestrictedLocked(uid, code, packageName)) { + return AppOpsManager.MODE_IGNORED; + } + + synchronized (this) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } code = AppOpsManager.opToSwitch(code); @@ -1831,7 +1839,7 @@ public class AppOpsService extends IAppOpsService.Stub { final int rawMode = uidState.opModes.get(code); return raw ? rawMode : uidState.evalMode(code, rawMode); } - Op op = getOpLocked(code, uid, packageName, false, verify, false); + Op op = getOpLocked(code, uid, packageName, false, false); if (op == null) { return AppOpsManager.opToDefaultMode(code); } @@ -1936,14 +1944,12 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public int checkPackage(int uid, String packageName) { Preconditions.checkNotNull(packageName); - synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - true /* uidMismatchExpected */); - if (ops != null) { - return AppOpsManager.MODE_ALLOWED; - } else { - return AppOpsManager.MODE_ERRORED; - } + try { + verifyAndGetIsPrivileged(uid, packageName); + + return AppOpsManager.MODE_ALLOWED; + } catch (SecurityException ignored) { + return AppOpsManager.MODE_ERRORED; } } @@ -2006,9 +2012,16 @@ public class AppOpsService extends IAppOpsService.Stub { private int noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName, @OpFlags int flags) { + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot startOperation", e); + return AppOpsManager.MODE_IGNORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */); if (ops == null) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); @@ -2017,7 +2030,7 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); return AppOpsManager.MODE_IGNORED; @@ -2176,16 +2189,25 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_IGNORED; } ClientState client = (ClientState)token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot startOperation", e); + return AppOpsManager.MODE_IGNORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged, + true /* edit */); if (ops == null) { if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + resolvedPackageName); return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { + if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } final int switchCode = AppOpsManager.opToSwitch(code); @@ -2257,8 +2279,17 @@ public class AppOpsService extends IAppOpsService.Stub { return; } ClientState client = (ClientState) token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot finishOperation", e); + return; + } + synchronized (this) { - Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false); + Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true); if (op == null) { return; } @@ -2508,8 +2539,76 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.pendingStateCommitTime = 0; } - private Ops getOpsRawLocked(int uid, String packageName, boolean edit, - boolean uidMismatchExpected) { + /** + * Verify that package belongs to uid and return whether the package is privileged. + * + * @param uid The uid the package belongs to + * @param packageName The package the might belong to the uid + * + * @return {@code true} iff the package is privileged + */ + private boolean verifyAndGetIsPrivileged(int uid, String packageName) { + if (uid == Process.ROOT_UID) { + // For backwards compatibility, don't check package name for root UID. + return false; + } + + // Do not check if uid/packageName is already known + synchronized (this) { + UidState uidState = mUidStates.get(uid); + if (uidState != null && uidState.pkgOps != null) { + Ops ops = uidState.pkgOps.get(packageName); + + if (ops != null) { + return ops.isPrivileged; + } + } + } + + boolean isPrivileged = false; + final long ident = Binder.clearCallingIdentity(); + try { + int pkgUid; + + ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class) + .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_INSTANT, + Process.SYSTEM_UID, UserHandle.getUserId(uid)); + if (appInfo != null) { + pkgUid = appInfo.uid; + isPrivileged = (appInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + } else { + pkgUid = resolveUid(packageName); + if (pkgUid >= 0) { + isPrivileged = false; + } + } + if (pkgUid != uid) { + throw new SecurityException("Specified package " + packageName + " under uid " + uid + + " but it is really " + pkgUid); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + + return isPrivileged; + } + + /** + * Get (and potentially create) ops. + * + * @param uid The uid the package belongs to + * @param packageName The name of the package + * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false) + * @param edit If an ops does not exist, create the ops? + + * @return + */ + private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) { UidState uidState = getUidStateLocked(uid, edit); if (uidState == null) { return null; @@ -2527,47 +2626,6 @@ public class AppOpsService extends IAppOpsService.Stub { if (!edit) { return null; } - boolean isPrivileged = false; - // This is the first time we have seen this package name under this uid, - // so let's make sure it is valid. - if (uid != 0) { - final long ident = Binder.clearCallingIdentity(); - try { - int pkgUid = -1; - try { - ApplicationInfo appInfo = ActivityThread.getPackageManager() - .getApplicationInfo(packageName, - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - UserHandle.getUserId(uid)); - if (appInfo != null) { - pkgUid = appInfo.uid; - isPrivileged = (appInfo.privateFlags - & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; - } else { - pkgUid = resolveUid(packageName); - if (pkgUid >= 0) { - isPrivileged = false; - } - } - } catch (RemoteException e) { - Slog.w(TAG, "Could not contact PackageManager", e); - } - if (pkgUid != uid) { - // Oops! The package name is not valid for the uid they are calling - // under. Abort. - if (!uidMismatchExpected) { - RuntimeException ex = new RuntimeException("here"); - ex.fillInStackTrace(); - Slog.w(TAG, "Bad call: specified package " + packageName - + " under uid " + uid + " but it is really " + pkgUid, ex); - } - return null; - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } ops = new Ops(packageName, uidState, isPrivileged); uidState.pkgOps.put(packageName, ops); } @@ -2575,7 +2633,7 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * Get the state of all ops for a package, don't verify that package belongs to uid. + * Get the state of all ops for a package. * *

Usually callers should use {@link #getOpLocked} and not call this directly. * @@ -2633,23 +2691,15 @@ public class AppOpsService extends IAppOpsService.Stub { * @param code The code of the op * @param uid The uid the of the package * @param packageName The package name for which to get the state for + * @param isPrivileged Whether the package is privileged or not (only used if {@code edit + * == true}) * @param edit Iff {@code true} create the {@link Op} object if not yet created - * @param verifyUid Iff {@code true} check that the package belongs to the uid - * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid - * == false}) * * @return The {@link Op state} of the op */ - private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit, - boolean verifyUid, boolean isPrivileged) { - Ops ops; - - if (verifyUid) { - ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */); - } else { - ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); - } - + private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, + boolean isPrivileged, boolean edit) { + Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); if (ops == null) { return null; } @@ -2679,7 +2729,8 @@ public class AppOpsService extends IAppOpsService.Stub { return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); } - private boolean isOpRestrictedLocked(int uid, int code, String packageName) { + private boolean isOpRestrictedLocked(int uid, int code, String packageName, + boolean isPrivileged) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); @@ -2691,8 +2742,8 @@ public class AppOpsService extends IAppOpsService.Stub { if (AppOpsManager.opAllowSystemBypassRestriction(code)) { // If we are the system, bypass user restrictions for certain codes synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, + true /* edit */); if ((ops != null) && ops.isPrivileged) { return false; } @@ -3063,7 +3114,7 @@ public class AppOpsService extends IAppOpsService.Stub { out.attribute(null, "n", Integer.toString(pkg.getUid())); synchronized (this) { Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), - false /* edit */, false /* uidMismatchExpected */); + false /* isPrivileged */, false /* edit */); // Should always be present as the list of PackageOps is generated // from Ops. if (ops != null) { -- GitLab From 1a459638398446938a20b32fa0fbc63ad4bd505f Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Wed, 18 Dec 2019 09:54:09 -0500 Subject: [PATCH 017/143] Prevent sending early termination of appop use If a package starts a particular appop both as active and noted, once one of them is finished (usually noted after 5s), a message will be sent to callbacks indicating the end of the use. However, the app op may still be active. This could result in the removal of indicators prematurely from notifications. This change prevents that from happening by checking if the app op is still in use by that combination uid/package (either active or noted) and not notifying listeners if that's the case. Test: atest AppOpsControllerTest Test: use app from bug report. Observe that notification does not lose the microphone indicator Bug: 144092031 Merged-In: I180e7c257e6171e7686ba7eda9bf02249358ed0 Change-Id: I94473c3ccf1318dac29f067dade91e540e20285e --- .../systemui/appops/AppOpsControllerImpl.java | 51 ++++++- .../systemui/appops/AppOpsControllerTest.java | 138 +++++++++++++++++- 2 files changed, 179 insertions(+), 10 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java index afb8e7421412..bfdda207b5b4 100644 --- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java @@ -193,20 +193,32 @@ public class AppOpsControllerImpl implements AppOpsController, mNotedItems.remove(item); if (DEBUG) Log.w(TAG, "Removed item: " + item.toString()); } - notifySuscribers(code, uid, packageName, false); + boolean active; + // Check if the item is also active + synchronized (mActiveItems) { + active = getAppOpItem(mActiveItems, code, uid, packageName) != null; + } + if (!active) { + notifySuscribers(code, uid, packageName, false); + } } - private void addNoted(int code, int uid, String packageName) { + private boolean addNoted(int code, int uid, String packageName) { AppOpItem item; + boolean createdNew = false; synchronized (mNotedItems) { item = getAppOpItem(mNotedItems, code, uid, packageName); if (item == null) { item = new AppOpItem(code, uid, packageName, System.currentTimeMillis()); mNotedItems.add(item); if (DEBUG) Log.w(TAG, "Added item: " + item.toString()); + createdNew = true; } } + // We should keep this so we make sure it cannot time out. + mBGHandler.removeCallbacksAndMessages(item); mBGHandler.scheduleRemoval(item, NOTED_OP_TIME_DELAY_MS); + return createdNew; } /** @@ -253,23 +265,46 @@ public class AppOpsControllerImpl implements AppOpsController, @Override public void onOpActiveChanged(int code, int uid, String packageName, boolean active) { - if (updateActives(code, uid, packageName, active)) { - notifySuscribers(code, uid, packageName, active); + if (DEBUG) { + Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s", code, uid, packageName, + Boolean.toString(active))); + } + boolean activeChanged = updateActives(code, uid, packageName, active); + if (!activeChanged) return; // early return + // Check if the item is also noted, in that case, there's no update. + boolean alsoNoted; + synchronized (mNotedItems) { + alsoNoted = getAppOpItem(mNotedItems, code, uid, packageName) != null; + } + // If active is true, we only send the update if the op is not actively noted (already true) + // If active is false, we only send the update if the op is not actively noted (prevent + // early removal) + if (!alsoNoted) { + mBGHandler.post(() -> notifySuscribers(code, uid, packageName, active)); } } @Override public void onOpNoted(int code, int uid, String packageName, int result) { if (DEBUG) { - Log.w(TAG, "Op: " + code + " with result " + AppOpsManager.MODE_NAMES[result]); + Log.w(TAG, "Noted op: " + code + " with result " + + AppOpsManager.MODE_NAMES[result] + " for package " + packageName); } if (result != AppOpsManager.MODE_ALLOWED) return; - addNoted(code, uid, packageName); - notifySuscribers(code, uid, packageName, true); + boolean notedAdded = addNoted(code, uid, packageName); + if (!notedAdded) return; // early return + boolean alsoActive; + synchronized (mActiveItems) { + alsoActive = getAppOpItem(mActiveItems, code, uid, packageName) != null; + } + if (!alsoActive) { + mBGHandler.post(() -> notifySuscribers(code, uid, packageName, true)); + } } private void notifySuscribers(int code, int uid, String packageName, boolean active) { if (mCallbacksByCode.containsKey(code)) { + if (DEBUG) Log.d(TAG, "Notifying of change in package " + packageName); for (Callback cb: mCallbacksByCode.get(code)) { cb.onActiveStateChanged(code, uid, packageName, active); } @@ -292,7 +327,7 @@ public class AppOpsControllerImpl implements AppOpsController, } - protected final class H extends Handler { + protected class H extends Handler { H(Looper looper) { super(looper); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java index bd7f897dc1c0..df7221e2f663 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java @@ -29,6 +29,8 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static java.lang.Thread.sleep; + import android.app.AppOpsManager; import android.content.pm.PackageManager; import android.os.UserHandle; @@ -37,7 +39,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import org.junit.Before; @@ -46,6 +47,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -64,14 +67,16 @@ public class AppOpsControllerTest extends SysuiTestCase { private AppOpsControllerImpl.H mMockHandler; private AppOpsControllerImpl mController; + private TestableLooper mTestableLooper; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mTestableLooper = TestableLooper.get(this); getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager); - mController = new AppOpsControllerImpl(mContext, Dependency.get(Dependency.BG_LOOPER)); + mController = new AppOpsControllerImpl(mContext, mTestableLooper.getLooper()); } @Test @@ -95,6 +100,7 @@ public class AppOpsControllerTest extends SysuiTestCase { AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); + mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); } @@ -104,6 +110,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); verify(mCallback, never()).onActiveStateChanged( anyInt(), anyInt(), anyString(), anyBoolean()); } @@ -114,6 +121,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.removeCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); verify(mCallback, never()).onActiveStateChanged( anyInt(), anyInt(), anyString(), anyBoolean()); } @@ -124,6 +132,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.removeCallback(new int[]{AppOpsManager.OP_CAMERA}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); } @@ -186,4 +195,129 @@ public class AppOpsControllerTest extends SysuiTestCase { verify(mMockHandler).removeCallbacksAndMessages(null); assertTrue(mController.getActiveAppOps().isEmpty()); } + + @Test + public void noDoubleUpdateOnOpNoted() { + mController.setBGHandler(mMockHandler); + + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + + // Only one post to notify subscribers + verify(mMockHandler, times(1)).post(any()); + + List list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + } + + @Test + public void onDoubleOPNoted_scheduleTwiceForRemoval() { + mController.setBGHandler(mMockHandler); + + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + + // Only one post to notify subscribers + verify(mMockHandler, times(2)).scheduleRemoval(any(), anyLong()); + } + + @Test + public void testActiveOpNotRemovedAfterNoted() throws InterruptedException { + // Replaces the timeout delay with 5 ms + AppOpsControllerImpl.H testHandler = mController.new H(mTestableLooper.getLooper()) { + @Override + public void scheduleRemoval(AppOpItem item, long timeToRemoval) { + super.scheduleRemoval(item, 5L); + } + }; + + mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + mController.setBGHandler(testHandler); + + mController.onOpActiveChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + + mTestableLooper.processAllMessages(); + List list = mController.getActiveAppOps(); + verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + + // Duplicates are not removed between active and noted + assertEquals(2, list.size()); + + sleep(10L); + + mTestableLooper.processAllMessages(); + + verify(mCallback, never()).onActiveStateChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, false); + list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + } + + @Test + public void testNotedNotRemovedAfterActive() { + mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + + mController.onOpActiveChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + + mTestableLooper.processAllMessages(); + List list = mController.getActiveAppOps(); + verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + + // Duplicates are not removed between active and noted + assertEquals(2, list.size()); + + mController.onOpActiveChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, false); + + mTestableLooper.processAllMessages(); + + verify(mCallback, never()).onActiveStateChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, false); + list = mController.getActiveAppOps(); + assertEquals(1, list.size()); + } + + @Test + public void testNotedAndActiveOnlyOneCall() { + mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + + mController.onOpActiveChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + + mTestableLooper.processAllMessages(); + verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + } + + @Test + public void testActiveAndNotedOnlyOneCall() { + mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); + + mController.onOpActiveChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + + mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + + mTestableLooper.processAllMessages(); + verify(mCallback).onActiveStateChanged( + AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); + } } -- GitLab From 73e2690eded5d035de8560aaff60a6f47290305d Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Tue, 7 May 2019 08:57:35 -0700 Subject: [PATCH 018/143] DO NOT MERGE Remove unnecessary internal APIs. Test: Built Bug: 146463528 Bug: 146590200 Bug: 147649036 Change-Id: I5391ac4989d7d5712982f5608f9fc28cf7935b00 --- .../android/app/AppOpsManagerInternal.java | 29 ----------------- .../android/server/appop/AppOpsService.java | 31 ++----------------- 2 files changed, 2 insertions(+), 58 deletions(-) diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 08cad04401e9..996939eb9ee1 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -16,7 +16,6 @@ package android.app; -import android.annotation.NonNull; import android.util.SparseIntArray; import com.android.internal.util.function.QuadFunction; @@ -76,20 +75,6 @@ public abstract class AppOpsManagerInternal { */ public abstract void setDeviceAndProfileOwners(SparseIntArray owners); - /** - * Sets the app-ops mode for a certain app-op and uid. - * - *

Similar as {@link AppOpsManager#setUidMode} but does not require the package manager to be - * working. Hence this can be used very early during boot. - * - *

Only for internal callers. Does not verify that package name belongs to uid. - * - * @param code The op code to set. - * @param uid The UID for which to set. - * @param mode The new mode to set. - */ - public abstract void setUidMode(int code, int uid, int mode); - /** * Set all {@link #setMode (package) modes} for this uid to the default value. * @@ -97,18 +82,4 @@ public abstract class AppOpsManagerInternal { * @param uid The uid */ public abstract void setAllPkgModesToDefault(int code, int uid); - - /** - * Get the (raw) mode of an app-op. - * - *

Does not verify that package belongs to uid. The caller needs to do that. - * - * @param code The code of the op - * @param uid The uid of the package the op belongs to - * @param packageName The package the op belongs to - * - * @return The mode of the op - */ - public abstract @AppOpsManager.Mode int checkOperationUnchecked(int code, int uid, - @NonNull String packageName); } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 2949099e305e..1760371597f1 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1793,14 +1793,6 @@ public class AppOpsService extends IAppOpsService.Stub { return checkOperationUnchecked(code, uid, resolvedPackageName, raw); } - /** - * @see #checkOperationUnchecked(int, int, String, boolean, boolean) - */ - private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw) { - return checkOperationUnchecked(code, uid, packageName, raw, true); - } - /** * Get the mode of an app-op. * @@ -1808,25 +1800,16 @@ public class AppOpsService extends IAppOpsService.Stub { * @param uid The uid of the package the op belongs to * @param packageName The package the op belongs to * @param raw If the raw state of eval-ed state should be checked. - * @param verify If the code should check the package belongs to the uid * * @return The mode of the op */ private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw, boolean verify) { + boolean raw) { if (isOpRestrictedDueToSuspend(code, packageName, uid)) { return AppOpsManager.MODE_IGNORED; } - boolean isPrivileged; - try { - isPrivileged = verifyAndGetIsPrivileged(uid, packageName); - } catch (Exception e) { - if (verify) { - throw e; - } - return AppOpsManager.MODE_IGNORED; - } + boolean isPrivileged = verifyAndGetIsPrivileged(uid, packageName); synchronized (this) { if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { @@ -4692,19 +4675,9 @@ public class AppOpsService extends IAppOpsService.Stub { } } - @Override - public void setUidMode(int code, int uid, int mode) { - AppOpsService.this.setUidMode(code, uid, mode); - } - @Override public void setAllPkgModesToDefault(int code, int uid) { AppOpsService.this.setAllPkgModesToDefault(code, uid); } - - @Override - public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) { - return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false); - } } } -- GitLab From 892ded1e8a56dd622fd2bbddd77c762f0cad8f4e Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Wed, 12 Jun 2019 16:31:29 -0700 Subject: [PATCH 019/143] DO NOT MERGE Don't throw exception in AppOpsManager.checkOp In Q we handled the case where the op does not match the package name by returning the default state. NoteOp and StartOp returned errored. Fix up these scenarios. Test: - atest CtsAppOpsTestCases - backported new test to Q to verify the behavior is the same in Q and master Bug: 132885449 Bug: 146463528 Bug: 146590200 Bug: 147649036 Change-Id: I5b94e92af759580f2d2644ece49f159bd006b31c --- .../com/android/server/appop/AppOpsService.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 1760371597f1..3e7188c6e8ec 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1809,7 +1809,14 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_IGNORED; } - boolean isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + boolean isPrivileged; + + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "checkOperation", e); + return AppOpsManager.opToDefaultMode(code); + } synchronized (this) { if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { @@ -1999,8 +2006,8 @@ public class AppOpsService extends IAppOpsService.Stub { try { isPrivileged = verifyAndGetIsPrivileged(uid, packageName); } catch (SecurityException e) { - Slog.e(TAG, "Cannot startOperation", e); - return AppOpsManager.MODE_IGNORED; + Slog.e(TAG, "noteOperation", e); + return AppOpsManager.MODE_ERRORED; } synchronized (this) { @@ -2177,8 +2184,8 @@ public class AppOpsService extends IAppOpsService.Stub { try { isPrivileged = verifyAndGetIsPrivileged(uid, packageName); } catch (SecurityException e) { - Slog.e(TAG, "Cannot startOperation", e); - return AppOpsManager.MODE_IGNORED; + Slog.e(TAG, "startOperation", e); + return AppOpsManager.MODE_ERRORED; } synchronized (this) { -- GitLab From c6a61a6b0ce93a5ede0842fdaefca73a1bf243a9 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 18 Dec 2019 07:01:25 +0100 Subject: [PATCH 020/143] Fix IsolatedUidAllocator for non-primary users. The UID allocator stores complete UIDs, not app IDs. When removing a UID from the range, we should therefore also use the UID, not the app ID. Also added a test to cover this scenario, which passes with this change. Bug: 146313311 Test: atest ActivityManagerTest Change-Id: I1118ec73dcee5987e12f35aabce5cfa8cbe407a1 (cherry picked from commit c9a0df2d88884617b86c09a0ab86363200d6a66d) --- .../java/com/android/server/am/ProcessList.java | 4 +--- .../server/am/ActivityManagerServiceTest.java | 13 ++++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index fe29a36ec45f..278163b9dfe4 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -422,9 +422,7 @@ public final class ProcessList { @GuardedBy("ProcessList.this.mService") void freeIsolatedUidLocked(int uid) { - // Strip out userId - final int appId = UserHandle.getAppId(uid); - mUidUsed.delete(appId); + mUidUsed.delete(uid); } }; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 3df6976a2cae..2b849e71fdaf 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -346,10 +346,21 @@ public class ActivityManagerServiceTest { verifyUidRangesNoOverlap(range, range2); verifyIsolatedUidAllocator(range2); - // Free both, then try to allocate the maximum number of UID ranges + // Free both allocator.freeUidRangeLocked(appInfo); allocator.freeUidRangeLocked(appInfo2); + // Verify for a secondary user + ApplicationInfo appInfo3 = new ApplicationInfo(); + appInfo3.processName = "com.android.test.app"; + appInfo3.uid = 1010000; + final IsolatedUidRange range3 = allocator.getOrCreateIsolatedUidRangeLocked( + appInfo3.processName, appInfo3.uid); + validateAppZygoteIsolatedUidRange(range3); + verifyIsolatedUidAllocator(range3); + + allocator.freeUidRangeLocked(appInfo3); + // Try to allocate the maximum number of UID ranges int maxNumUidRanges = (Process.LAST_APP_ZYGOTE_ISOLATED_UID - Process.FIRST_APP_ZYGOTE_ISOLATED_UID + 1) / Process.NUM_UIDS_PER_APP_ZYGOTE; for (int i = 0; i < maxNumUidRanges; i++) { -- GitLab From ad08b5b831d4e7abee46593686f235f45be65b93 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Wed, 15 Jan 2020 13:59:00 -0500 Subject: [PATCH 021/143] DO NOT MERGE: Use a copy of bt device profile list when updating CachedBluetoothDevice#getProfiles() only returns a Collections.unmodifiableList which isn't thread safe. Use a copy in BluetoothControllerImpl so we can avoid a CME Test: atest SystemUITests Bug: 146828136 Change-Id: I451a746836c67b8b82f26f4f39b5363ac5e0ea79 --- .../android/settingslib/bluetooth/CachedBluetoothDevice.java | 4 ++++ .../systemui/statusbar/policy/BluetoothControllerImpl.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 8f164f1592d3..c7d72f2e3ce4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -661,6 +661,10 @@ public class CachedBluetoothDevice implements Comparable return Collections.unmodifiableList(mProfiles); } + public List getProfileListCopy() { + return new ArrayList<>(mProfiles); + } + public List getConnectableProfiles() { List connectableProfiles = new ArrayList(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java index 351579a95710..7d562fbdfe61 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java @@ -277,7 +277,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa boolean otherProfileConnected = false; for (CachedBluetoothDevice device : getDevices()) { - for (LocalBluetoothProfile profile : device.getProfiles()) { + for (LocalBluetoothProfile profile : device.getProfileListCopy()) { int profileId = profile.getProfileId(); boolean isConnected = device.isConnectedProfile(profile); if (profileId == BluetoothProfile.HEADSET -- GitLab From 05024a1523f796ed740781218cdde5849e4db84c Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Wed, 8 May 2019 15:14:09 -0700 Subject: [PATCH 022/143] DO NOT MERGE Fix AppOpsServiceTest - Mock LocalService dependency - Always assume calling app has appropriate permissions Test: atest atest FrameworksMockingServicesTests:com.android.server.appop Fixes: 132274015 Fixes: 147778434 Bug: 146463528 Bug: 146590200 Merged-In: Ie816e0c6c81ecf25d37f05187591ca0d1edf0bc2 Change-Id: Ie816e0c6c81ecf25d37f05187591ca0d1edf0bc2 --- .../com/android/server/appop/TEST_MAPPING | 8 + .../mockingservicestests/AndroidManifest.xml | 1 + .../server/appop/AppOpsServiceTest.java | 167 +++++++++++------- 3 files changed, 114 insertions(+), 62 deletions(-) rename services/tests/{servicestests => mockingservicestests}/src/com/android/server/appop/AppOpsServiceTest.java (76%) diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING index a53797dfa9e0..1a5dac503463 100644 --- a/services/core/java/com/android/server/appop/TEST_MAPPING +++ b/services/core/java/com/android/server/appop/TEST_MAPPING @@ -10,6 +10,14 @@ "include-filter": "com.android.server.appop" } ] + }, + { + "name": "FrameworksMockingServicesTests", + "options": [ + { + "include-filter": "com.android.server.appop" + } + ] } ] } diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml index 32d7d026ff10..1200c0c8c7bd 100644 --- a/services/tests/mockingservicestests/AndroidManifest.xml +++ b/services/tests/mockingservicestests/AndroidManifest.xml @@ -20,6 +20,7 @@ + diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java similarity index 76% rename from services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java rename to services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 71661452d800..698e491a8926 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -25,14 +25,27 @@ import static android.app.AppOpsManager.OP_READ_SMS; import static android.app.AppOpsManager.OP_WIFI_SCAN; import static android.app.AppOpsManager.OP_WRITE_SMS; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; + import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; + import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; import android.content.Context; +import android.content.pm.PackageManagerInternal; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -43,12 +56,17 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; +import com.android.server.LocalServices; + +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.quality.Strictness; import java.io.File; import java.util.List; @@ -69,21 +87,46 @@ public class AppOpsServiceTest { // State will be persisted into this XML file. private static final String APP_OPS_FILENAME = "appops-service-test.xml"; + private static final Context sContext = InstrumentationRegistry.getTargetContext(); + private static final String sMyPackageName = sContext.getOpPackageName(); + private File mAppOpsFile; - private Context mContext; private Handler mHandler; - private AppOpsManager mAppOpsManager; private AppOpsService mAppOpsService; - private String mMyPackageName; private int mMyUid; private long mTestStartMillis; + private StaticMockitoSession mMockingSession; + + @Before + public void mockPackageManagerInternalGetApplicationInfo() { + mMockingSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(LocalServices.class) + .startMocking(); + + // Mock LocalServices.getService(PackageManagerInternal.class).getApplicationInfo dependency + // needed by AppOpsService + PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class); + when(mockPackageManagerInternal.getApplicationInfo(eq(sMyPackageName), anyInt(), anyInt(), + anyInt())).thenReturn(sContext.getApplicationInfo()); + doReturn(mockPackageManagerInternal).when( + () -> LocalServices.getService(PackageManagerInternal.class)); + } + + private void setupAppOpsService() { + mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); + mAppOpsService.mContext = spy(sContext); + + // Always approve all permission checks + doNothing().when(mAppOpsService.mContext).enforcePermission(anyString(), anyInt(), + anyInt(), nullable(String.class)); + } private static String sDefaultAppopHistoryParameters; @Before public void setUp() { - mContext = InstrumentationRegistry.getTargetContext(); - mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME); + mAppOpsFile = new File(sContext.getFilesDir(), APP_OPS_FILENAME); if (mAppOpsFile.exists()) { // Start with a clean state (persisted into XML). mAppOpsFile.delete(); @@ -92,13 +135,10 @@ public class AppOpsServiceTest { HandlerThread handlerThread = new HandlerThread(TAG); handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); - mMyPackageName = mContext.getOpPackageName(); mMyUid = Process.myUid(); - mAppOpsManager = mContext.getSystemService(AppOpsManager.class); - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mHistoricalRegistry.systemReady(mContext.getContentResolver()); - mAppOpsService.mContext = mContext; + setupAppOpsService(); + mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver()); mTestStartMillis = System.currentTimeMillis(); } @@ -118,6 +158,11 @@ public class AppOpsServiceTest { sDefaultAppopHistoryParameters); } + @After + public void resetStaticMocks() { + mMockingSession.finishMocking(); + } + @Test public void testGetOpsForPackage_noOpsLogged() { assertThat(getLoggedOps()).isNull(); @@ -125,16 +170,16 @@ public class AppOpsServiceTest { @Test public void testNoteOperationAndGetOpsForPackage() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); // Note an op that's allowed. - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Note another op that's not allowed. - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName); + mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName); loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED); @@ -148,17 +193,17 @@ public class AppOpsServiceTest { @Test public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() { // This op controls WIFI_SCAN - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1, MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */); // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well. - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ERRORED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName)) + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED); + assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName)) .isEqualTo(MODE_ERRORED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis, @@ -168,15 +213,14 @@ public class AppOpsServiceTest { // Tests the dumping and restoring of the in-memory state to/from XML. @Test public void testStatePersistence() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); + mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName); mAppOpsService.writeState(); // Create a new app ops service, and initialize its state from XML. - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mContext = mContext; + setupAppOpsService(); mAppOpsService.readState(); // Query the state of the 2nd service. @@ -188,13 +232,12 @@ public class AppOpsServiceTest { // Tests that ops are persisted during shutdown. @Test public void testShutdown() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); mAppOpsService.shutdown(); // Create a new app ops service, and initialize its state from XML. - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mContext = mContext; + setupAppOpsService(); mAppOpsService.readState(); // Query the state of the 2nd service. @@ -204,21 +247,21 @@ public class AppOpsServiceTest { @Test public void testGetOpsForPackage() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); // Query all ops List loggedOps = mAppOpsService.getOpsForPackage( - mMyUid, mMyPackageName, null /* all ops */); + mMyUid, sMyPackageName, null /* all ops */); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Query specific ops loggedOps = mAppOpsService.getOpsForPackage( - mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS}); + mMyUid, sMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS}); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Query unknown UID - loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */); + loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, sMyPackageName, null /* all ops */); assertThat(loggedOps).isNull(); // Query unknown package name @@ -226,31 +269,31 @@ public class AppOpsServiceTest { assertThat(loggedOps).isNull(); // Query op code that's not been logged - loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, + loggedOps = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, new int[]{OP_WRITE_SMS}); assertThat(loggedOps).isNull(); } @Test public void testPackageRemoved() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); - mAppOpsService.packageRemoved(mMyUid, mMyPackageName); + mAppOpsService.packageRemoved(mMyUid, sMyPackageName); assertThat(getLoggedOps()).isNull(); } @Ignore("Historical appops are disabled in Android Q") @Test public void testPackageRemovedHistoricalOps() throws InterruptedException { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000); - historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, mMyPackageName, + historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName, AppOpsManager.UID_STATE_PERSISTENT, 0, 1); mAppOpsService.addHistoricalOps(historicalOps); @@ -263,7 +306,7 @@ public class AppOpsServiceTest { }); // First, do a fetch to ensure it's written - mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0, callback); latchRef.get().await(5, TimeUnit.SECONDS); @@ -271,11 +314,11 @@ public class AppOpsServiceTest { assertThat(resultOpsRef.get().isEmpty()).isFalse(); // Then, check it's deleted on removal - mAppOpsService.packageRemoved(mMyUid, mMyPackageName); + mAppOpsService.packageRemoved(mMyUid, sMyPackageName); latchRef.set(new CountDownLatch(1)); - mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0, callback); latchRef.get().await(5, TimeUnit.SECONDS); @@ -285,8 +328,8 @@ public class AppOpsServiceTest { @Test public void testUidRemoved() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); @@ -297,7 +340,7 @@ public class AppOpsServiceTest { private void setupProcStateTests() { // For the location proc state tests - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_FOREGROUND); + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_FOREGROUND); mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0; mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0; mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0; @@ -308,18 +351,18 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -328,11 +371,11 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -341,12 +384,12 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); } @@ -355,18 +398,18 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -375,30 +418,30 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } private List getLoggedOps() { - return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */); + return mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, null /* all ops */); } private void assertContainsOp(List loggedOps, int opCode, long minMillis, @@ -407,7 +450,7 @@ public class AppOpsServiceTest { boolean opLogged = false; for (PackageOps pkgOps : loggedOps) { assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid()); - assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo( + assertWithMessage("Unexpected package name").that(sMyPackageName).isEqualTo( pkgOps.getPackageName()); for (OpEntry opEntry : pkgOps.getOps()) { -- GitLab From 93320661ca9a23c7b38b3f166d0facf048f2a8a3 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Wed, 15 Jan 2020 11:43:47 -0800 Subject: [PATCH 023/143] Fix potential double destroy of AssetManager Assume there is a XmlBlock [X] created by a AssetManager [A] ([A] will have mNumRefs = 2). After [A].close is called (mNumRefs = 1) and then both [X] and [A] are going to be GCed, if [A].finalize is called first (nativeDestroy), the later [X].finalize will invoke [A].xmlBlockGone that triggers the second nativeDestroy of [A] and leads to crash. By clearing the mObject in AssetManager.finalize, the decRefsLocked from other paths won't call nativeDestroy again. Bug: 144028297 Test: atest android.security.cts.AssetManagerTest Change-Id: Ia938502d2443f5a6de6a3cabdb7ce1d41d3ff6d1 Merged-In: Ia938502d2443f5a6de6a3cabdb7ce1d41d3ff6d1 --- .../android/content/res/AssetManager.java | 71 ++++++++++--------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index f0adcd6cfb3e..4a187cd774bb 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -68,24 +68,24 @@ public final class AssetManager implements AutoCloseable { private static final String TAG = "AssetManager"; private static final boolean localLOGV = false || false; - + private static final boolean DEBUG_REFS = false; - + private static final Object sSync = new Object(); /*package*/ static AssetManager sSystem = null; private final TypedValue mValue = new TypedValue(); private final long[] mOffsets = new long[2]; - + // For communication with native code. private long mObject; private StringBlock mStringBlocks[] = null; - + private int mNumRefs = 1; private boolean mOpen = true; private HashMap mRefStacks; - + /** * Create a new AssetManager containing only the basic system assets. * Applications will not generally use this method, instead retrieving the @@ -114,7 +114,7 @@ public final class AssetManager implements AutoCloseable { } } } - + private AssetManager(boolean isSystem) { if (DEBUG_REFS) { synchronized (this) { @@ -337,10 +337,10 @@ public final class AssetManager implements AutoCloseable { * Open an asset using ACCESS_STREAMING mode. This provides access to * files that have been bundled with an application as assets -- that is, * files placed in to the "assets" directory. - * + * * @param fileName The name of the asset to open. This name can be * hierarchical. - * + * * @see #open(String, int) * @see #list */ @@ -353,11 +353,11 @@ public final class AssetManager implements AutoCloseable { * read its contents. This provides access to files that have been bundled * with an application as assets -- that is, files placed in to the * "assets" directory. - * + * * @param fileName The name of the asset to open. This name can be * hierarchical. * @param accessMode Desired access mode for retrieving the data. - * + * * @see #ACCESS_UNKNOWN * @see #ACCESS_STREAMING * @see #ACCESS_RANDOM @@ -397,14 +397,14 @@ public final class AssetManager implements AutoCloseable { /** * Return a String array of all the assets at the given path. - * + * * @param path A relative path within the assets, i.e., "docs/home.html". - * + * * @return String[] Array of strings, one for each asset. These file * names are relative to 'path'. You can open the file by * concatenating 'path' and a name in the returned string (via * File) and passing that to open(). - * + * * @see #open */ public native final String[] list(String path) @@ -416,7 +416,7 @@ public final class AssetManager implements AutoCloseable { * provides direct access to all of the files included in an application * package (not only its assets). Applications should not normally use * this. - * + * * @see #open(String) */ public final InputStream openNonAsset(String fileName) throws IOException { @@ -429,7 +429,7 @@ public final class AssetManager implements AutoCloseable { * provides direct access to all of the files included in an application * package (not only its assets). Applications should not normally use * this. - * + * * @see #open(String, int) */ public final InputStream openNonAsset(String fileName, int accessMode) @@ -440,7 +440,7 @@ public final class AssetManager implements AutoCloseable { /** * {@hide} * Open a non-asset in a specified package. Not for use by applications. - * + * * @param cookie Identifier of the package to be opened. * @param fileName Name of the asset to retrieve. */ @@ -452,7 +452,7 @@ public final class AssetManager implements AutoCloseable { /** * {@hide} * Open a non-asset in a specified package. Not for use by applications. - * + * * @param cookie Identifier of the package to be opened. * @param fileName Name of the asset to retrieve. * @param accessMode Desired access mode for retrieving the data. @@ -477,7 +477,7 @@ public final class AssetManager implements AutoCloseable { throws IOException { return openNonAssetFd(0, fileName); } - + public final AssetFileDescriptor openNonAssetFd(int cookie, String fileName) throws IOException { synchronized (this) { @@ -492,20 +492,20 @@ public final class AssetManager implements AutoCloseable { } throw new FileNotFoundException("Asset absolute file: " + fileName); } - + /** * Retrieve a parser for a compiled XML file. - * + * * @param fileName The name of the file to retrieve. */ public final XmlResourceParser openXmlResourceParser(String fileName) throws IOException { return openXmlResourceParser(0, fileName); } - + /** * Retrieve a parser for a compiled XML file. - * + * * @param cookie Identifier of the package to be opened. * @param fileName The name of the file to retrieve. */ @@ -521,7 +521,7 @@ public final class AssetManager implements AutoCloseable { * {@hide} * Retrieve a non-asset as a compiled XML file. Not for use by * applications. - * + * * @param fileName The name of the file to retrieve. */ /*package*/ final XmlBlock openXmlBlockAsset(String fileName) @@ -533,7 +533,7 @@ public final class AssetManager implements AutoCloseable { * {@hide} * Retrieve a non-asset as a compiled XML file. Not for use by * applications. - * + * * @param cookie Identifier of the package to be opened. * @param fileName Name of the asset to retrieve. */ @@ -588,12 +588,18 @@ public final class AssetManager implements AutoCloseable { } } } - destroy(); + + synchronized (this) { + if (mObject != 0) { + destroy(); + mObject = 0; + } + } } finally { super.finalize(); } } - + public final class AssetInputStream extends InputStream { /** * @hide @@ -796,7 +802,7 @@ public final class AssetManager implements AutoCloseable { /*package*/ native final String getResourcePackageName(int resid); /*package*/ native final String getResourceTypeName(int resid); /*package*/ native final String getResourceEntryName(int resid); - + private native final long openAsset(String fileName, int accessMode); private final native ParcelFileDescriptor openAssetFd(String fileName, long[] outOffsets) throws IOException; @@ -856,17 +862,17 @@ public final class AssetManager implements AutoCloseable { * {@hide} */ public native static final int getGlobalAssetCount(); - + /** * {@hide} */ public native static final String getAssetAllocations(); - + /** * {@hide} */ public native static final int getGlobalAssetManagerCount(); - + private native final long newTheme(); private native final void deleteTheme(long theme); /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force); @@ -899,7 +905,7 @@ public final class AssetManager implements AutoCloseable { } mNumRefs++; } - + private final void decRefsLocked(long id) { if (DEBUG_REFS && mRefStacks != null) { mRefStacks.remove(id); @@ -907,8 +913,9 @@ public final class AssetManager implements AutoCloseable { mNumRefs--; //System.out.println("Dec streams: mNumRefs=" + mNumRefs // + " mReleased=" + mReleased); - if (mNumRefs == 0) { + if (mNumRefs == 0 && mObject != 0) { destroy(); + mObject = 0; } } } -- GitLab From f00d7fb3bd217bf236adb936febdb44e59250c78 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 22 Jul 2019 14:25:14 -0700 Subject: [PATCH 024/143] Adding atoms for metrics logging Define the atom protos for UpdateEngineUpdateAttemptReported UpdateEngineSuccessfulUpdateReported The fields for both atoms are copied from the already reported Tron counters, except for the source fingerprint. By defining our own proto, we can have a better insight about each update events. It also makes the query easier without the server side work to correlate each counters. Sample output from testdrive shows: data { elapsed_timestamp_nanos: 64932607816092 atom { update_engine_update_attempt_reported { attempt_number: 1 payload_type: FULL duration_boottime_in_minutes: 0 duration_monotonic_in_minutes: 0 payload_size_mib: 510 attempt_result: METADATA_VERIFICATION_FAILED error_code: DOWNLOAD_METADATA_SIGNATURE_MISMATCH fingerprint: "google/walleye/walleye:R/MASTER/eng.xuncha.20190731.151212:userdebug/dev-keys" } } } Bug: 138253582 Bug: 137682371 Test: run statsd_testdrive and check events Merged-In: Ic502acc8831fe4da0b32a826171d10e9c0f9876d (cherry picked from commit 167c3db93401adccc703815a9d71ef057b17e780) Change-Id: Ifa57f23135b4cd63888df2b8f25650be133bb1de --- cmds/statsd/src/atoms.proto | 70 ++++++++++++++++ .../stats/otaupdate/updateengine_enums.proto | 82 +++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 core/proto/android/stats/otaupdate/updateengine_enums.proto diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 1ac37eadae0d..bf89759385cb 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -50,6 +50,7 @@ import "frameworks/base/core/proto/android/stats/intelligence/enums.proto"; import "frameworks/base/core/proto/android/stats/launcher/launcher.proto"; import "frameworks/base/core/proto/android/stats/location/location_enums.proto"; import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto"; +import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto"; import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto"; import "frameworks/base/core/proto/android/stats/style/style_enums.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; @@ -322,6 +323,8 @@ message Atom { ExclusionRectStateChanged exclusion_rect_state_changed = 223; BackGesture back_gesture_reported_reported = 224; + UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225; + UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226; AppCompatibilityChangeReported app_compatibility_change_reported = 228 [(allow_from_any_uid) = true]; PerfettoUploaded perfetto_uploaded = @@ -6983,3 +6986,70 @@ message VmsClientStats { optional int64 dropped_bytes = 9; optional int64 dropped_packets = 10; } + +/** + * Information about an OTA update attempt by update_engine. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineUpdateAttemptReported { + // The number of attempts for the update engine to apply a given payload. + optional int32 attempt_number = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_BOOTTIME; and + // it's increased when the system is sleeping. + optional int32 duration_boottime_in_minutes = 3; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_MONOTONIC_RAW; + // and it's not increased when the system is sleeping. + optional int32 duration_monotonic_in_minutes = 4; + + // The size of the payload in MiBs. + optional int32 payload_size_mib = 5; + + // The attempt result reported by the update engine for an OTA update. + optional android.stats.otaupdate.AttemptResult attempt_result = 6; + + // The error code reported by the update engine after an OTA update attempt + // on A/B devices. + optional android.stats.otaupdate.ErrorCode error_code = 7; + + // The build fingerprint of the source system. The value is read from a + // system property when the device takes the update. e.g. + // Android/aosp_sailfish/sailfish:10/QP1A.190425.004/5507117:userdebug/test-keys + optional string source_fingerprint = 8; +} + +/** + * Information about all the attempts the device make before finishing the + * successful update. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineSuccessfulUpdateReported { + // The number of attempts for the update engine to apply the payload for a + // successful update. + optional int32 attempt_count = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + optional int32 payload_size_mib = 3; + + // The total number of bytes downloaded by update_engine since the last + // successful update. + optional int32 total_bytes_downloaded_mib = 4; + + // The ratio in percentage of the over-downloaded bytes compared to the + // total bytes needed to successfully install the update. e.g. 200 if we + // download 200MiB in total for a 100MiB package. + optional int32 download_overhead_percentage = 5; + + // The total time in minutes for the update engine to apply the payload for a + // successful update. + optional int32 total_duration_minutes = 6; + + // The number of reboot of the device during a successful update. + optional int32 reboot_count = 7; +} diff --git a/core/proto/android/stats/otaupdate/updateengine_enums.proto b/core/proto/android/stats/otaupdate/updateengine_enums.proto new file mode 100644 index 000000000000..a6e9919ba606 --- /dev/null +++ b/core/proto/android/stats/otaupdate/updateengine_enums.proto @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package android.stats.otaupdate; + +// The payload type of an OTA update attempt on A/B devices. +enum PayloadType { + FULL = 10000; + DELTA = 10001; +} + +// The attempt result reported by the update engine for an OTA update. +enum AttemptResult { + UPDATE_SUCCEEDED = 10000; + INTERNAL_ERROR = 10001; + PAYLOAD_DOWNLOAD_ERROR = 10002; + METADATA_MALFORMED = 10003; + OPERATION_MALFORMED = 10004; + OPERATION_EXECUTION_ERROR = 10005; + METADATA_VERIFICATION_FAILED = 10006; + PAYLOAD_VERIFICATION_FAILED = 10007; + VERIFICATION_FAILED = 10008; + POSTINSTALL_FAILED = 10009; + ABNORMAL_TERMINATION = 10010; + UPDATE_CANCELED = 10011; + UPDATE_SUCCEEDED_NOT_ACTIVE = 10012; +} + +// The error code reported by the update engine after an OTA update attempt +// on A/B devices. More details in system/update_engine/common/error_code.h +enum ErrorCode { + SUCCESS = 10000; + ERROR = 10001; + FILESYSTEM_COPIER_ERROR = 10004; + POST_INSTALL_RUNNER_ERROR = 10005; + PAYLOAD_MISMATCHED_TYPE_ERROR = 10006; + INSTALL_DEVICE_OPEN_ERROR = 10007; + KERNEL_DEVICE_OPEN_ERROR = 10008; + DOWNLOAD_TRANSFER_ERROR = 10009; + PAYLOAD_HASH_MISMATCH_ERROR = 10010; + PAYLOAD_SIZE_MISMATCH_ERROR = 10011; + DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 10012; + DOWNLOAD_NEW_PARTITION_INFO_ERROR = 10013; + DOWNLOAD_WRITE_ERROR = 10014; + NEW_ROOTFS_VERIFICATION_ERROR = 10015; + SIGNED_DELTA_PAYLOAD_EXPECTED_ERROR = 10017; + DOWNLOAD_PAYLOAD_PUB_KEY_VERIFICATION_ERROR = 10018; + DOWNLOAD_STATE_INITIALIZATION_ERROR = 10020; + DOWNLOAD_INVALID_METADATA_MAGIC_STRING = 10021; + DOWNLOAD_SIGNATURE_MISSING_IN_MANIFEST = 10022; + DOWNLOAD_MANIFEST_PARSE_ERROR = 10023; + DOWNLOAD_METADATA_SIGNATURE_ERROR = 10024; + DOWNLOAD_METADATA_SIGNATURE_VERIFICATION_ERROR = 10025; + DOWNLOAD_METADATA_SIGNATURE_MISMATCH = 10026; + DOWNLOAD_OPERATION_HASH_VERIFICATION_ERROR = 10027; + DOWNLOAD_OPERATION_EXECUTION_ERROR = 10028; + DOWNLOAD_OPERATION_HASH_MISMATCH = 10029; + DOWNLOAD_INVALID_METADATA_SIZE = 10032; + DOWNLOAD_INVALID_METADATA_SIGNATURE = 10033; + DOWNLOAD_OPERATION_HASH_MISSING_ERROR = 10038; + DOWNLOAD_METADATA_SIGNATURE_MISSING_ERROR = 10039; + UNSUPPORTED_MAJOR_PAYLOAD_VERSION = 10044; + UNSUPPORTED_MINOR_PAYLOAD_VERSION = 10045; + FILESYSTEM_VERIFIER_ERROR = 10047; + USER_CANCELED = 10048; + PAYLOAD_TIMESTAMP_ERROR = 10051; + UPDATED_BUT_NOT_ACTIVE = 10052; +} -- GitLab From 77e6f5ff3ef505d5c659e074413135314e8ceed5 Mon Sep 17 00:00:00 2001 From: Joanne Chung Date: Mon, 19 Aug 2019 14:48:05 +0800 Subject: [PATCH 025/143] Change permissionLevel of ACCESS_SHORTCUTS and UNLIMITED_SHORTCUTS_API_CALLS ACCESS_SHORTCUTS and UNLIMITED_SHORTCUTS_API_CALLS should be granted to an app predictor rather than a text classifier. Bug: 139523153 Test: atest CtsPermission2TestCases Change-Id: I12360b5d5ba3c75bb2dfffd86bd6069b75fbdb53 (cherry picked from commit b6a7851271184b2177a2c5f70163d2691ca26a06) --- core/res/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index aa5141d98cc3..5778d02737b9 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4467,12 +4467,12 @@ + android:protectionLevel="signature|appPredictor" /> + android:protectionLevel="signature|appPredictor" /> -- GitLab From 0a8a1e9d40a3cdff06150c43c623fa4c415226b6 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Thu, 4 Jul 2019 16:10:08 +0800 Subject: [PATCH 026/143] Fix potential double destroy of AssetManager Assume there is a XmlBlock [X] created by a AssetManager [A] ([A] will have mNumRefs = 2). After [A].close is called (mNumRefs = 1) and then both [X] and [A] are going to be GCed, if [A].finalize is called first (nativeDestroy), the later [X].finalize will invoke [A].xmlBlockGone that triggers the second nativeDestroy of [A] and leads to crash. By clearing the mObject in AssetManager.finalize, the decRefsLocked from other paths won't call nativeDestroy again. Bug: 136721562 Bug: 144028297 Test: atest AssetManagerTest Test: Build and install CorePerfTests adb shell am instrument -w -r --no-hidden-api-checks -e class \ android.app.ResourcesPerfTest#getLayoutAndTravese,android.graphics.perftests.RenderNodePerfTest \ com.android.perftests.core/androidx.test.runner.AndroidJUnitRunner Change-Id: Ia938502d2443f5a6de6a3cabdb7ce1d41d3ff6d1 Merged-In: Ia938502d2443f5a6de6a3cabdb7ce1d41d3ff6d1 --- core/java/android/content/res/AssetManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 289534273d13..4ddaa9b4cdf8 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -1050,8 +1050,11 @@ public final class AssetManager implements AutoCloseable { } } - if (mObject != 0) { - nativeDestroy(mObject); + synchronized (this) { + if (mObject != 0) { + nativeDestroy(mObject); + mObject = 0; + } } } -- GitLab From 6f99815dfd949c6208318e4c849de30b6c959dc9 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 18 Jan 2020 10:26:52 -0800 Subject: [PATCH 027/143] Import translations. DO NOT MERGE Change-Id: I38cd73f81ea8fd45fa632a6d3f210cbdaed3361b Auto-generated-cl: translation import --- core/res/res/values-ar/strings.xml | 8 ++++---- core/res/res/values-da/strings.xml | 2 +- core/res/res/values-gu/strings.xml | 4 ++-- core/res/res/values-hy/strings.xml | 2 +- core/res/res/values-ky/strings.xml | 8 ++++---- core/res/res/values-mk/strings.xml | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 5b613d7677fe..954ffd3b50d5 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -334,7 +334,7 @@ "التحكم في تكبير الشاشة" "يمكنك التحكّم في مستوى تكبير/تصغير الشاشة وتحديد الموضع." "تنفيذ إيماءات" - "يمكن النقر والتمرير بسرعة والتصغير وتنفيذ إيماءات أخرى." + "يمكن النقر والتمرير بسرعة والتصغير أو التكبير بإصبعين وتنفيذ إيماءات أخرى." "إيماءات بصمات الإصبع" "يمكن أن تلتقط الإيماءات التي تم تنفيذها على جهاز استشعار بصمات الإصبع في الجهاز." "إيقاف شريط الحالة أو تعديله" @@ -680,7 +680,7 @@ "التحكّم في طريقة ووقت قفل الشاشة" "محو جميع البيانات" "يمكنك محو بيانات الجهاز اللوحي بدون تحذير، وذلك عبر إجراء إعادة الضبط بحسب بيانات المصنع." - "محو بيانات التلفزيون بدون تحذير من خلال إجراء إعادة ضبط البيانات على إعدادات المصنع." + "محو بيانات التلفزيون بدون تحذير من خلال إجراء إعادة ضبط البيانات على الإعدادات الأصلية." "محو بيانات الهاتف بدون تحذير، وذلك من خلال إعادة ضبط البيانات على الإعدادات الأصلية" "محو بيانات المستخدم" "لمحو بيانات هذا المستخدم على هذا الجهاز اللوحي بدون تحذير." @@ -1455,7 +1455,7 @@ "‏انقر لإيقاف تصحيح أخطاء الجهاز عبر USB." "‏اختيار إيقاف تصحيح أخطاء USB." "تم تفعيل وضع \"مفعّل الاختبار\"" - "يمكنك إجراء إعادة ضبط على إعدادات المصنع لإيقاف وضع \"مفعِّل اختبار\"." + "يمكنك إجراء إعادة ضبط على الإعدادات الأصلية لإيقاف وضع \"مفعِّل اختبار\"." "‏السوائل والشوائب في منفذ USB" "‏تمّ إيقاف منفذ USB تلقائيًا. انقُر لمعرفة المزيد من المعلومات." "‏مسموح باستخدام منفذ USB" @@ -1529,7 +1529,7 @@ "للسماح لتطبيق ما بطلب حذف الحِزم." "طلب تجاهل تحسينات البطارية" "للسماح للتطبيق بطلب الإذن لتجاهل تحسينات البطارية في هذا التطبيق." - "اضغط مرتين للتحكم في التكبير/التصغير" + "اضغط مرتين للتحكم في التكبير أو التصغير" "تعذرت إضافة أداة." "تنفيذ" "بحث" diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 1f78ba3bc3c7..f4e4f7377cbf 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -368,7 +368,7 @@ "Denne app kan vises oven på andre apps" "Denne app kan vises oven på andre apps eller andre dele af skærmen. Dette kan forstyrre den normale brug af appen og ændre visningen af andre apps." "kør i baggrunden" - "Denne app kan køre i baggrunden. Dette kan aflade batteriet hurtigere." + "Denne app kan køre i baggrunden. Dette kan dræne batteriet hurtigere." "brug data i baggrunden" "Denne app kan bruge data i baggrunden. Dette kan øge dataforbruget." "sørge for, at appen altid kører" diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index fe6e07610a8e..853d27f2c84b 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -246,7 +246,7 @@ "એરપ્લેન મોડ" "એરપ્લેન મોડ ચાલુ છે." "એરપ્લેન મોડ બંધ છે." - "સેટિંગ્સ" + "સેટિંગ" "સહાય" "વૉઇસ સહાય" "લૉકડાઉન" @@ -1613,7 +1613,7 @@ "ઉપકરણ સાથે કનેક્ટ કરો" "ઉપકરણ પર સ્ક્રીન કાસ્ટ કરો" "ઉપકરણો માટે શોધી રહ્યું છે…" - "સેટિંગ્સ" + "સેટિંગ" "ડિસ્કનેક્ટ કરો" "સ્કેન કરી રહ્યું છે..." "કનેક્ટ કરી રહ્યું છે..." diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index c94afd88425a..401e27428224 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1923,7 +1923,7 @@ "Հպեք՝ ֆայլերը տեսնելու համար" "Ամրացնել" "Ապամրացնել" - "Հավելվածի տվյալներ" + "Հավելվածի մասին" "−%1$s" "Ցուցադրական օգտատերը գործարկվում է…" "Սարաքը վերակայվում է…" diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index c2ab5705905f..161e4e6cb8f0 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1452,7 +1452,7 @@ "Аткаруу" "%s менен\nномерди терүү" "%s менен\nбайланыш түзүү" - "Төмөнкү бир же бир нече колдонмо каттоо эсебиңизге азыр жана кийинчерээк кирүү мүмкүнчүлүгүн сурап жатат." + "Төмөнкү бир же бир нече колдонмо аккаунтуңузга азыр жана кийинчерээк кирүү мүмкүнчүлүгүн сурап жатат." "Бул өтүнүчкө уруксат бересизби?" "Жетки талабы" "Уруксат берүү" @@ -1663,9 +1663,9 @@ "Сиз планшетиңизди %d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Планшет баштапкы абалына кайтарылат." "Сыналгыңыздын кулпусун ачууда %d_0 жолу туура эмес аракет кылдыңыз. Сыналгыңыз баштапкы абалга келтирилет." "Сиз телефонуңузду %d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Телефон баштапкы абалына кайтарылат." - "Графикалык ачкычты %1$d жолу туура эмес көрсөттүңүз. %2$d жолу туура эмес көрсөтүлгөндөн кийин, планшетиңиздин кулпусун ачуу үчүн Google каттоо эсебиңизге кирүүгө туура келет.\n\n%3$d секундадан кийин кайталап көрсөңүз болот." - "Кулпуну ачуу үлгүсүн %1$d жолу туура эмес тарттыңыз. Дагы %2$d жолу туура эмес тартсаңыз, сыналгыңыздын кулпусун электрондук каттоо эсебиңизге кирип ачууга туура келет.\n\n %3$d секундадан кийин дагы аракет кылып көрүңүз." - "Графикалык ачкычты %1$d жолу туура эмес көрсөттүңүз. %2$d жолу туура эмес көрсөтүлгөндөн кийин, телефондун кулпусун ачуу үчүн Google каттоо эсебиңизге кирүүгө туура келет.\n\n%3$d секундадан кийин кайталап көрсөңүз болот." + "Графикалык ачкычты %1$d жолу туура эмес көрсөттүңүз. %2$d жолу туура эмес көрсөтүлгөндөн кийин, планшетиңиздин кулпусун ачуу үчүн Google аккаунтуңузга кирүүгө туура келет.\n\n%3$d секундадан кийин кайталап көрсөңүз болот." + "Кулпуну ачуу үлгүсүн %1$d жолу туура эмес тарттыңыз. Дагы %2$d жолу туура эмес тартсаңыз, сыналгыңыздын кулпусун электрондук аккаунтуңузга кирип ачууга туура келет.\n\n %3$d секундадан кийин дагы аракет кылып көрүңүз." + "Графикалык ачкычты %1$d жолу туура эмес көрсөттүңүз. %2$d жолу туура эмес көрсөтүлгөндөн кийин, телефондун кулпусун ачуу үчүн Google аккаунтуңузга кирүүгө туура келет.\n\n%3$d секундадан кийин кайталап көрсөңүз болот." " — " "Алып салуу" "Сунушталган деңгээлден да катуулатып уккуңуз келеби?\n\nМузыканы узакка чейин катуу уксаңыз, угууңуз начарлап кетиши мүмкүн." diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index fb578b91159a..af73a792ddfd 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1515,7 +1515,7 @@ "Избриши ги ставките" "Врати ги избришаните" "Не прави ништо засега" - "Избери сметка" + "Изберете сметка" "Додај сметка" "Додај сметка" "Зголеми" -- GitLab From 5b94476ce6bbf93f5ac4216bf70816f19a57abad Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sun, 19 Jan 2020 10:32:43 -0800 Subject: [PATCH 028/143] Import translations. DO NOT MERGE Change-Id: I1df70b7205ca4090d6a9978050049d378fff7cbc Auto-generated-cl: translation import --- packages/SystemUI/res/values-ar/strings.xml | 2 +- packages/SystemUI/res/values-gu/strings.xml | 10 +++++----- packages/SystemUI/res/values-kn/strings.xml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 5998c56c33b0..9548551d6ba6 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -130,7 +130,7 @@ "جارٍ البحث عن وجهك…" "رمز الوجه" "زر تكبير/تصغير للتوافق." - "استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر" + "استخدام التكبير أو التصغير لتحويل شاشة صغيرة إلى شاشة أكبر" "تم توصيل البلوتوث." "تم فصل البلوتوث." "ليست هناك بطارية." diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 921c81d72a29..d4fdfb19e3a3 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -37,7 +37,7 @@ "બૅટરી સેવર વિશે" "ચાલુ કરો" "બૅટરી સેવર ચાલુ કરો" - "સેટિંગ્સ" + "સેટિંગ" "વાઇ-ફાઇ" "ઑટો રોટેટ સ્ક્રીન" "મ્યૂટ કરો" @@ -217,7 +217,7 @@ "નોટિફિકેશન શેડ." "ઝડપી સેટિંગ્સ." "લૉક સ્ક્રીન." - "સેટિંગ્સ" + "સેટિંગ" "ઝલક." "કાર્ય લૉક સ્ક્રીન" "બંધ કરો" @@ -288,7 +288,7 @@ "%1$s: %2$s" "સૂચનાઓની સેટિંગ્સ" - "%s સેટિંગ્સ" + "%s સેટિંગ" "સ્ક્રીન આપમેળે ફરશે." "સ્ક્રીન લેન્ડસ્કેપ ઓરિએન્ટેશનમાં લૉક કરેલ છે." "સ્ક્રીન પોટ્રેટ ઓરિએન્ટેશનમાં લૉક કરેલ છે." @@ -326,7 +326,7 @@ "મીડિયા ઉપકરણ" "RSSI" "ફક્ત કટોકટીના કૉલ્સ" - "સેટિંગ્સ" + "સેટિંગ" "સમય" "હું" "વપરાશકર્તા" @@ -876,7 +876,7 @@ "સામાન્ય સંદેશા" "સ્ટોરેજ" "હિન્ટ" - "ઝટપટ ઍપ્લિકેશનો" + "ઝટપટ ઍપ્લિકેશન" "%1$s ચાલી રહી છે" "ઍપ ઇન્સ્ટૉલ કર્યા વિના ખુલી જાય છે." "ઍપ ઇન્સ્ટૉલ કર્યા વિના ખુલી જાય છે. વધુ જાણવા માટે ટૅપ કરો." diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 92e373142d6d..712dca2748c5 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -876,7 +876,7 @@ "ಸಾಮಾನ್ಯ ಸಂದೇಶಗಳು" "ಸಂಗ್ರಹಣೆ" "ಸುಳಿವುಗಳು" - "ತತ್‌ಕ್ಷಣ ಆಪ್‌ಗಳು" + "ಇನ್‌ಸ್ಟಂಟ್ ಆ್ಯಪ್‌ಗಳು" "%1$s ರನ್ ಆಗುತ್ತಿದೆ" "ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡದೆ ಆ್ಯಪ್‌ ತೆರೆಯಲಾಗಿದೆ." "ಇನ್‌ಸ್ಟಾಲ್‌ ಮಾಡದೆ ಆ್ಯಪ್‌ ತೆರೆಯಲಾಗಿದೆ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ." -- GitLab From 67c89f3e5fa3f3abd81765e00daa3ddaf7ab14b6 Mon Sep 17 00:00:00 2001 From: Mohammad Samiul Islam Date: Tue, 14 Jan 2020 18:33:39 +0000 Subject: [PATCH 029/143] Handle ParcelableException instead of crashing system server Unhandled exception is causing system server to crash. Bug: 146790672 Test: builds successfully Change-Id: Ibfe53ee0309dcec6fd3b24f8b67fcb78f5ce7fd5 Merged-In: Ibfe53ee0309dcec6fd3b24f8b67fcb78f5ce7fd5 --- .../com/android/server/pm/StagingManager.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 9c87c748f867..9913c9846a17 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -40,6 +40,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.ParcelableException; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; @@ -403,29 +404,28 @@ public class StagingManager { } else { params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; } - int apkSessionId = mPi.createSession( - params, originalSession.getInstallerPackageName(), - 0 /* UserHandle.SYSTEM */); - PackageInstallerSession apkSession = mPi.getSession(apkSessionId); - try { + int apkSessionId = mPi.createSession( + params, originalSession.getInstallerPackageName(), + 0 /* UserHandle.SYSTEM */); + PackageInstallerSession apkSession = mPi.getSession(apkSessionId); apkSession.open(); for (String apkFilePath : apkFilePaths) { File apkFile = new File(apkFilePath); ParcelFileDescriptor pfd = ParcelFileDescriptor.open(apkFile, ParcelFileDescriptor.MODE_READ_ONLY); - long sizeBytes = pfd.getStatSize(); + long sizeBytes = (pfd == null) ? -1 : pfd.getStatSize(); if (sizeBytes < 0) { Slog.e(TAG, "Unable to get size of: " + apkFilePath); return null; } apkSession.write(apkFile.getName(), 0, sizeBytes, pfd); } - } catch (IOException e) { + return apkSession; + } catch (IOException | ParcelableException e) { Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e); return null; } - return apkSession; } private boolean commitApkSession(@NonNull PackageInstallerSession apkSession, -- GitLab From c8a7c2bd74b00bfda55788d63303ef693d186e36 Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Tue, 21 Jan 2020 11:25:10 -0500 Subject: [PATCH 030/143] Do not destroy CustomTile when in QSCustomizer Before this CL, TileQueryHelper would create CustomTile when creating tiles for current tiles. This caused them to be destroyed after taking the information and being removed from the maps in TileServices. In this CL, current CustomTile are fixed to only being created by addPackageTiles which knows what to do. Fixes: 148002667 Fixes: 127508346 Test: manual Test: atest TileQueryHelperTest Change-Id: I2c4d3ce6c31449f20670982dad334019cc25469c Merged-In: I2c4d3ce6c31449f20670982dad334019cc25469c (cherry picked from commit 198b0b6ef1e15ca040a67c48f232cdd6efa6c081) --- .../systemui/qs/customize/TileQueryHelper.java | 4 +++- .../qs/customize/TileQueryHelperTest.java | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index 70062492c162..7a8f497041c1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -103,7 +103,9 @@ public class TileQueryHelper { final ArrayList tilesToAdd = new ArrayList<>(); for (String spec : possibleTiles) { - // Only add current and stock tiles that can be created from QSFactoryImpl + // Only add current and stock tiles that can be created from QSFactoryImpl. + // Do not include CustomTile. Those will be created by `addPackageTiles`. + if (spec.startsWith(CustomTile.PREFIX)) continue; final QSTile tile = host.createTile(spec); if (tile == null) { continue; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index 9e226f693622..2fed441c861e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -79,12 +80,14 @@ public class TileQueryHelperTest extends SysuiTestCase { private static final Set FACTORY_TILES = new ArraySet<>(); private static final String TEST_PKG = "test_pkg"; private static final String TEST_CLS = "test_cls"; + private static final String CUSTOM_TILE = "custom(" + TEST_PKG + "/" + TEST_CLS + ")"; static { FACTORY_TILES.addAll(Arrays.asList( new String[]{"wifi", "bt", "cell", "dnd", "inversion", "airplane", "work", "rotation", "flashlight", "location", "cast", "hotspot", "user", "battery", "saver", "night", "nfc"})); + FACTORY_TILES.add(CUSTOM_TILE); } @Mock @@ -227,6 +230,18 @@ public class TileQueryHelperTest extends SysuiTestCase { assertFalse(specs.contains("other")); } + @Test + public void testCustomTileNotCreated() { + Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, + CUSTOM_TILE); + mTileQueryHelper.queryTiles(mQSTileHost); + + mBGLooper.processAllMessages(); + waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + + verify(mQSTileHost, never()).createTile(CUSTOM_TILE); + } + @Test public void testThirdPartyTilesInactive() { ResolveInfo resolveInfo = new ResolveInfo(); -- GitLab From c718e54c27103ba690d99266b1d2f63fbe7f163d Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Wed, 8 Jan 2020 17:42:48 -0800 Subject: [PATCH 031/143] Ensure adb key store is instantiated before revoking grants If adb is not enabled on a device then the adb key store is not instantiated when the AdbDebuggingManager's handler is started as in most cases it will not be needed. However if the user attempts to revoke any previous adb grants when a device is booted with adb disabled it will result in a NPE. This commit ensures the key store is instantiated before attempting to revoke authorizations. Test: atest AdbDebuggingManagerTest Test: Manually invoked 'Revoke USB debugging authorizations' after a boot with adb disabled. Fixes: 145790817 Change-Id: Id00e531c18412be009a211eec80a72867659608f Merged-In: Id00e531c18412be009a211eec80a72867659608f --- .../server/adb/AdbDebuggingManager.java | 5 ++++ .../server/adb/AdbDebuggingManagerTest.java | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index 4b48ef917744..143474bd5c94 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -413,6 +413,11 @@ public class AdbDebuggingManager { case MESSAGE_ADB_CLEAR: { Slog.d(TAG, "Received a request to clear the adb authorizations"); mConnectedKeys.clear(); + // If the key store has not yet been instantiated then do so now; this avoids + // the unnecessary creation of the key store when adb is not enabled. + if (mAdbKeyStore == null) { + mAdbKeyStore = new AdbKeyStore(); + } mAdbKeyStore.deleteKeyStore(); cancelJobToUpdateAdbKeyStore(); break; diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java index d4182f3d31e2..5a1ad8655ab0 100644 --- a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java @@ -672,6 +672,30 @@ public final class AdbDebuggingManagerTest { connectionTime2, mKeyStore.getLastConnectionTime(TEST_KEY_2)); } + @Test + public void testClearAuthorizationsBeforeAdbEnabled() throws Exception { + // The adb key store is not instantiated until adb is enabled; however if the user attempts + // to clear the adb authorizations when adb is disabled after a boot a NullPointerException + // was thrown as deleteKeyStore is invoked against the key store. This test ensures the + // key store can be successfully cleared when adb is disabled. + mHandler = mManager.new AdbDebuggingHandler(FgThread.get().getLooper()); + + clearKeyStore(); + } + + @Test + public void testClearAuthorizationsDeletesKeyFiles() throws Exception { + mAdbKeyFile.createNewFile(); + mAdbKeyXmlFile.createNewFile(); + + clearKeyStore(); + + assertFalse("The adb key file should have been deleted after revocation of the grants", + mAdbKeyFile.exists()); + assertFalse("The adb xml key file should have been deleted after revocation of the grants", + mAdbKeyXmlFile.exists()); + } + /** * Runs an adb test with the provided configuration. * -- GitLab From 4cc695ce4456b02ccba626f95184804a2d35c45c Mon Sep 17 00:00:00 2001 From: Zhen Zhang Date: Mon, 4 Nov 2019 17:03:09 -0800 Subject: [PATCH 032/143] Update mOnDissmissRunnable when Notification gets updated. mOnDissmissRunnable holds reference to StatusBarNotification instance. We should update it when notification gets updated. Bug: 141699084 Test: atest NotifCollectionTest, NotificationDataTest, NotificationEntryManagerTest Change-Id: Iaa4306eedeb144dba480c551808dd431e096314c Merged-In: Iaa4306eedeb144dba480c551808dd431e096314c (cherry picked from commit 52d82f59eab69c944e5e2cdb5f06e91960b76f01) --- .../notification/collection/NotificationRowBinderImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java index 247c31fc80a3..240d567b78c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java @@ -137,6 +137,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { entry.updateIcons(mContext, sbn); entry.reset(); updateNotification(entry, pmUser, sbn, entry.getRow()); + entry.getRow().setOnDismissRunnable(onDismissRunnable); } else { entry.createIcons(mContext, sbn); new RowInflaterTask().inflate(mContext, parent, entry, -- GitLab From a9feb4602fb611522c4ad4d9b917b0bec1ef15d4 Mon Sep 17 00:00:00 2001 From: Mayank Garg Date: Fri, 10 Jan 2020 00:47:08 -0800 Subject: [PATCH 033/143] Adding option in global setting to control the display message during user switch Bug: 145915635 Bug: 145132885 Test: adb shell settings put global android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE true Merged-In: I70c72d7d74c72a78d919ae34906b6f7b96466ad1 Change-Id: I70c72d7d74c72a78d919ae34906b6f7b96466ad1 (cherry picked from commit e12de0beb45d07aaaaec923e9f009130d5053d2f) --- .../server/am/CarUserSwitchingDialog.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index ebfc2a011e88..60754fbc5cd3 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -33,6 +33,7 @@ import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.UserManager; +import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; @@ -81,8 +82,19 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { .setImageDrawable(drawable); } - ((TextView) view.findViewById(R.id.user_loading)) - .setText(res.getString(R.string.car_loading_profile)); + TextView msgView = view.findViewById(R.id.user_loading); + + // TODO(b/145132885): use constant from CarSettings + boolean showInfo = "true".equals(Settings.Global.getString( + getContext().getContentResolver(), + "android.car.ENABLE_USER_SWITCH_DEVELOPER_MESSAGE")); + + if (showInfo) { + msgView.setText(res.getString(R.string.car_loading_profile) + " user\n(from " + + mOldUser.id + " to " + mNewUser.id + ")"); + } else { + msgView.setText(res.getString(R.string.car_loading_profile)); + } setView(view); } -- GitLab From eb4f716bf3a0ee3ac8015cde48305aeb82724039 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Thu, 7 Nov 2019 11:37:18 -0500 Subject: [PATCH 034/143] Only suspend package from system or shell Test: manual Bug: 148059175 Change-Id: I50ee768e792266ad2091f1913168e89d5d1463ed Merged-In: I50ee768e792266ad2091f1913168e89d5d1463ed (cherry picked from commit 1c943a2670c1ff499669b42ef72dcd9f07db08c3) (cherry picked from commit adc39de3a148a2058d63bd7a1b8b71ee0a3524ac) --- .../android/server/notification/NotificationManagerService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b1ea47c6f3b0..06b7c4d45c71 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -7101,6 +7101,7 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) { + checkCallerIsSystemOrShell(); // only use for testing: mimic receive broadcast that package is (un)suspended // but does not actually (un)suspend the package final Bundle extras = new Bundle(); -- GitLab From 5c31a5c18db13ecb4018b69ea1af6568dd36251e Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Fri, 24 Jan 2020 16:26:38 -0800 Subject: [PATCH 035/143] DO NOT MERGE Only set the LAYOUT flags if the window is fullscreen This addresses an issue where toasts will be hidden due to the setting of the LAYOUT_HIDE_NAVIGATION flag. Bug: 148180738 Test: manual (adb shell settings put global policy_control "immersive.navigation=*" then try to show a toast with gravity top) Change-Id: Ic47edc5423c4daf373fc3a8bfc30af15cadd6d90 --- .../core/java/com/android/server/wm/PolicyControl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java index 4c8ce9ebb72c..87c34908d043 100644 --- a/services/core/java/com/android/server/wm/PolicyControl.java +++ b/services/core/java/com/android/server/wm/PolicyControl.java @@ -67,15 +67,19 @@ class PolicyControl { : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility); if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) { vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + | View.SYSTEM_UI_FLAG_FULLSCREEN; + if (attrs.isFullscreen()) { + vis |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + } vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.STATUS_BAR_TRANSLUCENT); } if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) { vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + if (attrs.isFullscreen()) { + vis |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + } vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.NAVIGATION_BAR_TRANSLUCENT); } -- GitLab From a3acf85a3badf1caacd09d83d0047c3a32358686 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Fri, 8 Nov 2019 12:16:28 -0800 Subject: [PATCH 036/143] GraphicsEnv: refactor to unify the debuggable logic By default, PR_SET_DUMPABLE is 0 for zygote spawned apps, except in the following circumstances: 1. ro.debuggable=1 (global debuggable enabled, i.e., userdebug or eng builds). 2. android:debuggable="true" in the manifest for an individual application. 3. An app which explicitly calls prctl(PR_SET_DUMPABLE, 1). 4. GraphicsEnv calls prctl(PR_SET_DUMPABLE, 1) in the presence of in the application manifest. So checking both ro.debuggable=1 and PR_GET_DUMPABLE is redundant. Bug: b/144186877, b/148566223 Test: CtsAngleIntegrationHostTestCases Test: CtsRootlessGpuDebugHostTest Change-Id: Ica49254df2c7c090808411935cdeb8efd4e3cb51 Merged-In: Ica49254df2c7c090808411935cdeb8efd4e3cb51 (cherry picked from commit 097a3062b93045d9980d83f903bd4b781505522b) --- core/java/android/os/GraphicsEnvironment.java | 25 +++++-------------- core/jni/android_os_GraphicsEnvironment.cpp | 6 ++--- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index 7a70e93b69d5..31cdf42e3a06 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -172,13 +172,6 @@ public class GraphicsEnvironment { return 0; } - /** - * Check whether application is debuggable - */ - private static boolean isDebuggable(Context context) { - return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0; - } - /** * Store the layer paths available to the loader. */ @@ -233,7 +226,7 @@ public class GraphicsEnvironment { // 2. ENABLE_GPU_DEBUG_LAYERS is true // 3. Package name is equal to GPU_DEBUG_APP - if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) { + if (isDebuggable()) { final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0); @@ -414,9 +407,7 @@ public class GraphicsEnvironment { * Check for ANGLE debug package, but only for apps that can load them (dumpable) */ private String getAngleDebugPackage(Context context, Bundle coreSettings) { - final boolean appIsDebuggable = isDebuggable(context); - final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1; - if (appIsDebuggable || deviceIsDebuggable) { + if (isDebuggable()) { String debugPackage; if (coreSettings != null) { @@ -451,12 +442,8 @@ public class GraphicsEnvironment { * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for * debugging (PR_SET_DUMPABLE). */ - final boolean appIsDebuggable = isDebuggable(context); - final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1; - if (!(appIsDebuggable || deviceIsDebuggable)) { - Log.v(TAG, "Skipping loading temporary rules file: " - + "appIsDebuggable = " + appIsDebuggable + ", " - + "adbRootEnabled = " + deviceIsDebuggable); + if (!isDebuggable()) { + Log.v(TAG, "Skipping loading temporary rules file"); return false; } @@ -725,7 +712,7 @@ public class GraphicsEnvironment { final boolean enablePrereleaseDriver = (ai.metaData != null && ai.metaData.getBoolean(METADATA_DEVELOPER_DRIVER_ENABLE)) - || getCanLoadSystemLibraries() == 1; + || isDebuggable(); // Priority for Game Driver settings global on confliction (Higher priority comes first): // 1. GAME_DRIVER_ALL_APPS @@ -901,7 +888,7 @@ public class GraphicsEnvironment { return ""; } - private static native int getCanLoadSystemLibraries(); + private static native boolean isDebuggable(); private static native void setLayerPaths(ClassLoader classLoader, String layerPaths); private static native void setDebugLayers(String layers); private static native void setDebugLayersGLES(String layers); diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp index be9aee410d40..9ae1a9794395 100644 --- a/core/jni/android_os_GraphicsEnvironment.cpp +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -23,8 +23,8 @@ namespace { -int getCanLoadSystemLibraries_native() { - return android::GraphicsEnv::getInstance().getCanLoadSystemLibraries(); +bool isDebuggable_native() { + return android::GraphicsEnv::getInstance().isDebuggable(); } void setDriverPathAndSphalLibraries_native(JNIEnv* env, jobject clazz, jstring path, @@ -90,7 +90,7 @@ void hintActivityLaunch_native(JNIEnv* env, jobject clazz) { } const JNINativeMethod g_methods[] = { - { "getCanLoadSystemLibraries", "()I", reinterpret_cast(getCanLoadSystemLibraries_native) }, + { "isDebuggable", "()Z", reinterpret_cast(isDebuggable_native) }, { "setDriverPathAndSphalLibraries", "(Ljava/lang/String;Ljava/lang/String;)V", reinterpret_cast(setDriverPathAndSphalLibraries_native) }, { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;I)V", reinterpret_cast(setGpuStats_native) }, { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast(setAngleInfo_native) }, -- GitLab From b1a33a8b4fd4b1603c0465a904be29f0c4a07e64 Mon Sep 17 00:00:00 2001 From: Alexey Kuzmin Date: Tue, 7 Jan 2020 11:59:18 +0000 Subject: [PATCH 037/143] Fix serialization issue of ExternalVibration Remove excessive serialization of Audio Attributes Bug: 140417434 Test: atest ExternalVibrationTest#testSerialization Change-Id: Ib7ceaed875889126a53f874eec64fab4817e48d1 --- core/java/android/os/ExternalVibration.java | 1 - .../src/android/os/ExternalVibrationTest.java | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 core/tests/coretests/src/android/os/ExternalVibrationTest.java diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java index 37ca868598f5..041d21fabd6f 100644 --- a/core/java/android/os/ExternalVibration.java +++ b/core/java/android/os/ExternalVibration.java @@ -157,7 +157,6 @@ public class ExternalVibration implements Parcelable { out.writeInt(mUid); out.writeString(mPkg); writeAudioAttributes(mAttrs, out, flags); - out.writeParcelable(mAttrs, flags); out.writeStrongBinder(mController.asBinder()); out.writeStrongBinder(mToken); } diff --git a/core/tests/coretests/src/android/os/ExternalVibrationTest.java b/core/tests/coretests/src/android/os/ExternalVibrationTest.java new file mode 100644 index 000000000000..3b872d5a7ff1 --- /dev/null +++ b/core/tests/coretests/src/android/os/ExternalVibrationTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import static junit.framework.Assert.assertEquals; + +import static org.mockito.Mockito.mock; + +import android.media.AudioAttributes; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ExternalVibrationTest { + @Test + public void testSerialization() { + AudioAttributes audio = new AudioAttributes.Builder().build(); + IExternalVibrationController controller = mock(IExternalVibrationController.class); + ExternalVibration original = new ExternalVibration( + 123, // uid + "pkg", + audio, + controller); + Parcel p = Parcel.obtain(); + original.writeToParcel(p, 0); + p.setDataPosition(0); + ExternalVibration restored = ExternalVibration.CREATOR.createFromParcel(p); + assertEquals(original, restored); + } +} + -- GitLab From 0860a5c5c303426073c36763bef28644673ff441 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Tue, 5 Nov 2019 10:15:36 +0000 Subject: [PATCH 038/143] RESTRICT AUTOMERGE Update keyguard locked state from TrustManagerService TrustManagerService holds the ground truth about whether a user is locked or not, so update keystore using the information there, instead of doing it from KeyguardStateMonitor. This fixes the issue of work profile locked state not being correctly pushed to keystore. Note: since this change is likely to be backported as a security patch, I'm refraining from doing major refactoring right now. Bug: 141329041 Bug: 144430870 Test: manually with KeyPairSampleApp Change-Id: I3472ece73d573a775345ebcceeeb2cc460374c9b --- keystore/java/android/security/KeyStore.java | 11 +++++ .../policy/keyguard/KeyguardStateMonitor.java | 16 ------- .../server/trust/TrustManagerService.java | 48 +++++++++++++++++++ 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index fe05c13c999b..6be2da24e630 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -691,6 +691,17 @@ public class KeyStore { return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword); } + /** + * Notify keystore about the latest user locked state. This is to support keyguard-bound key. + */ + public void onUserLockedStateChanged(int userHandle, boolean locked) { + try { + mBinder.onKeyguardVisibilityChanged(locked, userHandle); + } catch (RemoteException e) { + Log.w(TAG, "Failed to update user locked state " + userHandle, e); + } + } + public int attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain) { try { diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index 1cba1c7bed1b..add0b01f1879 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -19,8 +19,6 @@ package com.android.server.policy.keyguard; import android.app.ActivityManager; import android.content.Context; import android.os.RemoteException; -import android.os.ServiceManager; -import android.security.IKeystoreService; import android.util.Slog; import com.android.internal.policy.IKeyguardService; @@ -53,16 +51,11 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { private final LockPatternUtils mLockPatternUtils; private final StateCallback mCallback; - IKeystoreService mKeystoreService; - public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) { mLockPatternUtils = new LockPatternUtils(context); mCurrentUserId = ActivityManager.getCurrentUser(); mCallback = callback; - mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager - .getService("android.security.keystore")); - try { service.addStateMonitorCallback(this); } catch (RemoteException e) { @@ -95,11 +88,6 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { mIsShowing = showing; mCallback.onShowingChanged(); - try { - mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId); - } catch (RemoteException e) { - Slog.e(TAG, "Error informing keystore of screen lock", e); - } } @Override // Binder interface @@ -111,10 +99,6 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { mCurrentUserId = userId; } - private synchronized int getCurrentUser() { - return mCurrentUserId; - } - @Override // Binder interface public void onInputRestrictedStateChanged(boolean inputRestricted) { mInputRestricted = inputRestricted; diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index f9f4bbfc8eb0..0c22f2f1c18a 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -47,6 +47,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.KeyStore; import android.service.trust.TrustAgentService; import android.text.TextUtils; import android.util.ArraySet; @@ -121,6 +122,33 @@ public class TrustManagerService extends SystemService { @GuardedBy("mUserIsTrusted") private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray(); + /** + * Stores the locked state for users on the device. There are three different type of users + * which are handled slightly differently: + *

    + *
  • Users with real keyguard + * These are users who can be switched to ({@link UserInfo#supportsSwitchToByUser()}). Their + * locked state is derived by a combination of user secure state, keyguard state, trust agent + * decision and biometric authentication result. These are updated via + * {@link #refreshDeviceLockedForUser(int)} and result stored in {@link #mDeviceLockedForUser}. + *
  • Managed profiles with unified challenge + * Managed profile with unified challenge always shares the same locked state as their parent, + * so their locked state is not recorded in {@link #mDeviceLockedForUser}. Instead, + * {@link ITrustManager#isDeviceLocked(int)} always resolves their parent user handle and + * queries its locked state instead. + *
  • Managed profiles with separate challenge + * Locked state for profile with separate challenge is determined by other parts of the + * framework (mostly PowerManager) and pushed to TrustManagerService via + * {@link ITrustManager#setDeviceLockedForUser(int, boolean)}. Although in a corner case when + * the profile has a separate but empty challenge, setting its {@link #mDeviceLockedForUser} to + * {@code false} is actually done by {@link #refreshDeviceLockedForUser(int)}. + *
+ * TODO: Rename {@link ITrustManager#setDeviceLockedForUser(int, boolean)} to + * {@code setDeviceLockedForProfile} to better reflect its purpose. Unifying + * {@code setDeviceLockedForProfile} and {@link #setDeviceLockedForUser} would also be nice. + * At the moment they both update {@link #mDeviceLockedForUser} but have slightly different + * side-effects: one notifies trust agents while the other sends out a broadcast. + */ @GuardedBy("mDeviceLockedForUser") private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray(); @@ -410,6 +438,10 @@ public class TrustManagerService extends SystemService { } } + /** + * Update the user's locked state. Only applicable to users with a real keyguard + * ({@link UserInfo#supportsSwitchToByUser}) and unsecured managed profiles. + */ private void refreshDeviceLockedForUser(int userId) { if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) { Log.e(TAG, "refreshDeviceLockedForUser(userId=" + userId + "): Invalid user handle," @@ -470,6 +502,15 @@ public class TrustManagerService extends SystemService { } if (changed) { dispatchDeviceLocked(userId, locked); + + KeyStore.getInstance().onUserLockedStateChanged(userId, locked); + // Also update the user's profiles who have unified challenge, since they + // share the same unlocked state (see {@link #isDeviceLocked(int)}) + for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) { + if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) { + KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked); + } + } } } @@ -992,6 +1033,10 @@ public class TrustManagerService extends SystemService { return "0x" + Integer.toHexString(i); } + /** + * Changes the lock status for the given user. This is only applicable to managed profiles, + * other users should be handled by Keyguard. + */ @Override public void setDeviceLockedForUser(int userId, boolean locked) { enforceReportPermission(); @@ -1002,6 +1047,9 @@ public class TrustManagerService extends SystemService { synchronized (mDeviceLockedForUser) { mDeviceLockedForUser.put(userId, locked); } + + KeyStore.getInstance().onUserLockedStateChanged(userId, locked); + if (locked) { try { ActivityManager.getService().notifyLockedProfile(userId); -- GitLab From 6a56247200e1a8afc4dacc2497ec384efa200b92 Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Tue, 10 Dec 2019 17:34:18 -0800 Subject: [PATCH 039/143] DO NOT MERGE Ensure package names read from config are system packages. Fixes: 145981139 Test: manually tested ensureSystemPackageName() returns null for non-system app Change-Id: I1d23910cbd282f6702785c9dfb059d7be6b0e895 --- .../server/pm/PackageManagerService.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 04cebb309216..77415aae22bc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3127,8 +3127,7 @@ public class PackageManagerService extends IPackageManager.Stub mWellbeingPackage = getWellbeingPackageName(); mDocumenterPackage = getDocumenterPackageName(); - mConfiguratorPackage = - mContext.getString(R.string.config_deviceConfiguratorPackageName); + mConfiguratorPackage = getDeviceConfiguratorPackageName(); mAppPredictionServicePackage = getAppPredictionServicePackageName(); mIncidentReportApproverPackage = getIncidentReportApproverPackageName(); @@ -21118,7 +21117,8 @@ public class PackageManagerService extends IPackageManager.Stub @Override public String getSystemTextClassifierPackageName() { - return mContext.getString(R.string.config_defaultTextClassifierPackage); + return ensureSystemPackageName(mContext.getString( + R.string.config_defaultTextClassifierPackage)); } @Override @@ -21128,7 +21128,7 @@ public class PackageManagerService extends IPackageManager.Stub if (flattenedComponentName != null) { ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName); if (componentName != null && componentName.getPackageName() != null) { - return componentName.getPackageName(); + return ensureSystemPackageName(componentName.getPackageName()); } } return null; @@ -21153,9 +21153,15 @@ public class PackageManagerService extends IPackageManager.Stub } } + @Nullable + private String getDeviceConfiguratorPackageName() { + return ensureSystemPackageName(mContext.getString( + R.string.config_deviceConfiguratorPackageName)); + } + @Override public String getWellbeingPackageName() { - return mContext.getString(R.string.config_defaultWellbeingPackage); + return ensureSystemPackageName(mContext.getString(R.string.config_defaultWellbeingPackage)); } @Override @@ -21170,7 +21176,7 @@ public class PackageManagerService extends IPackageManager.Stub if (appPredictionServiceComponentName == null) { return null; } - return appPredictionServiceComponentName.getPackageName(); + return ensureSystemPackageName(appPredictionServiceComponentName.getPackageName()); } @Override @@ -21187,11 +21193,23 @@ public class PackageManagerService extends IPackageManager.Stub if (systemCaptionsServiceComponentName == null) { return null; } - return systemCaptionsServiceComponentName.getPackageName(); + return ensureSystemPackageName(systemCaptionsServiceComponentName.getPackageName()); } public String getIncidentReportApproverPackageName() { - return mContext.getString(R.string.config_incidentReportApproverPackage); + return ensureSystemPackageName(mContext.getString( + R.string.config_incidentReportApproverPackage)); + } + + @Nullable + private String ensureSystemPackageName(@Nullable String packageName) { + if (packageName == null) { + return null; + } + if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) { + return null; + } + return packageName; } @Override -- GitLab From 58048eb8a972e107c9b9d137e4121964b3f41b71 Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Tue, 28 Jan 2020 21:25:53 -0500 Subject: [PATCH 040/143] Separate icon sizes for sharesheet and resolver list. Fixes: 148246479 Test: visual Change-Id: I16d06af155d2eec45d064e73bb45cc9cb6c5f2ca --- core/res/res/layout/resolve_grid_item.xml | 4 ++-- core/res/res/values/dimens.xml | 1 + core/res/res/values/symbols.xml | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml index 7098c958ce36..6d8682c61df1 100644 --- a/core/res/res/layout/resolve_grid_item.xml +++ b/core/res/res/layout/resolve_grid_item.xml @@ -30,8 +30,8 @@ android:background="?attr/selectableItemBackgroundBorderless"> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 4fdb498451ae..3edfb36982f8 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -764,6 +764,7 @@ 288dp 72dp 32dp + 42dp 8dp 18dp 16dp diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 09d927401548..10e9f9e8caa0 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3809,6 +3809,7 @@ + -- GitLab From 71801c6ac1459c28afe854e8ea633767788d704a Mon Sep 17 00:00:00 2001 From: Eric Berglund Date: Thu, 30 Jan 2020 10:05:54 -0800 Subject: [PATCH 041/143] DO NOT MERGE Unregister notification listener before creating a new one to avoid duplicate Heads Up notifications. Bug: 148530083 Test: manual Change-Id: I3f55b60a390f847b81b2de7da06d12b5725b3b39 --- .../systemui/statusbar/car/CarStatusBar.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 0046c20ab164..0a2d5a08a914 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -41,6 +41,7 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.RemoteException; import android.util.Log; import android.view.Display; import android.view.GestureDetector; @@ -167,6 +168,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private FlingAnimationUtils mFlingAnimationUtils; private SwitchToGuestTimer mSwitchToGuestTimer; private NotificationDataManager mNotificationDataManager; + private CarNotificationListener mCarNotificationListener; private NotificationClickHandlerFactory mNotificationClickHandlerFactory; private ScreenLifecycle mScreenLifecycle; private CarAudioManager mCarAudioManager; @@ -643,7 +645,17 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } }); - CarNotificationListener carNotificationListener = new CarNotificationListener(); + if (mCarNotificationListener != null) { + try { + // If we already had a notification listener we need to unreigster is before + // making a new one + mCarNotificationListener.unregisterAsSystemService(); + } catch (RemoteException e) { + Log.e(TAG, "Error unregistering notification listener."); + } + } + + mCarNotificationListener = new CarNotificationListener(); mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper(); mNotificationDataManager = new NotificationDataManager(); @@ -660,7 +672,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mNotificationClickHandlerFactory, mNotificationDataManager); mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager); - carNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper, + mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper, carHeadsUpNotificationManager, mNotificationDataManager); mNotificationView = mStatusBarWindow.findViewById(R.id.notification_view); @@ -769,7 +781,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mNotificationViewController = new NotificationViewController( mNotificationView, PreprocessingManager.getInstance(mContext), - carNotificationListener, + mCarNotificationListener, mCarUxRestrictionManagerWrapper, mNotificationDataManager); mNotificationViewController.enable(); @@ -1343,6 +1355,19 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override public void onLocaleListChanged() { + // When locale changes we need to reload the notification panel with the new language + if (mNotificationView == null) { + return; + } + + LayoutParams params = mNotificationView.getLayoutParams(); + int index = mStatusBarWindow.indexOfChild(mNotificationView); + + mStatusBarWindow.removeView(mNotificationView); + + View v = View.inflate(mContext, R.layout.notification_center_activity, null); + mStatusBarWindow.addView(v, index, params); + restartNavBars(); connectNotificationsUI(); } -- GitLab From 692e12085835925d4e34607032e4f290502394fc Mon Sep 17 00:00:00 2001 From: Rhed Jao Date: Thu, 16 Jan 2020 18:38:17 +0800 Subject: [PATCH 042/143] Fixed NPE in package installer session. We updated staged sessions to activation failed state when they aren't in terminal state, and device received ota and reboot. This happend before the StagingManager resumes the sessions when the whole set of parent+child sessions have been restored. A parent session probably cannot find the child session, and a null exception could happen. In this change, we do not destroy child sessions before we destroy the parent session. We only destroy a child session directly if we are sure that its parent session doesn't exist. Bug: 147651771 Test: StagedInstallTest Change-Id: Iac6489a04df35f851aa18a91e1dde2d73928b8ec Merged-in: Iac6489a04df35f851aa18a91e1dde2d73928b8ec (cherry picked from commit 1fc8b36cf38e2632db68e5d15acd3ff83d1f54aa) --- .../com/android/server/pm/PackageInstallerService.java | 9 ++++++--- .../core/java/com/android/server/pm/StagingManager.java | 9 ++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index fd8db4b99be8..d17365db77dd 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -258,12 +258,15 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } // Don't hold mSessions lock when calling restoreSession, since it might trigger an APK // atomic install which needs to query sessions, which requires lock on mSessions. + boolean isDeviceUpgrading = mPm.isDeviceUpgrading(); for (PackageInstallerSession session : stagedSessionsToRestore) { - if (mPm.isDeviceUpgrading() && !session.isStagedAndInTerminalState()) { + if (!session.isStagedAndInTerminalState() && session.hasParentSessionId() + && getSession(session.getParentSessionId()) == null) { session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, - "Build fingerprint has changed"); + "An orphan staged session " + session.sessionId + " is found, " + + "parent " + session.getParentSessionId() + " is missing"); } - mStagingManager.restoreSession(session); + mStagingManager.restoreSession(session, isDeviceUpgrading); } // Broadcasts are not sent while we restore sessions on boot, since no processes would be // ready to listen to them. From now on, we greedily assume that broadcasts requests are diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 9913c9846a17..895d2c5d00bf 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -619,7 +619,7 @@ public class StagingManager { return false; } - void restoreSession(@NonNull PackageInstallerSession session) { + void restoreSession(@NonNull PackageInstallerSession session, boolean isDeviceUpgrading) { PackageInstallerSession sessionToResume = session; synchronized (mStagedSessions) { mStagedSessions.append(session.sessionId, session); @@ -636,6 +636,13 @@ public class StagingManager { } } } + // The preconditions used during pre-reboot verification might have changed when device + // is upgrading. Updated staged sessions to activation failed before we resume the session. + if (isDeviceUpgrading && !sessionToResume.isStagedAndInTerminalState()) { + sessionToResume.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Build fingerprint has changed"); + return; + } checkStateAndResume(sessionToResume); } -- GitLab From 44d1c652ce124eb40101effe300d8655a7869f7b Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 29 Jan 2020 18:15:05 -0800 Subject: [PATCH 043/143] Update redaction upon profile changes We can't rely on status bar state changes to update the notification list. The current user might not be set yet, causing wrong notifications to become visible. Fixes: 145135488 Test: manual Test: atest NotificationStackScrollLayoutTest Change-Id: I34d1d5f9a751c1d7680a5a5941c39b9fe33a473b Merged-In: I34d1d5f9a751c1d7680a5a5941c39b9fe33a473b --- .../stack/NotificationStackScrollLayout.java | 7 +++++-- .../stack/NotificationStackScrollLayoutTest.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index f7b79d175263..918e257fcee0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -566,6 +566,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated); mRoundnessManager.setOnRoundingChangedCallback(this::invalidate); addOnExpandedHeightListener(mRoundnessManager::setExpanded); + mLockscreenUserManager.addUserChangedListener(userId -> + updateSensitiveness(false /* animated */)); setOutlineProvider(mOutlineProvider); // Blocking helper manager wants to know the expanded state, update as well. @@ -4567,7 +4569,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - private void setHideSensitive(boolean hideSensitive, boolean animate) { + private void updateSensitiveness(boolean animate) { + boolean hideSensitive = mLockscreenUserManager.isAnyProfilePublicMode(); if (hideSensitive != mAmbientState.isHideSensitive()) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -5331,7 +5334,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd SysuiStatusBarStateController state = (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); - setHideSensitive(publicMode, state.goingToFullShade() /* animate */); + updateSensitiveness(state.goingToFullShade() /* animate */); setDimmed(onKeyguard, state.fromShadeLocked() /* animate */); setExpandingEnabled(!onKeyguard); ActivatableNotificationView activatedChild = getActivatedChild(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index ff835871d822..34163841cc59 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -57,6 +57,8 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.AmbientPulseManager; import com.android.systemui.statusbar.EmptyShadeView; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; @@ -117,6 +119,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private NotificationIconAreaController mNotificationIconAreaController; @Mock private MetricsLogger mMetricsLogger; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; + @Mock private NotificationLockscreenUserManager mLockscreenUserManager; + private UserChangedListener mUserChangedListener; private TestableNotificationEntryManager mEntryManager; private int mOriginalInterruptionModelSetting; @@ -135,6 +139,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mDependency.injectTestDependency( NotificationBlockingHelperManager.class, mBlockingHelperManager); + mDependency.injectTestDependency(NotificationLockscreenUserManager.class, + mLockscreenUserManager); mDependency.injectTestDependency(StatusBarStateController.class, mBarState); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); mDependency.injectTestDependency(NotificationRemoteInputManager.class, @@ -150,6 +156,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { NotificationShelf notificationShelf = mock(NotificationShelf.class); + ArgumentCaptor userChangedCaptor = ArgumentCaptor + .forClass(UserChangedListener.class); // The actual class under test. You may need to work with this class directly when // testing anonymous class members of mStackScroller, like mMenuEventListener, @@ -171,6 +179,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mStackScroller.setGroupManager(mGroupManager); mStackScroller.setEmptyShadeView(mEmptyShadeView); mStackScroller.setIconAreaController(mNotificationIconAreaController); + verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture()); + mUserChangedListener = userChangedCaptor.getValue(); // Stub out functionality that isn't necessary to test. doNothing().when(mBar) @@ -255,6 +265,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mBlockingHelperManager).setNotificationShadeExpanded(100f); } + @Test + public void testOnStatePostChange_verifyIfProfileIsPublic() { + mUserChangedListener.onUserChanged(0); + verify(mLockscreenUserManager).isAnyProfilePublicMode(); + } + @Test public void manageNotifications_visible() { FooterView view = mock(FooterView.class); -- GitLab From f83594ce422bb487eebc6c2a3627de273a6c8fe7 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Tue, 28 Jan 2020 15:09:33 -0800 Subject: [PATCH 044/143] Don't crash system process on empty onTuneFailed This change: - modifies internal programSelectorFromHal to return null instead of throwing NPE on empty input - throws NPE on two of its usages where null is unexpected - *does not* throw NPE on one usage where program selector is optional (onTuneFailed in RadioModule.java) Bug: 147522441 Test: boots, but have no quick way to trigger onTuneFailed(Result::error, {}) Change-Id: I6317da3fbde2bce90079b61bb0839e893e1c4712 (cherry picked from commit dc8a5683a149b4f5ce3d9a9f6198fbe310547dbf) --- .../server/broadcastradio/hal2/Convert.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java index 9730c9a1a380..ab5bef8b80a7 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java @@ -275,8 +275,18 @@ class Convert { return hwSel; } - static @NonNull ProgramSelector programSelectorFromHal( + private static boolean isEmpty( @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) { + if (sel.primaryId.type != 0) return false; + if (sel.primaryId.value != 0) return false; + if (sel.secondaryIds.size() != 0) return false; + return true; + } + + static @Nullable ProgramSelector programSelectorFromHal( + @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) { + if (isEmpty(sel)) return null; + ProgramSelector.Identifier[] secondaryIds = sel.secondaryIds.stream(). map(Convert::programIdentifierFromHal).map(Objects::requireNonNull). toArray(ProgramSelector.Identifier[]::new); @@ -364,7 +374,7 @@ class Convert { collect(Collectors.toList()); return new RadioManager.ProgramInfo( - programSelectorFromHal(info.selector), + Objects.requireNonNull(programSelectorFromHal(info.selector)), programIdentifierFromHal(info.logicallyTunedTo), programIdentifierFromHal(info.physicallyTunedTo), relatedContent, @@ -402,7 +412,7 @@ class Convert { public static @NonNull android.hardware.radio.Announcement announcementFromHal( @NonNull Announcement hwAnnouncement) { return new android.hardware.radio.Announcement( - programSelectorFromHal(hwAnnouncement.selector), + Objects.requireNonNull(programSelectorFromHal(hwAnnouncement.selector)), hwAnnouncement.type, vendorInfoFromHal(hwAnnouncement.vendorInfo) ); -- GitLab From 43c949771924179cc21095ca621bbda383e53d4b Mon Sep 17 00:00:00 2001 From: Kavi Gupta Date: Tue, 11 Jun 2019 09:19:35 -0700 Subject: [PATCH 045/143] Add JVMTI agent to dump/reset JaCoCo coverage information This agent can be attached to an arbitrary Android process with arguments that cause it to either reset or dump the JaCoCo information to a provided directory. Bug: 148178774 Test: manual, used examples in README to test whether it works on a userdebug_coverage build on cuttlefish Change-Id: If6cee20046f790676b8085e1ca84652c063295fa Merged-In: If6cee20046f790676b8085e1ca84652c063295fa (cherry picked from commit 2d84ae7640641c1e931746071a58f13c8a49c61b) --- tools/dump-coverage/Android.bp | 29 ++++ tools/dump-coverage/README.md | 50 ++++++ tools/dump-coverage/dump_coverage.cc | 239 +++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 tools/dump-coverage/Android.bp create mode 100644 tools/dump-coverage/README.md create mode 100644 tools/dump-coverage/dump_coverage.cc diff --git a/tools/dump-coverage/Android.bp b/tools/dump-coverage/Android.bp new file mode 100644 index 000000000000..4519ce3636bf --- /dev/null +++ b/tools/dump-coverage/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Build variants {target,host} x {32,64} +cc_library { + name: "libdumpcoverage", + srcs: ["dump_coverage.cc"], + header_libs: [ + "libopenjdkjvmti_headers", + ], + + host_supported: true, + shared_libs: [ + "libbase", + ], +} diff --git a/tools/dump-coverage/README.md b/tools/dump-coverage/README.md new file mode 100644 index 000000000000..2bab4bc8c984 --- /dev/null +++ b/tools/dump-coverage/README.md @@ -0,0 +1,50 @@ +# dumpcoverage + +libdumpcoverage.so is a JVMTI agent designed to dump coverage information for a process, where the binaries have been instrumented by JaCoCo. JaCoCo automatically starts recording data on process start, and we need a way to trigger the resetting or dumping of this data. + +The JVMTI agent is used to make the calls to JaCoCo in its process. + +# Usage + +Note that these examples assume you have an instrumented build (userdebug_coverage). Here is, for example, how to dump coverage information regarding the default clock app. First some setup is necessary: + +``` +adb root # necessary to copy files in/out of the /data/data/{package} folder +adb shell 'mkdir /data/data/com.android.deskclock/folder-to-use' +``` + +Then we can run the command to dump the data: + +``` +adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=dump:/data/data/com.android.deskclock/folder-to-use' +``` + +We can also reset the coverage information with + +``` +adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=reset' +``` + +then perform more actions, then dump the data again. To get the files, we can get + +``` +adb pull /data/data/com.android.deskclock/folder-to-use ~/path-on-your-computer +``` + +And you should have timestamped `.exec` files on your machine under the folder `~/path-on-your-computer` + +# Details + +In dump mode, the agent makes JNI calls equivalent to + +``` +Agent.getInstance().getExecutionData(/*reset = */ false); +``` + +and then saves the result to a file specified by the passed in directory + +In reset mode, it makes a JNI call equivalent to + +``` +Agent.getInstance().reset(); +``` diff --git a/tools/dump-coverage/dump_coverage.cc b/tools/dump-coverage/dump_coverage.cc new file mode 100644 index 000000000000..3de1865b8018 --- /dev/null +++ b/tools/dump-coverage/dump_coverage.cc @@ -0,0 +1,239 @@ +// Copyright (C) 2018 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::get; +using std::tuple; +using std::chrono::system_clock; + +namespace dump_coverage { + +#define CHECK_JVMTI(x) CHECK_EQ((x), JVMTI_ERROR_NONE) +#define CHECK_NOTNULL(x) CHECK((x) != nullptr) +#define CHECK_NO_EXCEPTION(env) CHECK(!(env)->ExceptionCheck()); + +static JavaVM* java_vm = nullptr; + +// Get the current JNI environment. +static JNIEnv* GetJNIEnv() { + JNIEnv* env = nullptr; + CHECK_EQ(java_vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6), + JNI_OK); + return env; +} + +// Get the JaCoCo Agent class and an instance of the class, given a JNI +// environment. +// Will crash if the Agent isn't found or if any Java Exception occurs. +static tuple GetJavaAgent(JNIEnv* env) { + jclass java_agent_class = + env->FindClass("org/jacoco/agent/rt/internal/Agent"); + CHECK_NOTNULL(java_agent_class); + + jmethodID java_agent_get_instance = + env->GetStaticMethodID(java_agent_class, "getInstance", + "()Lorg/jacoco/agent/rt/internal/Agent;"); + CHECK_NOTNULL(java_agent_get_instance); + + jobject java_agent_instance = + env->CallStaticObjectMethod(java_agent_class, java_agent_get_instance); + CHECK_NO_EXCEPTION(env); + CHECK_NOTNULL(java_agent_instance); + + return tuple(java_agent_class, java_agent_instance); +} + +// Runs equivalent of Agent.getInstance().getExecutionData(false) and returns +// the result. +// Will crash if the Agent isn't found or if any Java Exception occurs. +static jbyteArray GetExecutionData(JNIEnv* env) { + auto java_agent = GetJavaAgent(env); + jmethodID java_agent_get_execution_data = + env->GetMethodID(get<0>(java_agent), "getExecutionData", "(Z)[B"); + CHECK_NO_EXCEPTION(env); + CHECK_NOTNULL(java_agent_get_execution_data); + + jbyteArray java_result_array = (jbyteArray)env->CallObjectMethod( + get<1>(java_agent), java_agent_get_execution_data, false); + CHECK_NO_EXCEPTION(env); + + return java_result_array; +} + +// Gets the filename to write execution data to +// dirname: the directory in which to place the file +// outputs /YYYY-MM-DD-HH-MM-SS.SSS.exec +static std::string GetFilename(const std::string& dirname) { + system_clock::time_point time_point = system_clock::now(); + auto seconds = std::chrono::time_point_cast(time_point); + auto fractional_time = time_point - seconds; + auto millis = std::chrono::duration_cast(fractional_time); + + std::time_t time = system_clock::to_time_t(time_point); + auto tm = *std::gmtime(&time); + + std::ostringstream oss; + oss + << dirname + << "/" + << std::put_time(&tm, "%Y-%m-%d-%H-%M-%S.") + << std::setfill('0') << std::setw(3) << millis.count() + << ".ec"; + return oss.str(); +} + +// Writes the execution data to a file +// data, length: represent the data, as a sequence of bytes +// dirname: directory name to contain the file +// returns JNI_ERR if there is an error in writing the file, otherwise JNI_OK. +static jint WriteFile(const char* data, int length, const std::string& dirname) { + auto filename = GetFilename(dirname); + + LOG(INFO) << "Writing file of length " << length << " to '" << filename + << "'"; + std::ofstream file(filename, std::ios::binary); + + if (!file.is_open()) { + LOG(ERROR) << "Could not open file: '" << filename << "'"; + return JNI_ERR; + } + file.write(data, length); + file.close(); + + if (!file) { + LOG(ERROR) << "I/O error in reading file"; + return JNI_ERR; + } + + LOG(INFO) << "Done writing file"; + return JNI_OK; +} + +// Grabs execution data and writes it to a file +// dirname: directory name to contain the file +// returns JNI_ERR if there is an error writing the file. +// Will crash if the Agent isn't found or if any Java Exception occurs. +static jint Dump(const std::string& dirname) { + LOG(INFO) << "Dumping file"; + + JNIEnv* env = GetJNIEnv(); + jbyteArray java_result_array = GetExecutionData(env); + CHECK_NOTNULL(java_result_array); + + jbyte* result_ptr = env->GetByteArrayElements(java_result_array, 0); + CHECK_NOTNULL(result_ptr); + + int result_len = env->GetArrayLength(java_result_array); + + return WriteFile((const char*) result_ptr, result_len, dirname); +} + +// Resets execution data, performing the equivalent of +// Agent.getInstance().reset(); +// args: should be empty +// returns JNI_ERR if the arguments are invalid. +// Will crash if the Agent isn't found or if any Java Exception occurs. +static jint Reset(const std::string& args) { + if (args != "") { + LOG(ERROR) << "reset takes no arguments, but received '" << args << "'"; + return JNI_ERR; + } + + JNIEnv* env = GetJNIEnv(); + auto java_agent = GetJavaAgent(env); + + jmethodID java_agent_reset = + env->GetMethodID(get<0>(java_agent), "reset", "()V"); + CHECK_NOTNULL(java_agent_reset); + + env->CallVoidMethod(get<1>(java_agent), java_agent_reset); + CHECK_NO_EXCEPTION(env); + return JNI_OK; +} + +// Given a string of the form ":" returns (, ). +// Given a string that doesn't contain a colon, returns (, ""). +static tuple SplitOnColon(const std::string& options) { + size_t loc_delim = options.find(':'); + std::string command, args; + + if (loc_delim == std::string::npos) { + command = options; + } else { + command = options.substr(0, loc_delim); + args = options.substr(loc_delim + 1, options.length()); + } + return tuple(command, args); +} + +// Parses and executes a command specified by options of the form +// ":" where is either "dump" or "reset". +static jint ParseOptionsAndExecuteCommand(const std::string& options) { + auto split = SplitOnColon(options); + auto command = get<0>(split), args = get<1>(split); + + LOG(INFO) << "command: '" << command << "' args: '" << args << "'"; + + if (command == "dump") { + return Dump(args); + } + + if (command == "reset") { + return Reset(args); + } + + LOG(ERROR) << "Invalid command: expected 'dump' or 'reset' but was '" + << command << "'"; + return JNI_ERR; +} + +static jint AgentStart(JavaVM* vm, char* options) { + android::base::InitLogging(/* argv= */ nullptr); + java_vm = vm; + + return ParseOptionsAndExecuteCommand(options); +} + +// Late attachment (e.g. 'am attach-agent'). +extern "C" JNIEXPORT jint JNICALL +Agent_OnAttach(JavaVM* vm, char* options, void* reserved ATTRIBUTE_UNUSED) { + return AgentStart(vm, options); +} + +// Early attachment. +extern "C" JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM* jvm ATTRIBUTE_UNUSED, char* options ATTRIBUTE_UNUSED, void* reserved ATTRIBUTE_UNUSED) { + LOG(ERROR) + << "The dumpcoverage agent will not work on load," + << " as it does not have access to the runtime."; + return JNI_ERR; +} + +} // namespace dump_coverage -- GitLab From 3f81e072da4a20d0753787720fac6d014d9e4670 Mon Sep 17 00:00:00 2001 From: Oliver Nguyen Date: Tue, 16 Jul 2019 14:09:38 -0700 Subject: [PATCH 046/143] Change coverage dump to specify the output file instead of directory. Bug: 137857876 Test: manual Change-Id: I2d835856d7a1b6b1ded561eca923f455b39317e4 Merged-In: I2d835856d7a1b6b1ded561eca923f455b39317e4 (cherry picked from commit 05b1c06a91b54321bd2b329916ea0702a020d12e) --- tools/dump-coverage/README.md | 6 ++-- tools/dump-coverage/dump_coverage.cc | 52 +++++----------------------- 2 files changed, 12 insertions(+), 46 deletions(-) diff --git a/tools/dump-coverage/README.md b/tools/dump-coverage/README.md index 2bab4bc8c984..d1c10bc2e520 100644 --- a/tools/dump-coverage/README.md +++ b/tools/dump-coverage/README.md @@ -16,7 +16,7 @@ adb shell 'mkdir /data/data/com.android.deskclock/folder-to-use' Then we can run the command to dump the data: ``` -adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=dump:/data/data/com.android.deskclock/folder-to-use' +adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so=dump:/data/data/com.android.deskclock/folder-to-use/coverage-file.ec' ``` We can also reset the coverage information with @@ -28,10 +28,10 @@ adb shell 'am attach-agent com.android.deskclock /system/lib/libdumpcoverage.so= then perform more actions, then dump the data again. To get the files, we can get ``` -adb pull /data/data/com.android.deskclock/folder-to-use ~/path-on-your-computer +adb pull /data/data/com.android.deskclock/folder-to-use/coverage-file.ec ~/path-on-your-computer ``` -And you should have timestamped `.exec` files on your machine under the folder `~/path-on-your-computer` +And you should have `coverage-file.ec` on your machine under the folder `~/path-on-your-computer` # Details diff --git a/tools/dump-coverage/dump_coverage.cc b/tools/dump-coverage/dump_coverage.cc index 3de1865b8018..0808e776f190 100644 --- a/tools/dump-coverage/dump_coverage.cc +++ b/tools/dump-coverage/dump_coverage.cc @@ -18,20 +18,10 @@ #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include using std::get; using std::tuple; -using std::chrono::system_clock; namespace dump_coverage { @@ -87,35 +77,11 @@ static jbyteArray GetExecutionData(JNIEnv* env) { return java_result_array; } -// Gets the filename to write execution data to -// dirname: the directory in which to place the file -// outputs /YYYY-MM-DD-HH-MM-SS.SSS.exec -static std::string GetFilename(const std::string& dirname) { - system_clock::time_point time_point = system_clock::now(); - auto seconds = std::chrono::time_point_cast(time_point); - auto fractional_time = time_point - seconds; - auto millis = std::chrono::duration_cast(fractional_time); - - std::time_t time = system_clock::to_time_t(time_point); - auto tm = *std::gmtime(&time); - - std::ostringstream oss; - oss - << dirname - << "/" - << std::put_time(&tm, "%Y-%m-%d-%H-%M-%S.") - << std::setfill('0') << std::setw(3) << millis.count() - << ".ec"; - return oss.str(); -} - -// Writes the execution data to a file -// data, length: represent the data, as a sequence of bytes -// dirname: directory name to contain the file +// Writes the execution data to a file. +// data, length: represent the data, as a sequence of bytes. +// filename: file to write coverage data to. // returns JNI_ERR if there is an error in writing the file, otherwise JNI_OK. -static jint WriteFile(const char* data, int length, const std::string& dirname) { - auto filename = GetFilename(dirname); - +static jint WriteFile(const char* data, int length, const std::string& filename) { LOG(INFO) << "Writing file of length " << length << " to '" << filename << "'"; std::ofstream file(filename, std::ios::binary); @@ -136,11 +102,11 @@ static jint WriteFile(const char* data, int length, const std::string& dirname) return JNI_OK; } -// Grabs execution data and writes it to a file -// dirname: directory name to contain the file +// Grabs execution data and writes it to a file. +// filename: file to write coverage data to. // returns JNI_ERR if there is an error writing the file. // Will crash if the Agent isn't found or if any Java Exception occurs. -static jint Dump(const std::string& dirname) { +static jint Dump(const std::string& filename) { LOG(INFO) << "Dumping file"; JNIEnv* env = GetJNIEnv(); @@ -152,12 +118,12 @@ static jint Dump(const std::string& dirname) { int result_len = env->GetArrayLength(java_result_array); - return WriteFile((const char*) result_ptr, result_len, dirname); + return WriteFile((const char*) result_ptr, result_len, filename); } // Resets execution data, performing the equivalent of // Agent.getInstance().reset(); -// args: should be empty +// args: should be empty. // returns JNI_ERR if the arguments are invalid. // Will crash if the Agent isn't found or if any Java Exception occurs. static jint Reset(const std::string& args) { -- GitLab From 3736484a0d4e92c3436b63d7112ec7db2502c4b0 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 29 Jan 2020 18:15:05 -0800 Subject: [PATCH 047/143] Update redaction upon profile changes We can't rely on status bar state changes to update the notification list. The current user might not be set yet, causing wrong notifications to become visible. Fixes: 145135488 Test: manual Test: atest NotificationStackScrollLayoutTest Change-Id: I34d1d5f9a751c1d7680a5a5941c39b9fe33a473b Merged-In: I34d1d5f9a751c1d7680a5a5941c39b9fe33a473b --- .../stack/NotificationStackScrollLayout.java | 7 +++++-- .../stack/NotificationStackScrollLayoutTest.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 688e8eb8f2e3..7c49c3f961c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -566,6 +566,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated); mRoundnessManager.setOnRoundingChangedCallback(this::invalidate); addOnExpandedHeightChangedListener(mRoundnessManager::setExpanded); + mLockscreenUserManager.addUserChangedListener(userId -> + updateSensitiveness(false /* animated */)); setOutlineProvider(mOutlineProvider); // Blocking helper manager wants to know the expanded state, update as well. @@ -4602,7 +4604,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - private void setHideSensitive(boolean hideSensitive, boolean animate) { + private void updateSensitiveness(boolean animate) { + boolean hideSensitive = mLockscreenUserManager.isAnyProfilePublicMode(); if (hideSensitive != mAmbientState.isHideSensitive()) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -5306,7 +5309,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd SysuiStatusBarStateController state = (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); - setHideSensitive(publicMode, state.goingToFullShade() /* animate */); + updateSensitiveness(state.goingToFullShade() /* animate */); setDimmed(onKeyguard, state.fromShadeLocked() /* animate */); setExpandingEnabled(!onKeyguard); ActivatableNotificationView activatedChild = getActivatedChild(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 31054260eb15..7c9537b95319 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -57,6 +57,8 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.EmptyShadeView; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; @@ -119,6 +121,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private MetricsLogger mMetricsLogger; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock private NotificationLockscreenUserManager mLockscreenUserManager; + private UserChangedListener mUserChangedListener; private TestableNotificationEntryManager mEntryManager; private int mOriginalInterruptionModelSetting; @@ -138,6 +142,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { NotificationBlockingHelperManager.class, mBlockingHelperManager); mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState); + mDependency.injectTestDependency(NotificationLockscreenUserManager.class, + mLockscreenUserManager); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); mDependency.injectTestDependency(NotificationRemoteInputManager.class, mRemoteInputManager); @@ -152,6 +158,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { NotificationShelf notificationShelf = mock(NotificationShelf.class); + ArgumentCaptor userChangedCaptor = ArgumentCaptor + .forClass(UserChangedListener.class); // The actual class under test. You may need to work with this class directly when // testing anonymous class members of mStackScroller, like mMenuEventListener, @@ -174,6 +182,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mStackScroller.setGroupManager(mGroupManager); mStackScroller.setEmptyShadeView(mEmptyShadeView); mStackScroller.setIconAreaController(mNotificationIconAreaController); + verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture()); + mUserChangedListener = userChangedCaptor.getValue(); // Stub out functionality that isn't necessary to test. doNothing().when(mBar) @@ -246,6 +256,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mBlockingHelperManager).setNotificationShadeExpanded(100f); } + @Test + public void testOnStatePostChange_verifyIfProfileIsPublic() { + mUserChangedListener.onUserChanged(0); + verify(mLockscreenUserManager).isAnyProfilePublicMode(); + } + @Test public void manageNotifications_visible() { FooterView view = mock(FooterView.class); -- GitLab From 715c0180eb26c97b9a9ffa95a9a1f8c4d64ff832 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 24 Sep 2019 09:35:49 -0700 Subject: [PATCH 048/143] Added log statements to some user-switching tasks. NOTE: as user switch is a very low-frequency operation, these logs statements don't need to be guard (to avoid spam). Test: manual verification Bug: 141502467 Bug: 140999054 Bug: 145027829 Change-Id: I7122e45c45a646419b03242c99d90417a29da92a Merged-In: I7122e45c45a646419b03242c99d90417a29da92a (cherry picked from commit ebccffe3b10d8642e7b1d64f183b627f644011a4) (cherry picked from commit b5f0e74302b14dd850b41909052638f24edc15b5) --- .../core/java/com/android/server/am/UserController.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 598a68e90aa8..b8cf27c9698e 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -408,6 +408,7 @@ class UserController implements Handler.Callback { */ private boolean finishUserUnlocking(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserUnlocking(" + userId + ")"); // Only keep marching forward if user is actually unlocked if (!StorageManager.isUserKeyUnlocked(userId)) return false; synchronized (mLock) { @@ -452,6 +453,7 @@ class UserController implements Handler.Callback { */ void finishUserUnlocked(final UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserUnlocked(" + userId + ")"); // Only keep marching forward if user is actually unlocked if (!StorageManager.isUserKeyUnlocked(userId)) return; synchronized (mLock) { @@ -522,6 +524,7 @@ class UserController implements Handler.Callback { private void finishUserUnlockedCompleted(UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserUnlockedCompleted(" + userId + ")"); synchronized (mLock) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; @@ -739,6 +742,7 @@ class UserController implements Handler.Callback { } void finishUserStopping(final int userId, final UserState uss) { + Slog.d(TAG, "UserController event: finishUserStopping(" + userId + ")"); // On to the next. final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN); // This is the result receiver for the final shutdown broadcast. @@ -778,6 +782,7 @@ class UserController implements Handler.Callback { void finishUserStopped(UserState uss) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "UserController event: finishUserStopped(" + userId + ")"); final boolean stopped; boolean lockUser = true; final ArrayList stopCallbacks; @@ -1259,7 +1264,7 @@ class UserController implements Handler.Callback { Slog.w(TAG, msg); throw new SecurityException(msg); } - + Slog.i(TAG, "unlocking user " + userId); final long binderToken = Binder.clearCallingIdentity(); try { return unlockUserCleared(userId, token, secret, listener); @@ -1344,6 +1349,7 @@ class UserController implements Handler.Callback { boolean switchUser(final int targetUserId) { enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId); + Slog.i(TAG, "switching to user " + targetUserId); int currentUserId = getCurrentUserId(); UserInfo targetUserInfo = getUserInfo(targetUserId); if (targetUserId == currentUserId) { -- GitLab From eeb7039c236d718929acd2d13774019c0c11fde5 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 29 Jan 2020 12:15:29 -0800 Subject: [PATCH 049/143] Set a shorter timeout for logging a warn on slow IUserSwitchObservers. On automotive, it helps identify slow services. For example: W ActivityManager: User switch delayed: observer #1 WallpaperManagerService sent result after 1608 ms Without this change, the WallpaperManagerService wouldn't be logged because the "give up" timeout is 3000ms. Bug: 145558164 Bug: 144801993 Test: manual verification (see logcat above) Change-Id: I68e3b7220bbac25075e4fd4dad83c3a26b88940c Merged-In: I68e3b7220bbac25075e4fd4dad83c3a26b88940c (cherry picked from commit 48a75cbd675117471f7547c84e00833c32b4a677) --- .../java/com/android/server/am/UserController.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 598a68e90aa8..6807caec1c1b 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -129,6 +129,10 @@ class UserController implements Handler.Callback { // giving up on them and unfreezing the screen. static final int USER_SWITCH_TIMEOUT_MS = 3 * 1000; + // Amount of time we wait for observers to handle a user switch before we log a warning. + // Must be smaller than USER_SWITCH_TIMEOUT_MS. + private static final int USER_SWITCH_WARNING_TIMEOUT_MS = 500; + // ActivityManager thread message constants static final int REPORT_USER_SWITCH_MSG = 10; static final int CONTINUE_USER_SWITCH_MSG = 20; @@ -1486,9 +1490,13 @@ class UserController implements Handler.Callback { synchronized (mLock) { long delay = SystemClock.elapsedRealtime() - dispatchStartedTime; if (delay > USER_SWITCH_TIMEOUT_MS) { - Slog.e(TAG, "User switch timeout: observer " + name + Slog.e(TAG, "User switch timeout: observer " + name + " sent result after " + delay + " ms"); + } else if (delay > USER_SWITCH_WARNING_TIMEOUT_MS) { + Slog.w(TAG, "User switch slowed down by observer " + name + + ": result sent after " + delay + " ms"); } + curWaitingUserSwitchCallbacks.remove(name); // Continue switching if all callbacks have been notified and // user switching session is still valid -- GitLab From c93fa740aa8b3308c6a7b9b83d5bd3e08a4f3c92 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 29 Jan 2020 18:15:05 -0800 Subject: [PATCH 050/143] resolve merge conflicts of 01f94b7cc053049a472481f457593d895ad9eca0 to qt-qpr1-dev Bug: None Test: I solemnly swear I tested this conflict resolution. Change-Id: I2d15aaa7402e4e08f1630aa29892ad6cd68bd2b1 Merged-In: I34d1d5f9a751c1d7680a5a5941c39b9fe33a473b --- .../stack/NotificationStackScrollLayout.java | 7 +++++-- .../stack/NotificationStackScrollLayoutTest.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 688e8eb8f2e3..7c49c3f961c9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -566,6 +566,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated); mRoundnessManager.setOnRoundingChangedCallback(this::invalidate); addOnExpandedHeightChangedListener(mRoundnessManager::setExpanded); + mLockscreenUserManager.addUserChangedListener(userId -> + updateSensitiveness(false /* animated */)); setOutlineProvider(mOutlineProvider); // Blocking helper manager wants to know the expanded state, update as well. @@ -4602,7 +4604,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - private void setHideSensitive(boolean hideSensitive, boolean animate) { + private void updateSensitiveness(boolean animate) { + boolean hideSensitive = mLockscreenUserManager.isAnyProfilePublicMode(); if (hideSensitive != mAmbientState.isHideSensitive()) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { @@ -5306,7 +5309,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd SysuiStatusBarStateController state = (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); - setHideSensitive(publicMode, state.goingToFullShade() /* animate */); + updateSensitiveness(state.goingToFullShade() /* animate */); setDimmed(onKeyguard, state.fromShadeLocked() /* animate */); setExpandingEnabled(!onKeyguard); ActivatableNotificationView activatedChild = getActivatedChild(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 31054260eb15..7c9537b95319 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -57,6 +57,8 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.EmptyShadeView; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; @@ -119,6 +121,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Mock private MetricsLogger mMetricsLogger; @Mock private NotificationRoundnessManager mNotificationRoundnessManager; @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock private NotificationLockscreenUserManager mLockscreenUserManager; + private UserChangedListener mUserChangedListener; private TestableNotificationEntryManager mEntryManager; private int mOriginalInterruptionModelSetting; @@ -138,6 +142,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { NotificationBlockingHelperManager.class, mBlockingHelperManager); mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState); + mDependency.injectTestDependency(NotificationLockscreenUserManager.class, + mLockscreenUserManager); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); mDependency.injectTestDependency(NotificationRemoteInputManager.class, mRemoteInputManager); @@ -152,6 +158,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { NotificationShelf notificationShelf = mock(NotificationShelf.class); + ArgumentCaptor userChangedCaptor = ArgumentCaptor + .forClass(UserChangedListener.class); // The actual class under test. You may need to work with this class directly when // testing anonymous class members of mStackScroller, like mMenuEventListener, @@ -174,6 +182,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mStackScroller.setGroupManager(mGroupManager); mStackScroller.setEmptyShadeView(mEmptyShadeView); mStackScroller.setIconAreaController(mNotificationIconAreaController); + verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture()); + mUserChangedListener = userChangedCaptor.getValue(); // Stub out functionality that isn't necessary to test. doNothing().when(mBar) @@ -246,6 +256,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mBlockingHelperManager).setNotificationShadeExpanded(100f); } + @Test + public void testOnStatePostChange_verifyIfProfileIsPublic() { + mUserChangedListener.onUserChanged(0); + verify(mLockscreenUserManager).isAnyProfilePublicMode(); + } + @Test public void manageNotifications_visible() { FooterView view = mock(FooterView.class); -- GitLab From 4aced5d9065ebf1abbe35a8bcfb8f3bd105cd77a Mon Sep 17 00:00:00 2001 From: "Chris.CC Lee" Date: Tue, 4 Feb 2020 09:34:48 +0800 Subject: [PATCH 051/143] [DO NOT MERGE] Fix AoD front scrim being opaque at DOZE_PULSING When doze state changed from DOZE to DOZE_PULSING on devices not supporting doze_brightness_sensor_type sensor, there would be no sensor events to update the AoD front scrim. And due to the scrim was set to opaque at DOZE state, most views on the statusbar will be invisible. This patch change the scrim to transparent again at leaving DOZE state. Bug: 148129743 Test: atest DozeScreenBrightnessTest Change-Id: I1cf9d02c9e35dcb3e94cbbc24fec483c51e372d9 --- .../systemui/doze/DozeScreenBrightness.java | 4 ++++ .../systemui/doze/DozeScreenBrightnessTest.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index bd6882c01bbd..c27e633f2a96 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -161,6 +161,10 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi // again, it will only show after the brightness sensor has stabilized, // avoiding a potential flicker. scrimOpacity = 255; + } else if (!mScreenOff && mLightSensor == null) { + // No light sensor but previous state turned the screen black. Make the scrim + // transparent and below views visible. + scrimOpacity = 0; } else if (brightnessReady) { // Only unblank scrim once brightness is ready. scrimOpacity = computeScrimOpacity(sensorValue); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index 392c677b9827..3b760e31b4ac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -156,6 +156,20 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { assertEquals(1, mServiceFake.screenBrightness); } + @Test + public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception { + mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, + null /* sensor */, mHostFake, null /* handler */, + DEFAULT_BRIGHTNESS, SENSOR_TO_BRIGHTNESS, SENSOR_TO_OPACITY, + true /* debuggable */); + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE); + + mScreen.transitionTo(DOZE, DOZE_REQUEST_PULSE); + + assertEquals(0f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); + } + @Test public void testDozingAfterPulsing_pausesLightSensor() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); -- GitLab From b9c4862b8605b653153be29ed902142539f4ffe2 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 30 Oct 2019 13:29:01 +0000 Subject: [PATCH 052/143] Re-activate backup service after cleaning a profile owner Currently backup service is re-activated unconditionally when clearing a device owner but not profile owner. With this CL it should be re-activate in both cases. NB: there are two bits of state related to backup service: 1. activated or deactivated: This is out of user control, but can be changed by the admin via DPM.setBackupServiceEnabled (this name is a bit misleading here). 2. enabled or disabled: this is controlled by the user via Settings and only available when backup service is activated (see 1.) Bug: 143274029 Bug: 147997438 Test: atest CtsAdminTestCases && adb shell bmgr enabled Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest Merged-In: I6f11642abe544c7df265ed7e2ad466d47796e7f9 Change-Id: I6f11642abe544c7df265ed7e2ad466d47796e7f9 (cherry picked from commit 775b26d8844540680015c5df90f8592c1864a9a8) --- .../DevicePolicyManagerService.java | 15 +++----- .../devicepolicy/DevicePolicyManagerTest.java | 35 ++++++++++++++++--- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 37931be4eb10..c3749c3b0a92 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -8058,15 +8058,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mSecurityLogMonitor.stop(); setNetworkLoggingActiveInternal(false); deleteTransferOwnershipBundleLocked(userId); - - try { - if (mInjector.getIBackupManager() != null) { - // Reactivate backup service. - mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true); - } - } catch (RemoteException e) { - throw new IllegalStateException("Failed reactivating backup service.", e); - } + toggleBackupServiceActive(UserHandle.USER_SYSTEM, true); } @Override @@ -8126,7 +8118,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void toggleBackupServiceActive(int userId, boolean makeActive) { long ident = mInjector.binderClearCallingIdentity(); try { @@ -8135,7 +8126,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .setBackupServiceActive(userId, makeActive); } } catch (RemoteException e) { - throw new IllegalStateException("Failed deactivating backup service.", e); + throw new IllegalStateException(String.format("Failed %s backup service.", + makeActive ? "activating" : "deactivating"), e); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -8186,6 +8178,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mOwners.removeProfileOwner(userId); mOwners.writeProfileOwner(userId); deleteTransferOwnershipBundleLocked(userId); + toggleBackupServiceActive(userId, true); } @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 9ae9824da3e2..b9ae23cdfe51 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -909,10 +909,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { verify(getServices().iactivityManager, times(1)).updateDeviceOwner( eq(admin1.getPackageName())); - // TODO We should check if the caller has called clearCallerIdentity(). - verify(getServices().ibackupManager, times(1)).setBackupServiceActive( - eq(UserHandle.USER_SYSTEM), eq(false)); - verify(mContext.spiedContext, times(1)).sendBroadcastAsUser( MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED), MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)); @@ -1141,6 +1137,37 @@ public class DevicePolicyManagerTest extends DpmTestBase { // TODO Check other calls. } + public void testDeviceOwnerBackupActivateDeactivate() throws Exception { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + + // Set admin1 as a DA to the secondary user. + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); + dpm.setActiveAdmin(admin1, /* replace =*/ false); + assertTrue(dpm.setDeviceOwner(admin1, "owner-name")); + + verify(getServices().ibackupManager, times(1)).setBackupServiceActive( + eq(UserHandle.USER_SYSTEM), eq(false)); + + dpm.clearDeviceOwnerApp(admin1.getPackageName()); + + verify(getServices().ibackupManager, times(1)).setBackupServiceActive( + eq(UserHandle.USER_SYSTEM), eq(true)); + } + + public void testProfileOwnerBackupActivateDeactivate() throws Exception { + setAsProfileOwner(admin1); + + verify(getServices().ibackupManager, times(1)).setBackupServiceActive( + eq(DpmMockContext.CALLER_USER_HANDLE), eq(false)); + + dpm.clearProfileOwner(admin1); + + verify(getServices().ibackupManager, times(1)).setBackupServiceActive( + eq(DpmMockContext.CALLER_USER_HANDLE), eq(true)); + } + public void testClearDeviceOwner_fromDifferentUser() throws Exception { mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); mContext.callerPermissions.add(permission.MANAGE_USERS); -- GitLab From e693b797bcf0be38f0fc9d878bb5278eacf8b4b1 Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Tue, 4 Feb 2020 10:11:12 -0800 Subject: [PATCH 053/143] Call getPackageInfo() with cleared calling identity in ensureSystemPackageName(). Otherwise non-primary users might get a SecurityException. Bug: 145981139 Bug: 148763415 Test: manual Change-Id: I5883e296a0d753e43075cbf0abc5dc4da91e2fca --- .../com/android/server/pm/PackageManagerService.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 035dda2381e0..ca66776239db 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -21231,8 +21231,13 @@ public class PackageManagerService extends IPackageManager.Stub if (packageName == null) { return null; } - if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) { - return null; + long token = Binder.clearCallingIdentity(); + try { + if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) { + return null; + } + } finally { + Binder.restoreCallingIdentity(token); } return packageName; } -- GitLab From 584d73a0b066e01b0877b475c8e2b1a85fcf5328 Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Tue, 10 Dec 2019 17:34:18 -0800 Subject: [PATCH 054/143] DO NOT MERGE Ensure package names read from config are system packages. Bug: 145981139 Test: manually tested ensureSystemPackageName() returns null for non-system app Change-Id: I1d23910cbd282f6702785c9dfb059d7be6b0e895 (cherry picked from commit 6a56247200e1a8afc4dacc2497ec384efa200b92) --- .../server/pm/PackageManagerService.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index fc1392ac6b3e..dd86d91517ec 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -20710,7 +20710,29 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); @Override public String getSystemTextClassifierPackageName() { - return mContext.getString(R.string.config_defaultTextClassifierPackage); + return ensureSystemPackageName(mContext.getString( + R.string.config_defaultTextClassifierPackage)); + } + + @Nullable + private String ensureSystemPackageName(@Nullable String packageName) { + if (packageName == null) { + return null; + } + long token = Binder.clearCallingIdentity(); + try { + if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) { + PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM); + if (packageInfo != null) { + EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid, + ""); + } + return null; + } + } finally { + Binder.restoreCallingIdentity(token); + } + return packageName; } @Override -- GitLab From 4bf6bc5d50a8c439fe8b67edb1d9dd4a1437f57d Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Tue, 10 Dec 2019 17:34:18 -0800 Subject: [PATCH 055/143] DO NOT MERGE Ensure package names read from config are system packages. Bug: 145981139 Test: manually tested ensureSystemPackageName() returns null for non-system app Change-Id: I1d23910cbd282f6702785c9dfb059d7be6b0e895 Merged-In: I1d23910cbd282f6702785c9dfb059d7be6b0e895 Merged-In: I86c6bfc0a6e28e634e0fd201e424b7ee6882ba2c Merged-In: I5883e296a0d753e43075cbf0abc5dc4da91e2fca (cherry picked from commit 6a56247200e1a8afc4dacc2497ec384efa200b92) --- .../server/pm/PackageManagerService.java | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 161cdb8744f7..289a45b2414b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -3114,8 +3114,7 @@ public class PackageManagerService extends IPackageManager.Stub mWellbeingPackage = getWellbeingPackageName(); mDocumenterPackage = getDocumenterPackageName(); - mConfiguratorPackage = - mContext.getString(R.string.config_deviceConfiguratorPackageName); + mConfiguratorPackage = getDeviceConfiguratorPackageName(); mAppPredictionServicePackage = getAppPredictionServicePackageName(); mIncidentReportApproverPackage = getIncidentReportApproverPackageName(); @@ -21109,7 +21108,8 @@ public class PackageManagerService extends IPackageManager.Stub @Override public String getSystemTextClassifierPackageName() { - return mContext.getString(R.string.config_defaultTextClassifierPackage); + return ensureSystemPackageName(mContext.getString( + R.string.config_defaultTextClassifierPackage)); } @Override @@ -21119,7 +21119,7 @@ public class PackageManagerService extends IPackageManager.Stub if (flattenedComponentName != null) { ComponentName componentName = ComponentName.unflattenFromString(flattenedComponentName); if (componentName != null && componentName.getPackageName() != null) { - return componentName.getPackageName(); + return ensureSystemPackageName(componentName.getPackageName()); } } return null; @@ -21144,9 +21144,15 @@ public class PackageManagerService extends IPackageManager.Stub } } + @Nullable + private String getDeviceConfiguratorPackageName() { + return ensureSystemPackageName(mContext.getString( + R.string.config_deviceConfiguratorPackageName)); + } + @Override public String getWellbeingPackageName() { - return mContext.getString(R.string.config_defaultWellbeingPackage); + return ensureSystemPackageName(mContext.getString(R.string.config_defaultWellbeingPackage)); } @Override @@ -21161,7 +21167,7 @@ public class PackageManagerService extends IPackageManager.Stub if (appPredictionServiceComponentName == null) { return null; } - return appPredictionServiceComponentName.getPackageName(); + return ensureSystemPackageName(appPredictionServiceComponentName.getPackageName()); } @Override @@ -21178,11 +21184,33 @@ public class PackageManagerService extends IPackageManager.Stub if (systemCaptionsServiceComponentName == null) { return null; } - return systemCaptionsServiceComponentName.getPackageName(); + return ensureSystemPackageName(systemCaptionsServiceComponentName.getPackageName()); } public String getIncidentReportApproverPackageName() { - return mContext.getString(R.string.config_incidentReportApproverPackage); + return ensureSystemPackageName(mContext.getString( + R.string.config_incidentReportApproverPackage)); + } + + @Nullable + private String ensureSystemPackageName(@Nullable String packageName) { + if (packageName == null) { + return null; + } + long token = Binder.clearCallingIdentity(); + try { + if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) { + PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM); + if (packageInfo != null) { + EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid, + ""); + } + return null; + } + } finally { + Binder.restoreCallingIdentity(token); + } + return packageName; } @Override -- GitLab From 29e092bf290bacb980a47da22f722c1542197565 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Sat, 25 Jan 2020 06:54:06 -0800 Subject: [PATCH 056/143] Notify all packages is uid-mode is changed Multiple packages might share a UID, but appOpsService might not have cached the uid->package mapping for those yet. Hence the only way to list all packages for a uid is to ask package manager. setUidMode already handled this correctly, hence factor out the code into notifyOpChangedForAllPkgsInUid and reuse it from commitUidStatePendingLocked. Bug: 148180766 Test: (on master) atest CtsAppOpsTestCases:android.app.appops.cts.ForegroundModeTest Change-Id: I99a8f255a60d3523da7eb36a8f2c9426af1a1fea Merged-In: I2d5d6c7aa38d201707349a137c9c29b7987775be --- .../android/server/appop/AppOpsService.java | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 3e7188c6e8ec..90d0c3568c13 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -31,6 +31,7 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION; import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; import static android.app.AppOpsManager.UID_STATE_PERSISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; +import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager.modeToName; import static android.app.AppOpsManager.opToName; import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState; @@ -1288,6 +1289,18 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.evalForegroundOps(mOpModeWatchers); } + notifyOpChangedForAllPkgsInUid(code, uid, false); + notifyOpChangedSync(code, uid, null, mode); + } + + /** + * Notify that an op changed for all packages in an uid. + * + * @param code The op that changed + * @param uid The uid the op was changed for + * @param onlyForeground Only notify watchers that watch for foreground changes + */ + private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground) { String[] uidPackageNames = getPackagesForUid(uid); ArrayMap> callbackSpecs = null; @@ -1297,6 +1310,10 @@ public class AppOpsService extends IAppOpsService.Stub { final int callbackCount = callbacks.size(); for (int i = 0; i < callbackCount; i++) { ModeCallback callback = callbacks.valueAt(i); + if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + ArraySet changedPackages = new ArraySet<>(); Collections.addAll(changedPackages, uidPackageNames); if (callbackSpecs == null) { @@ -1315,6 +1332,10 @@ public class AppOpsService extends IAppOpsService.Stub { final int callbackCount = callbacks.size(); for (int i = 0; i < callbackCount; i++) { ModeCallback callback = callbacks.valueAt(i); + if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + ArraySet changedPackages = callbackSpecs.get(callback); if (changedPackages == null) { changedPackages = new ArraySet<>(); @@ -1327,7 +1348,6 @@ public class AppOpsService extends IAppOpsService.Stub { } if (callbackSpecs == null) { - notifyOpChangedSync(code, uid, null, mode); return; } @@ -1349,8 +1369,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - - notifyOpChangedSync(code, uid, null, mode); } private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) { @@ -2496,24 +2514,28 @@ public class AppOpsService extends IAppOpsService.Stub { if (resolvedLastFg == resolvedNowFg) { continue; } - final ArraySet callbacks = mOpModeWatchers.get(code); - if (callbacks != null) { - for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { - final ModeCallback callback = callbacks.valueAt(cbi); - if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 - || !callback.isWatchingUid(uidState.uid)) { - continue; - } - boolean doAllPackages = uidState.opModes != null - && uidState.opModes.indexOfKey(code) >= 0 - && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND; - if (uidState.pkgOps != null) { + + if (uidState.opModes != null + && uidState.opModes.indexOfKey(code) >= 0 + && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND) { + mHandler.sendMessage(PooledLambda.obtainMessage( + AppOpsService::notifyOpChangedForAllPkgsInUid, + this, code, uidState.uid, true)); + } else { + final ArraySet callbacks = mOpModeWatchers.get(code); + if (callbacks != null) { + for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { + final ModeCallback callback = callbacks.valueAt(cbi); + if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 + || !callback.isWatchingUid(uidState.uid)) { + continue; + } for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) { final Op op = uidState.pkgOps.valueAt(pkgi).get(code); if (op == null) { continue; } - if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) { + if (op.mode == AppOpsManager.MODE_FOREGROUND) { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpChanged, this, callback, code, uidState.uid, -- GitLab From ab9be4fdb63bf30831fd2e05be1315e6c7f067ae Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Sat, 25 Jan 2020 06:57:04 -0800 Subject: [PATCH 057/143] Force update uid state when pending uid state is applied Before the state was update lazily when someone interacted with appopsmanager. Since Q the the uid state might change depending on the procState and hence we might need to trigger the opChanged callbacks when the procState is applied. Bug: 148180766 Test: (on master) atest CtsAppOpsTestCases:android.app.appops.cts.ForegroundModeTest Change-Id: I99720a372db6e79eaba30e4563c09e009cffe86f Merged-In: Id974769a4e9d89c01890b7557dd93f8444a3908f --- .../android/server/appop/AppOpsService.java | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 90d0c3568c13..a5ad42f17912 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -36,6 +36,8 @@ import static android.app.AppOpsManager.modeToName; import static android.app.AppOpsManager.opToName; import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState; +import static java.lang.Long.max; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -934,6 +936,19 @@ public class AppOpsService extends IAppOpsService.Stub { } } + /** + * Update the pending state for the uid + * + * @param currentTime The current elapsed real time + * @param uid The uid that has a pending state + */ + private void updatePendingState(long currentTime, int uid) { + synchronized (this) { + mLastRealtime = max(currentTime, mLastRealtime); + updatePendingStateIfNeededLocked(mUidStates.get(uid)); + } + } + public void updateUidProcState(int uid, int procState) { synchronized (this) { final UidState uidState = getUidStateLocked(uid, true); @@ -959,7 +974,12 @@ public class AppOpsService extends IAppOpsService.Stub { } else { settleTime = mConstants.BG_STATE_SETTLE_TIME; } - uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime; + final long commitTime = SystemClock.elapsedRealtime() + settleTime; + uidState.pendingStateCommitTime = commitTime; + + mHandler.sendMessageDelayed( + PooledLambda.obtainMessage(AppOpsService::updatePendingState, this, + commitTime + 1, uid), settleTime + 1); } if (uidState.startNesting != 0) { // There is some actively running operation... need to find it @@ -2485,6 +2505,18 @@ public class AppOpsService extends IAppOpsService.Stub { uidState = new UidState(uid); mUidStates.put(uid, uidState); } else { + updatePendingStateIfNeededLocked(uidState); + } + return uidState; + } + + /** + * Check if the pending state should be updated and do so if needed + * + * @param uidState The uidState that might have a pending state + */ + private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) { + if (uidState != null) { if (uidState.pendingStateCommitTime != 0) { if (uidState.pendingStateCommitTime < mLastRealtime) { commitUidPendingStateLocked(uidState); @@ -2496,7 +2528,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - return uidState; } private void commitUidPendingStateLocked(UidState uidState) { -- GitLab From a79b6ba5c59dc6aaa8adbe1ffa3ee4b761f45e7f Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Mon, 19 Aug 2019 16:16:20 -0700 Subject: [PATCH 058/143] DO NOT MERGE - Kill apps outright for API contract violations ...rather than relying on in-app code to perform the shutdown. Backport of security fix. Bug: 128649910 Bug: 140108616 Test: manual Test: atest OsHostTests#testForegroundServiceBadNotification Change-Id: I94d9de50bb03c33666471e3dbd9c721e9278f7cb Merged-In: I94d9de50bb03c33666471e3dbd9c721e9278f7cb --- core/java/android/app/IActivityManager.aidl | 3 ++- .../com/android/server/am/ActiveServices.java | 11 +++++++- .../server/am/ActivityManagerService.java | 5 ++-- .../am/ActivityManagerShellCommand.java | 2 +- .../java/com/android/server/am/AppErrors.java | 26 ++++++++++++++----- .../com/android/server/am/ServiceRecord.java | 7 +++-- .../NotificationManagerService.java | 14 ++++++++++ 7 files changed, 52 insertions(+), 16 deletions(-) diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index b192021f821b..3f7f3b73c417 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -278,7 +278,8 @@ interface IActivityManager { boolean isImmersive(in IBinder token); void setImmersive(in IBinder token, boolean immersive); boolean isTopActivityImmersive(); - void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message); + void crashApplication(int uid, int initialPid, in String packageName, int userId, + in String message, boolean force); String getProviderMimeType(in Uri uri, int userId); IBinder newUriPermissionOwner(in String name); void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg, diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index ca715b51a328..b49d07f3e46c 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -787,6 +787,15 @@ public final class ActiveServices { } } + void killMisbehavingService(ServiceRecord r, + int appUid, int appPid, String localPackageName) { + synchronized (mAm) { + stopServiceLocked(r); + mAm.crashApplication(appUid, appPid, localPackageName, -1, + "Bad notification for startForeground", true /*force*/); + } + } + IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) { ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), @@ -3655,7 +3664,7 @@ public final class ActiveServices { void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) { mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId, "Context.startForegroundService() did not then call Service.startForeground(): " - + serviceRecord); + + serviceRecord, false /*force*/); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7c57c43533af..3dea717a9982 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5773,7 +5773,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void crashApplication(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: crashApplication() from pid=" @@ -5785,7 +5785,8 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message); + mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, + message, force); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index ccbc8ed32a9c..adb7056408ba 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -987,7 +987,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } catch (NumberFormatException e) { packageName = arg; } - mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash"); + mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false); return 0; } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index f0e2876b4761..0b8fca9d8e71 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -314,20 +314,24 @@ class AppErrors { } void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) { - app.crashing = false; - app.crashingReport = null; - app.notResponding = false; - app.notRespondingReport = null; if (app.anrDialog == fromDialog) { app.anrDialog = null; } if (app.waitDialog == fromDialog) { app.waitDialog = null; } + killAppImmediateLocked(app, "user-terminated", "user request after error"); + } + + private void killAppImmediateLocked(ProcessRecord app, String reason, String killReason) { + app.crashing = false; + app.crashingReport = null; + app.notResponding = false; + app.notRespondingReport = null; if (app.pid > 0 && app.pid != MY_PID) { - handleAppCrashLocked(app, "user-terminated" /*reason*/, + handleAppCrashLocked(app, reason, null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); - app.kill("user request after error", true); + app.kill(killReason, true); } } @@ -341,7 +345,7 @@ class AppErrors { * @param message */ void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { ProcessRecord proc = null; // Figure out which process to kill. We don't trust that initialPid @@ -374,6 +378,14 @@ class AppErrors { } proc.scheduleCrash(message); + if (force) { + // If the app is responsive, the scheduled crash will happen as expected + // and then the delayed summary kill will be a no-op. + final ProcessRecord p = proc; + mService.mHandler.postDelayed( + () -> killAppImmediateLocked(p, "forced", "killed for invalid state"), + 5000L); + } } /** diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 4d89d015b669..925a4d97fa32 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -584,6 +584,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN final String localPackageName = packageName; final int localForegroundId = foregroundId; final Notification _foregroundNoti = foregroundNoti; + final ServiceRecord record = this; ams.mHandler.post(new Runnable() { public void run() { NotificationManagerInternal nm = LocalServices.getService( @@ -682,10 +683,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN Slog.w(TAG, "Error showing notification for service", e); // If it gave us a garbage notification, it doesn't // get to be foreground. - ams.setServiceForeground(name, ServiceRecord.this, - 0, null, 0); - ams.crashApplication(appUid, appPid, localPackageName, -1, - "Bad notification for startForeground: " + e); + ams.mServices.killMisbehavingService(record, + appUid, appPid, localPackageName); } } }); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b1ea47c6f3b0..c4647096f61c 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -798,8 +798,22 @@ public class NotificationManagerService extends SystemService { @Override public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, int uid, int initialPid, String message, int userId) { + final boolean fgService; + synchronized (mNotificationLock) { + NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); + fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0; + } cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, REASON_ERROR, null); + if (fgService) { + // Still crash for foreground services, preventing the not-crash behaviour abused + // by apps to give us a garbage notification and silently start a fg service. + Binder.withCleanCallingIdentity( + () -> mAm.crashApplication(uid, initialPid, pkg, -1, + "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " + + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " + + message, true /* force */)); + } } @Override -- GitLab From 6b14ea266e9c5d72db901272f9c8e6e0ef0a51f3 Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Fri, 31 Jan 2020 16:25:45 -0800 Subject: [PATCH 059/143] Add SafetyNet logging for package names read from config. Bug: 145981139 Test: manual Change-Id: I86c6bfc0a6e28e634e0fd201e424b7ee6882ba2c --- .../java/com/android/server/pm/PackageManagerService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ca66776239db..8ee925e182e4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -21234,6 +21234,11 @@ public class PackageManagerService extends IPackageManager.Stub long token = Binder.clearCallingIdentity(); try { if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) { + PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM); + if (packageInfo != null) { + EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid, + ""); + } return null; } } finally { -- GitLab From ed30689e2190b19641db6cef664eb32d2f7cf0e0 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 5 Dec 2019 09:55:36 -0800 Subject: [PATCH 060/143] DO NOT MERGE - Use TimingsTraceLog on SystemServiceManager and VoiceInteractionManagerService. (NOTE: this change is manually cherry-picked from master - master has the same trace calls, but they were introduced by larger changes) Bug: 145626101 Bug: 145027829 Test: manual verification Change-Id: I5cae10c9c7e5ed6f733c72659643708dfa826fc7 --- .../android/server/SystemServiceManager.java | 41 ++++++++++++------- .../VoiceInteractionManagerService.java | 25 ++++++++++- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index c5b4966ddcf2..3df585e4b866 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -22,6 +22,7 @@ import android.os.Environment; import android.os.SystemClock; import android.os.Trace; import android.util.Slog; +import android.util.TimingsTraceLog; import java.io.File; import java.lang.reflect.Constructor; @@ -178,12 +179,13 @@ public class SystemServiceManager { } public void startUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.startUser-" + userHandle); Slog.i(TAG, "Calling onStartUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStartUser " - + service.getClass().getName()); + t.traceBegin("onStartUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onStartUser(userHandle); @@ -192,17 +194,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStartUser "); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void unlockUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.unlockUser-" + userHandle); Slog.i(TAG, "Calling onUnlockUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onUnlockUser " - + service.getClass().getName()); + t.traceBegin("onUnlockUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onUnlockUser(userHandle); @@ -211,17 +215,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onUnlockUser "); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void switchUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.switchUser-" + userHandle); Slog.i(TAG, "Calling switchUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onSwitchUser " - + service.getClass().getName()); + t.traceBegin("onSwitchUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onSwitchUser(userHandle); @@ -230,17 +236,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onSwitchUser"); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void stopUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.stopUser-" + userHandle); Slog.i(TAG, "Calling onStopUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStopUser " - + service.getClass().getName()); + t.traceBegin("onStopUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onStopUser(userHandle); @@ -249,17 +257,19 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStopUser"); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } public void cleanupUser(final int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("ssm.cleanupUser-" + userHandle); Slog.i(TAG, "Calling onCleanupUser u" + userHandle); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); - Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onCleanupUser " - + service.getClass().getName()); + t.traceBegin("onCleanupUser-" + userHandle + " " + service.getClass().getName()); long time = SystemClock.elapsedRealtime(); try { service.onCleanupUser(userHandle); @@ -268,8 +278,9 @@ public class SystemServiceManager { + " to service " + service.getClass().getName(), ex); } warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onCleanupUser"); - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceEnd(); } + t.traceEnd(); } /** Sets the safe mode flag for services to query. */ diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 46d7509b43ca..0b1c07b9ee43 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; @@ -51,6 +52,7 @@ import android.os.Parcel; import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -65,6 +67,7 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import android.util.TimingsTraceLog; import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceInteractionManagerService; @@ -269,7 +272,17 @@ public class VoiceInteractionManagerService extends SystemService { } } - public void initForUser(int userHandle) { + public void initForUser(@UserIdInt int userHandle) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("initForUser(" + userHandle + ")"); + try { + initForUserNoTracing(userHandle); + } finally { + t.traceEnd(); + } + } + + private void initForUserNoTracing(@UserIdInt int userHandle) { if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle); String curInteractorStr = Settings.Secure.getStringForUser( mContext.getContentResolver(), @@ -426,6 +439,16 @@ public class VoiceInteractionManagerService extends SystemService { } void switchImplementationIfNeededLocked(boolean force) { + final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + t.traceBegin("switchImplementation(" + mCurUser + ")"); + try { + switchImplementationIfNeededNoTracingLocked(force); + } finally { + t.traceEnd(); + } + } + + void switchImplementationIfNeededNoTracingLocked(boolean force) { if (!mSafeMode) { String curService = Settings.Secure.getStringForUser( mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); -- GitLab From 38567a6051bbc38041048fa36f5e83ac00adba70 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Mon, 19 Aug 2019 16:16:20 -0700 Subject: [PATCH 061/143] DO NOT MERGE - Kill apps outright for API contract violations ...rather than relying on in-app code to perform the shutdown. Bug: 128649910 Bug: 140108616 Test: manual Test: atest OsHostTests#testForegroundServiceBadNotification Change-Id: I94d9de50bb03c33666471e3dbd9c721e9278f7cb Merged-In: I94d9de50bb03c33666471e3dbd9c721e9278f7cb --- core/java/android/app/IActivityManager.aidl | 3 ++- .../com/android/server/am/ActiveServices.java | 11 +++++++- .../server/am/ActivityManagerService.java | 5 ++-- .../am/ActivityManagerShellCommand.java | 2 +- .../java/com/android/server/am/AppErrors.java | 26 ++++++++++++++----- .../com/android/server/am/ServiceRecord.java | 7 +++-- .../NotificationManagerService.java | 14 ++++++++++ 7 files changed, 52 insertions(+), 16 deletions(-) diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 48ca71690a1b..c0c63555b10a 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -287,7 +287,8 @@ interface IActivityManager { void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask, in StrictMode.ViolationInfo crashInfo); boolean isTopActivityImmersive(); - void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message); + void crashApplication(int uid, int initialPid, in String packageName, int userId, + in String message, boolean force); @UnsupportedAppUsage String getProviderMimeType(in Uri uri, int userId); // Cause the specified process to dump the specified heap. diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 7bc2e6d647be..5d72828964c7 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -829,6 +829,15 @@ public final class ActiveServices { } } + void killMisbehavingService(ServiceRecord r, + int appUid, int appPid, String localPackageName) { + synchronized (mAm) { + stopServiceLocked(r); + mAm.crashApplication(appUid, appPid, localPackageName, -1, + "Bad notification for startForeground", true /*force*/); + } + } + IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) { ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), @@ -3918,7 +3927,7 @@ public final class ActiveServices { void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) { mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId, "Context.startForegroundService() did not then call Service.startForeground(): " - + serviceRecord); + + serviceRecord, false /*force*/); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c6cae530e795..81d636ea832f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3568,7 +3568,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void crashApplication(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: crashApplication() from pid=" @@ -3580,7 +3580,8 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message); + mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, + message, force); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index cba9674d7360..8f16ed4768de 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1051,7 +1051,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } catch (NumberFormatException e) { packageName = arg; } - mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash"); + mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false); return 0; } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 1ff6f4dac724..6a29c75b702a 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -314,20 +314,24 @@ class AppErrors { } void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) { - app.setCrashing(false); - app.crashingReport = null; - app.setNotResponding(false); - app.notRespondingReport = null; if (app.anrDialog == fromDialog) { app.anrDialog = null; } if (app.waitDialog == fromDialog) { app.waitDialog = null; } + killAppImmediateLocked(app, "user-terminated", "user request after error"); + } + + private void killAppImmediateLocked(ProcessRecord app, String reason, String killReason) { + app.setCrashing(false); + app.crashingReport = null; + app.setNotResponding(false); + app.notRespondingReport = null; if (app.pid > 0 && app.pid != MY_PID) { - handleAppCrashLocked(app, "user-terminated" /*reason*/, + handleAppCrashLocked(app, reason, null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); - app.kill("user request after error", true); + app.kill(killReason, true); } } @@ -341,7 +345,7 @@ class AppErrors { * @param message */ void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { ProcessRecord proc = null; // Figure out which process to kill. We don't trust that initialPid @@ -374,6 +378,14 @@ class AppErrors { } proc.scheduleCrash(message); + if (force) { + // If the app is responsive, the scheduled crash will happen as expected + // and then the delayed summary kill will be a no-op. + final ProcessRecord p = proc; + mService.mHandler.postDelayed( + () -> killAppImmediateLocked(p, "forced", "killed for invalid state"), + 5000L); + } } /** diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index dee8e3b285a7..c408695bcb66 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -798,6 +798,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN final String localPackageName = packageName; final int localForegroundId = foregroundId; final Notification _foregroundNoti = foregroundNoti; + final ServiceRecord record = this; ams.mHandler.post(new Runnable() { public void run() { NotificationManagerInternal nm = LocalServices.getService( @@ -896,10 +897,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN Slog.w(TAG, "Error showing notification for service", e); // If it gave us a garbage notification, it doesn't // get to be foreground. - ams.setServiceForeground(instanceName, ServiceRecord.this, - 0, null, 0, 0); - ams.crashApplication(appUid, appPid, localPackageName, -1, - "Bad notification for startForeground: " + e); + ams.mServices.killMisbehavingService(record, + appUid, appPid, localPackageName); } } }); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 928747ecf14c..1eaafd4a8de1 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -892,8 +892,22 @@ public class NotificationManagerService extends SystemService { @Override public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, int uid, int initialPid, String message, int userId) { + final boolean fgService; + synchronized (mNotificationLock) { + NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); + fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0; + } cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, REASON_ERROR, null); + if (fgService) { + // Still crash for foreground services, preventing the not-crash behaviour abused + // by apps to give us a garbage notification and silently start a fg service. + Binder.withCleanCallingIdentity( + () -> mAm.crashApplication(uid, initialPid, pkg, -1, + "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " + + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " + + message, true /* force */)); + } } @Override -- GitLab From c4808d9a4b846b612a3d2a377a096ca92b66736b Mon Sep 17 00:00:00 2001 From: Aarthi Balachander Date: Mon, 27 Aug 2018 11:03:59 -0700 Subject: [PATCH 062/143] Make switching dialog full screen and change "Loading" text color. Bug: 148318514 Bug: 111928877, 112242211 Test: Tested on device Change-Id: Iaa45b8e7581f2a19106a6e734432fe2cda661a33 (cherry picked from commit 88def57a6d97271013c0ca996950ff33939e7013) --- core/res/res/layout/car_user_switching_dialog.xml | 13 +++++-------- .../android/server/am/CarUserSwitchingDialog.java | 3 --- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/core/res/res/layout/car_user_switching_dialog.xml b/core/res/res/layout/car_user_switching_dialog.xml index 7ce35df3613a..d7274348bd16 100644 --- a/core/res/res/layout/car_user_switching_dialog.xml +++ b/core/res/res/layout/car_user_switching_dialog.xml @@ -16,25 +16,22 @@ --> + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + android:layout_centerHorizontal="true"/> + android:gravity="center"/> \ No newline at end of file diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index 60754fbc5cd3..a6811e3070b2 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -30,7 +30,6 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.UserManager; import android.provider.Settings; @@ -57,8 +56,6 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { String switchingToSystemUserMessage) { super(service, context, oldUser, newUser, aboveSystem, switchingFromSystemUserMessage, switchingToSystemUserMessage); - - getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); } @Override -- GitLab From fb23ff98d90936bbae0d8f8ee3cd4465d9659680 Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Wed, 5 Feb 2020 17:35:19 -0800 Subject: [PATCH 063/143] Add null check for handler on Clock view On reboot, we've encountered an issue where the handler returns null, causing a null pointer exception in the broadcast receiver. In this CL, we add a null check and an error message to prevent a sysui crash. Bug: 148869042 Test: build, reboot a few times Change-Id: Iac7f3a538be9a53d4a76926523aa2a3f4f22723d Merged-In: Ie8a2627004876cf35291d52bd3686a5014498f52 --- .../systemui/statusbar/policy/Clock.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index c2c3f81527e8..371de7439f8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -34,6 +34,7 @@ import android.text.format.DateFormat; import android.text.style.CharacterStyle; import android.text.style.RelativeSizeSpan; import android.util.AttributeSet; +import android.util.Log; import android.view.Display; import android.view.View; import android.widget.TextView; @@ -67,6 +68,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C DarkReceiver, ConfigurationListener { public static final String CLOCK_SECONDS = "clock_seconds"; + private static final String TAG = "StatusBarClock"; private static final String CLOCK_SUPER_PARCELABLE = "clock_super_parcelable"; private static final String CURRENT_USER_ID = "current_user_id"; private static final String VISIBLE_BY_POLICY = "visible_by_policy"; @@ -228,9 +230,18 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); + Handler handler = getHandler(); + if (handler == null) { + Log.e(TAG, + "Received intent, but handler is null - still attached to window? Window " + + "token: " + + getWindowToken()); + return; + } + if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); - getHandler().post(() -> { + handler.post(() -> { mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz)); if (mClockFormat != null) { mClockFormat.setTimeZone(mCalendar.getTimeZone()); @@ -238,14 +249,14 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C }); } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { final Locale newLocale = getResources().getConfiguration().locale; - getHandler().post(() -> { + handler.post(() -> { if (!newLocale.equals(mLocale)) { mLocale = newLocale; mClockFormatString = ""; // force refresh } }); } - getHandler().post(() -> updateClock()); + handler.post(() -> updateClock()); } }; -- GitLab From a5fb0829d5aae26a5164fb132838a451d4cf8214 Mon Sep 17 00:00:00 2001 From: Dmitry Dementyev Date: Fri, 13 Dec 2019 16:19:50 -0800 Subject: [PATCH 064/143] Remove hidden shared account methods from AccountManager.java Bug: 145207098,145206763,145206842 Test: CTS Change-Id: I0d07e0e6c4377eff5756ee938c5b43ad632249df (cherry picked from commit b6907622f78a09966c14bc753ff48753eb3d8b76) --- .../java/android/accounts/AccountManager.java | 29 ------------------- .../android/accounts/IAccountManager.aidl | 3 -- .../accounts/AccountManagerService.java | 3 -- 3 files changed, 35 deletions(-) diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index f4e465ab3adb..0f10c3980021 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -1942,35 +1942,6 @@ public class AccountManager { }.start(); } - /** - * @hide - * Removes the shared account. - * @param account the account to remove - * @param user the user to remove the account from - * @return - */ - public boolean removeSharedAccount(final Account account, UserHandle user) { - try { - boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier()); - return val; - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } - - /** - * @hide - * @param user - * @return - */ - public Account[] getSharedAccounts(UserHandle user) { - try { - return mService.getSharedAccountsAsUser(user.getIdentifier()); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } - /** * Confirms that the user knows the password for an account to make extra * sure they are the owner of the account. The user-entered password can diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 4cf0a2089fe5..012713891d11 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -80,14 +80,11 @@ interface IAccountManager { String authTokenType); /* Shared accounts */ - Account[] getSharedAccountsAsUser(int userId); - boolean removeSharedAccountAsUser(in Account account, int userId); void addSharedAccountsFromParentUser(int parentUserId, int userId, String opPackageName); /* Account renaming. */ void renameAccount(in IAccountManagerResponse response, in Account accountToRename, String newName); String getPreviousName(in Account account); - boolean renameSharedAccountAsUser(in Account accountToRename, String newName, int userId); /* Add account in two steps. */ void startAddAccountSession(in IAccountManagerResponse response, String accountType, diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 0d2882216f08..c732521bb7cd 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4404,7 +4404,6 @@ public class AccountManagerService return true; } - @Override public boolean renameSharedAccountAsUser(Account account, String newName, int userId) { userId = handleIncomingUser(userId); UserAccounts accounts = getUserAccounts(userId); @@ -4420,7 +4419,6 @@ public class AccountManagerService return r > 0; } - @Override public boolean removeSharedAccountAsUser(Account account, int userId) { return removeSharedAccountAsUser(account, userId, getCallingUid()); } @@ -4438,7 +4436,6 @@ public class AccountManagerService return deleted; } - @Override public Account[] getSharedAccountsAsUser(int userId) { userId = handleIncomingUser(userId); UserAccounts accounts = getUserAccounts(userId); -- GitLab From 874c974f73839da761177a4e0a53b7f4a7d29288 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Mon, 3 Feb 2020 18:35:13 -0800 Subject: [PATCH 065/143] DO NOT MERGE - Kill apps outright for API contract violations ...rather than relying on in-app code to perform the shutdown. Backport of security fix. Bug: 128649910 Bug: 140108616 Test: manual Test: atest OsHostTests#testForegroundServiceBadNotification Change-Id: I94d9de50bb03c33666471e3dbd9c721e9278f7cb Merged-In: I94d9de50bb03c33666471e3dbd9c721e9278f7cb --- core/java/android/app/IActivityManager.aidl | 3 ++- .../com/android/server/am/ActiveServices.java | 12 ++++++++- .../server/am/ActivityManagerService.java | 5 ++-- .../am/ActivityManagerShellCommand.java | 2 +- .../java/com/android/server/am/AppErrors.java | 26 ++++++++++++++----- .../com/android/server/am/ServiceRecord.java | 7 +++-- .../NotificationManagerService.java | 23 +++++++++------- 7 files changed, 53 insertions(+), 25 deletions(-) diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 18117481b0ea..d29a332ae197 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -266,7 +266,8 @@ interface IActivityManager { boolean isImmersive(in IBinder token); void setImmersive(in IBinder token, boolean immersive); boolean isTopActivityImmersive(); - void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message); + void crashApplication(int uid, int initialPid, in String packageName, int userId, + in String message, boolean force); String getProviderMimeType(in Uri uri, int userId); IBinder newUriPermissionOwner(in String name); void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg, diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 9d823a726afe..8e0bf6fada37 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -653,6 +653,15 @@ public final class ActiveServices { } } + void killMisbehavingService(ServiceRecord r, + int appUid, int appPid, String localPackageName) { + synchronized (mAm) { + stopServiceLocked(r); + mAm.crashApplication(appUid, appPid, localPackageName, -1, + "Bad notification for startForeground", true /*force*/); + } + } + IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) { ServiceLookupResult r = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), @@ -3391,7 +3400,8 @@ public final class ActiveServices { void serviceForegroundCrash(ProcessRecord app) { mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId, - "Context.startForegroundService() did not then call Service.startForeground()"); + "Context.startForegroundService() did not then call Service.startForeground()", + false /*force*/); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b4c18b13947c..0d9fc03208db 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5141,7 +5141,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void crashApplication(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: crashApplication() from pid=" @@ -5153,7 +5153,8 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message); + mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, + message, force); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 8488e526eba9..9575fddf04f2 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -921,7 +921,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } catch (NumberFormatException e) { packageName = arg; } - mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash"); + mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false); return 0; } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index a842724c3177..a7954bbd624d 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -243,20 +243,24 @@ class AppErrors { } void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) { - app.crashing = false; - app.crashingReport = null; - app.notResponding = false; - app.notRespondingReport = null; if (app.anrDialog == fromDialog) { app.anrDialog = null; } if (app.waitDialog == fromDialog) { app.waitDialog = null; } + killAppImmediateLocked(app, "user-terminated", "user request after error"); + } + + private void killAppImmediateLocked(ProcessRecord app, String reason, String killReason) { + app.crashing = false; + app.crashingReport = null; + app.notResponding = false; + app.notRespondingReport = null; if (app.pid > 0 && app.pid != MY_PID) { - handleAppCrashLocked(app, "user-terminated" /*reason*/, + handleAppCrashLocked(app, reason, null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); - app.kill("user request after error", true); + app.kill(killReason, true); } } @@ -270,7 +274,7 @@ class AppErrors { * @param message */ void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { ProcessRecord proc = null; // Figure out which process to kill. We don't trust that initialPid @@ -303,6 +307,14 @@ class AppErrors { } proc.scheduleCrash(message); + if (force) { + // If the app is responsive, the scheduled crash will happen as expected + // and then the delayed summary kill will be a no-op. + final ProcessRecord p = proc; + mService.mHandler.postDelayed( + () -> killAppImmediateLocked(p, "forced", "killed for invalid state"), + 5000L); + } } /** diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 16995e50fdbf..f87ba716926e 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -453,6 +453,7 @@ final class ServiceRecord extends Binder { final String localPackageName = packageName; final int localForegroundId = foregroundId; final Notification _foregroundNoti = foregroundNoti; + final ServiceRecord record = this; ams.mHandler.post(new Runnable() { public void run() { NotificationManagerInternal nm = LocalServices.getService( @@ -551,10 +552,8 @@ final class ServiceRecord extends Binder { Slog.w(TAG, "Error showing notification for service", e); // If it gave us a garbage notification, it doesn't // get to be foreground. - ams.setServiceForeground(name, ServiceRecord.this, - 0, null, 0); - ams.crashApplication(appUid, appPid, localPackageName, -1, - "Bad notification for startForeground: " + e); + ams.mServices.killMisbehavingService(record, + appUid, appPid, localPackageName); } } }); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 5df6083bb223..797ce37af560 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -714,18 +714,23 @@ public class NotificationManagerService extends SystemService { @Override public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, int uid, int initialPid, String message, int userId) { - Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id - + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); + final boolean fgService; + synchronized (mNotificationLock) { + NotificationRecord r = findNotificationLocked(pkg, tag, id, userId); + fgService = r != null + && (r.getNotification().flags&Notification.FLAG_FOREGROUND_SERVICE) != 0; + } cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, REASON_ERROR, null); - long ident = Binder.clearCallingIdentity(); - try { - ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1, - "Bad notification posted from package " + pkg - + ": " + message); - } catch (RemoteException e) { + if (fgService) { + // Still crash for foreground services, preventing the not-crash behaviour abused + // by apps to give us a garbage notification and silently start a fg service. + Binder.withCleanCallingIdentity( + () -> mAm.crashApplication(uid, initialPid, pkg, -1, + "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " + + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " + + message, true /* force */)); } - Binder.restoreCallingIdentity(ident); } @Override -- GitLab From f656f6d2c1f3ff50b2c4c71d04c1b0924d176c08 Mon Sep 17 00:00:00 2001 From: Wilson Wu Date: Thu, 26 Dec 2019 16:17:56 +0800 Subject: [PATCH 066/143] Use the main thread to update alignment indication The alignment status is reported from WLC-HAL level and runs on another thread. It may cause CalledFromWrongThreadException, if use that thread to update UI directly. Bug: 146770234 Test: atest SystemUITests:KeyguardIndicationControllerTest Change-Id: I89bf1c188d6ba094106e059f1590c9eaf3703bb8 (cherry picked from commit 0e72713fdf3e065ec4d1e8ca5c4f14dfcc74ebb6) Merged-In: I89bf1c188d6ba094106e059f1590c9eaf3703bb8 --- .../KeyguardIndicationController.java | 3 +- .../KeyguardIndicationControllerTest.java | 50 +++++++++++-------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 8ee7305d99c5..4256976249b1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -166,7 +166,8 @@ public class KeyguardIndicationController implements StateListener, mStatusBarStateController = statusBarStateController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mDockManager = dockManager; - mDockManager.addAlignmentStateListener(this::handleAlignStateChanged); + mDockManager.addAlignmentStateListener( + alignState -> mHandler.post(() -> handleAlignStateChanged(alignState))); // lock icon is not used on all form factors. if (mLockIcon != null) { mLockIcon.setOnLongClickListener(this::handleLockLongClick); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java index 2fe51d35c490..8592fd1e9be2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java @@ -223,12 +223,14 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void onAlignmentStateChanged_showsSlowChargingIndication() { - createController(); - verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); - mController.setVisible(true); + mInstrumentation.runOnMainSync(() -> { + createController(); + verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); + mController.setVisible(true); - mAlignmentListener.getValue().onAlignmentStateChanged( - DockManager.ALIGN_STATE_POOR); + mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR); + }); + mInstrumentation.waitForIdleSync(); assertThat(mTextView.getText()).isEqualTo( mContext.getResources().getString(R.string.dock_alignment_slow_charging)); @@ -238,11 +240,14 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void onAlignmentStateChanged_showsNotChargingIndication() { - createController(); - verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); - mController.setVisible(true); + mInstrumentation.runOnMainSync(() -> { + createController(); + verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); + mController.setVisible(true); - mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE); + mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE); + }); + mInstrumentation.waitForIdleSync(); assertThat(mTextView.getText()).isEqualTo( mContext.getResources().getString(R.string.dock_alignment_not_charging)); @@ -252,13 +257,15 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void onAlignmentStateChanged_whileDozing_showsSlowChargingIndication() { - createController(); - verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); - mController.setVisible(true); - mController.setDozing(true); + mInstrumentation.runOnMainSync(() -> { + createController(); + verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); + mController.setVisible(true); + mController.setDozing(true); - mAlignmentListener.getValue().onAlignmentStateChanged( - DockManager.ALIGN_STATE_POOR); + mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_POOR); + }); + mInstrumentation.waitForIdleSync(); assertThat(mTextView.getText()).isEqualTo( mContext.getResources().getString(R.string.dock_alignment_slow_charging)); @@ -268,12 +275,15 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { @Test public void onAlignmentStateChanged_whileDozing_showsNotChargingIndication() { - createController(); - verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); - mController.setVisible(true); - mController.setDozing(true); + mInstrumentation.runOnMainSync(() -> { + createController(); + verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture()); + mController.setVisible(true); + mController.setDozing(true); - mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE); + mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE); + }); + mInstrumentation.waitForIdleSync(); assertThat(mTextView.getText()).isEqualTo( mContext.getResources().getString(R.string.dock_alignment_not_charging)); -- GitLab From 85382ce4d285d251cdc4643bb65cef5289034bc3 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 14 Jan 2020 10:09:36 -0800 Subject: [PATCH 067/143] Disabled some DEBUG constants. Bug: 138939803 Bug: 142965266 Bug: 148457657 Test: echo 'in TH we trust!' Change-Id: Ie3112fa1965d9b03bc142924ca17cf27dd6aa44d (cherry picked from commit e966b8e76d26283163721620528eea0bfd77b43c) --- core/java/android/app/DisabledWallpaperManager.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/java/android/app/DisabledWallpaperManager.java b/core/java/android/app/DisabledWallpaperManager.java index 518594191e6c..7151f900c5af 100644 --- a/core/java/android/app/DisabledWallpaperManager.java +++ b/core/java/android/app/DisabledWallpaperManager.java @@ -41,8 +41,7 @@ final class DisabledWallpaperManager extends WallpaperManager { // Don't need to worry about synchronization private static DisabledWallpaperManager sInstance; - // TODO(b/138939803): STOPSHIP changed to false and/or remove it - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; @NonNull static DisabledWallpaperManager getInstance() { @@ -66,10 +65,6 @@ final class DisabledWallpaperManager extends WallpaperManager { return false; } - // TODO(b/138939803): STOPSHIP methods below should not be necessary, - // callers should check if isWallpaperSupported(), consider removing them to keep this class - // simpler - private static T unsupported() { if (DEBUG) Log.w(TAG, "unsupported method called; returning null", new Exception()); return null; -- GitLab From a0e531aa71b49d8d696fb9b73559833a76890710 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Tue, 2 Jul 2019 09:45:58 -0400 Subject: [PATCH 068/143] Fix flaky sysui crash in devicehealthchecks test. Upgrade tuner on the main thread to avoid ConcurrentModificationException. Fixes: 133847620 Bug: 148794872 Test: mp droid Change-Id: I15ef66a19eeac2c6baf652d83e6a90669834f203 Merged-In: I15ef66a19eeac2c6baf652d83e6a90669834f203 --- .../com/android/systemui/tuner/TunerServiceImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java index 6185063e7966..aa4dcc0ca2ae 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java @@ -15,7 +15,7 @@ */ package com.android.systemui.tuner; -import static com.android.systemui.Dependency.BG_HANDLER_NAME; +import static com.android.systemui.Dependency.MAIN_HANDLER_NAME; import android.app.ActivityManager; import android.content.ContentResolver; @@ -82,7 +82,7 @@ public class TunerServiceImpl extends TunerService { /** */ @Inject - public TunerServiceImpl(Context context, @Named(BG_HANDLER_NAME) Handler bgHandler, + public TunerServiceImpl(Context context, @Named(MAIN_HANDLER_NAME) Handler mainHandler, LeakDetector leakDetector) { mContext = context; mContentResolver = mContext.getContentResolver(); @@ -91,7 +91,7 @@ public class TunerServiceImpl extends TunerService { for (UserInfo user : UserManager.get(mContext).getUsers()) { mCurrentUser = user.getUserHandle().getIdentifier(); if (getValue(TUNER_VERSION, 0) != CURRENT_TUNER_VERSION) { - upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION, bgHandler); + upgradeTuner(getValue(TUNER_VERSION, 0), CURRENT_TUNER_VERSION, mainHandler); } } @@ -112,7 +112,7 @@ public class TunerServiceImpl extends TunerService { mUserTracker.stopTracking(); } - private void upgradeTuner(int oldVersion, int newVersion, Handler bgHandler) { + private void upgradeTuner(int oldVersion, int newVersion, Handler mainHandler) { if (oldVersion < 1) { String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST); if (blacklistStr != null) { @@ -134,7 +134,7 @@ public class TunerServiceImpl extends TunerService { if (oldVersion < 4) { // Delay this so that we can wait for everything to be registered first. final int user = mCurrentUser; - bgHandler.postDelayed( + mainHandler.postDelayed( () -> clearAllFromUser(user), 5000); } setValue(TUNER_VERSION, newVersion); -- GitLab From f8c0b315240c5949fbbe755af1c2a2e4006e7210 Mon Sep 17 00:00:00 2001 From: Yan Zhu Date: Wed, 11 Dec 2019 09:14:44 -0800 Subject: [PATCH 069/143] DO NOT MERGE - Enable blacklist for headless system user - Get all packages for system user - Reuse split system user's logic to blacklist packages when headless system user is enabled - Add new method in UserManager to get headless sytem user mode (same as in master) Bug: 145626101 Test: edit device's sysconfig file, use tag: system-user-blacklisted-app to blacklist app make services && adb sync system && adb reboot cts test Change-Id: I98d1bc33e7dd59ffa3ac6426f95af708671138da (cherry picked from commit 9c4cf4945d57d45e429bc7d33bf6ffa68eb0838c) --- core/java/android/os/UserManager.java | 10 ++++ .../server/pm/PackageManagerService.java | 47 +++++++++++-------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 45842926ff1d..da41478e91a6 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1274,6 +1274,16 @@ public class UserManager { return RoSystemProperties.FW_SYSTEM_USER_SPLIT; } + /** + * @hide + * @return Whether the device is running in a headless system user mode. It means the headless + * user (system user) runs system services and system UI, but is not associated with any real + * person. Secondary users can be created to be associated with real person. + */ + public static boolean isHeadlessSystemUserMode() { + return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; + } + /** * @return Whether guest user is always ephemeral * @hide diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ca66776239db..fc43dc3a2016 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2321,32 +2321,41 @@ public class PackageManagerService extends IPackageManager.Stub } private void enableSystemUserPackages() { - if (!UserManager.isSplitSystemUser()) { + boolean isHeadlessSystemUserMode = UserManager.isHeadlessSystemUserMode(); + if (!isHeadlessSystemUserMode && !UserManager.isSplitSystemUser()) { return; } - // For system user, enable apps based on the following conditions: - // - app is whitelisted or belong to one of these groups: - // -- system app which has no launcher icons - // -- system app which has INTERACT_ACROSS_USERS permission - // -- system IME app - // - app is not in the blacklist - AppsQueryHelper queryHelper = new AppsQueryHelper(this); + Set enableApps = new ArraySet<>(); - enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS - | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM - | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM)); - ArraySet wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps(); - enableApps.addAll(wlApps); - enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER, - /* systemAppsOnly */ false, UserHandle.SYSTEM)); - ArraySet blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps(); - enableApps.removeAll(blApps); - Log.i(TAG, "Applications installed for system user: " + enableApps); + AppsQueryHelper queryHelper = new AppsQueryHelper(this); List allAps = queryHelper.queryApps(0, /* systemAppsOnly */ false, UserHandle.SYSTEM); + + if (isHeadlessSystemUserMode) { + enableApps.addAll(allAps); + } else { + // For split system user, select apps based on the following conditions: + // -- system app which has no launcher icons + // -- system app which has INTERACT_ACROSS_USERS permission + // -- system IME app + enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS + | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM + | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM)); + enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER, + /* systemAppsOnly */ false, UserHandle.SYSTEM)); + + // Apply whitelist for split system user + ArraySet wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps(); + enableApps.addAll(wlApps); + } + // Apply blacklist for split system user/headless system user + ArraySet blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps(); + enableApps.removeAll(blApps); + Log.i(TAG, "Blacklisted packages: " + blApps); + final int allAppsSize = allAps.size(); synchronized (mPackages) { - for (int i = 0; i < allAppsSize; i++) { + for (int i = 0; i < allAppsSize; i++) { String pName = allAps.get(i); PackageSetting pkgSetting = mSettings.mPackages.get(pName); // Should not happen, but we shouldn't be failing if it does -- GitLab From 81ce02f510b18974ade9ac5a377426e5ceba7f72 Mon Sep 17 00:00:00 2001 From: Yan Zhu Date: Tue, 17 Dec 2019 14:00:16 -0800 Subject: [PATCH 070/143] DO NOT MERGE - Add flag to turn on/off the headless user specific blacklist/whitelist Bug: 145626101 Test: manual: set config_systemUserPackagesBlacklistSupported build and flash Verify with: 1. adb shell dumpsys package packages 2. adb logcat | grep "blacklist" Change-Id: I5b45fc86e4c5008933bf361d5bb32a2c17259655 (cherry picked from commit d1c59ec220e95f881feefb55eb099b6f602d4e05) --- core/res/res/values/config.xml | 3 +++ core/res/res/values/symbols.xml | 1 + .../server/pm/PackageManagerService.java | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 10c727154814..12058c15458e 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1692,6 +1692,9 @@ This feature should be disabled for most devices. --> 0 + + false + false + true + + + com.android.server.location.ComprehensiveCountryDetector diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 29f90fb192c5..1c387baf7826 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3689,6 +3689,8 @@ + + diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java index 861c731c69e0..b0132d35fa3b 100644 --- a/services/core/java/com/android/server/CountryDetectorService.java +++ b/services/core/java/com/android/server/CountryDetectorService.java @@ -24,21 +24,29 @@ import android.location.ICountryListener; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; +import android.text.TextUtils; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.location.ComprehensiveCountryDetector; +import com.android.server.location.CountryDetectorBase; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; /** - * This class detects the country that the user is in through {@link ComprehensiveCountryDetector}. + * This class detects the country that the user is in. The default country detection is made through + * {@link com.android.server.location.ComprehensiveCountryDetector}. It is possible to overlay the + * detection algorithm by overlaying the attribute R.string.config_customCountryDetector with the + * custom class name to use instead. The custom class must extend + * {@link com.android.server.location.CountryDetectorBase} * * @hide */ @@ -88,7 +96,7 @@ public class CountryDetectorService extends ICountryDetector.Stub { private final HashMap mReceivers; private final Context mContext; - private ComprehensiveCountryDetector mCountryDetector; + private CountryDetectorBase mCountryDetector; private boolean mSystemReady; private Handler mHandler; private CountryListener mLocationBasedDetectorListener; @@ -184,8 +192,17 @@ public class CountryDetectorService extends ICountryDetector.Stub { }); } - private void initialize() { - mCountryDetector = new ComprehensiveCountryDetector(mContext); + @VisibleForTesting + void initialize() { + final String customCountryClass = mContext.getString(R.string.config_customCountryDetector); + if (!TextUtils.isEmpty(customCountryClass)) { + mCountryDetector = loadCustomCountryDetectorIfAvailable(customCountryClass); + } + + if (mCountryDetector == null) { + Slog.d(TAG, "Using default country detector"); + mCountryDetector = new ComprehensiveCountryDetector(mContext); + } mLocationBasedDetectorListener = country -> mHandler.post(() -> notifyReceivers(country)); } @@ -193,11 +210,33 @@ public class CountryDetectorService extends ICountryDetector.Stub { mHandler.post(() -> mCountryDetector.setCountryListener(listener)); } + @VisibleForTesting + CountryDetectorBase getCountryDetector() { + return mCountryDetector; + } + @VisibleForTesting boolean isSystemReady() { return mSystemReady; } + private CountryDetectorBase loadCustomCountryDetectorIfAvailable( + final String customCountryClass) { + CountryDetectorBase customCountryDetector = null; + + Slog.d(TAG, "Using custom country detector class: " + customCountryClass); + try { + customCountryDetector = Class.forName(customCountryClass).asSubclass( + CountryDetectorBase.class).getConstructor(Context.class).newInstance( + mContext); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | NoSuchMethodException | InvocationTargetException e) { + Slog.e(TAG, "Could not instantiate the custom country detector class"); + } + + return customCountryDetector; + } + @SuppressWarnings("unused") @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { @@ -206,9 +245,10 @@ public class CountryDetectorService extends ICountryDetector.Stub { try { final Printer p = new PrintWriterPrinter(fout); p.println("CountryDetectorService state:"); + p.println("Country detector class=" + mCountryDetector.getClass().getName()); p.println(" Number of listeners=" + mReceivers.keySet().size()); if (mCountryDetector == null) { - p.println(" ComprehensiveCountryDetector not initialized"); + p.println(" CountryDetector not initialized"); } else { p.println(" " + mCountryDetector.toString()); } diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java index e9c5ce7127de..d5483ffa5445 100644 --- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java @@ -19,8 +19,11 @@ package com.android.server; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; import android.content.Context; +import android.content.res.Resources; import android.location.Country; import android.location.CountryListener; import android.location.ICountryListener; @@ -31,6 +34,10 @@ import android.os.RemoteException; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.R; +import com.android.server.location.ComprehensiveCountryDetector; +import com.android.server.location.CustomCountryDetectorTestClass; + import com.google.common.truth.Expect; import org.junit.Before; @@ -38,12 +45,18 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class CountryDetectorServiceTest { + private static final String VALID_CUSTOM_TEST_CLASS = + "com.android.server.location.CustomCountryDetectorTestClass"; + private static final String INVALID_CUSTOM_TEST_CLASS = + "com.android.server.location.MissingCountryDetectorTestClass"; + private static class CountryListenerTester extends ICountryListener.Stub { private Country mCountry; @@ -83,12 +96,11 @@ public class CountryDetectorServiceTest { } } - @Rule - public final Expect expect = Expect.create(); - @Spy - private Context mContext = ApplicationProvider.getApplicationContext(); - @Spy - private Handler mHandler = new Handler(Looper.myLooper()); + @Rule public final Expect expect = Expect.create(); + @Spy private Context mContext = ApplicationProvider.getApplicationContext(); + @Spy private Handler mHandler = new Handler(Looper.myLooper()); + @Mock private Resources mResources; + private CountryDetectorServiceTester mCountryDetectorService; @BeforeClass @@ -108,10 +120,12 @@ public class CountryDetectorServiceTest { message.getCallback().run(); return true; }).when(mHandler).sendMessageAtTime(any(Message.class), anyLong()); + + doReturn(mResources).when(mContext).getResources(); } @Test - public void countryListener_add_successful() throws RemoteException { + public void addCountryListener_validListener_listenerAdded() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); mCountryDetectorService.systemRunning(); @@ -122,7 +136,7 @@ public class CountryDetectorServiceTest { } @Test - public void countryListener_remove_successful() throws RemoteException { + public void removeCountryListener_validListener_listenerRemoved() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); mCountryDetectorService.systemRunning(); @@ -133,8 +147,31 @@ public class CountryDetectorServiceTest { expect.that(mCountryDetectorService.isListenerSet()).isFalse(); } + @Test(expected = RemoteException.class) + public void addCountryListener_serviceNotReady_throwsException() throws RemoteException { + CountryListenerTester countryListener = new CountryListenerTester(); + + expect.that(mCountryDetectorService.isSystemReady()).isFalse(); + mCountryDetectorService.addCountryListener(countryListener); + } + + @Test(expected = RemoteException.class) + public void removeCountryListener_serviceNotReady_throwsException() throws RemoteException { + CountryListenerTester countryListener = new CountryListenerTester(); + + expect.that(mCountryDetectorService.isSystemReady()).isFalse(); + mCountryDetectorService.removeCountryListener(countryListener); + } + @Test - public void countryListener_notify_successful() throws RemoteException { + public void detectCountry_serviceNotReady_returnNull() { + expect.that(mCountryDetectorService.isSystemReady()).isFalse(); + + expect.that(mCountryDetectorService.detectCountry()).isNull(); + } + + @Test + public void notifyReceivers_twoListenersRegistered_bothNotified() throws RemoteException { CountryListenerTester countryListenerA = new CountryListenerTester(); CountryListenerTester countryListenerB = new CountryListenerTester(); Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK); @@ -151,4 +188,26 @@ public class CountryDetectorServiceTest { expect.that(countryListenerA.getCountry().equalsIgnoreSource(country)).isTrue(); expect.that(countryListenerB.getCountry().equalsIgnoreSource(country)).isTrue(); } + + @Test + public void initialize_deviceWithCustomDetector_useCustomDetectorClass() { + when(mResources.getString(R.string.config_customCountryDetector)) + .thenReturn(VALID_CUSTOM_TEST_CLASS); + + mCountryDetectorService.initialize(); + + expect.that(mCountryDetectorService.getCountryDetector()) + .isInstanceOf(CustomCountryDetectorTestClass.class); + } + + @Test + public void initialize_deviceWithInvalidCustomDetector_useDefaultDetector() { + when(mResources.getString(R.string.config_customCountryDetector)) + .thenReturn(INVALID_CUSTOM_TEST_CLASS); + + mCountryDetectorService.initialize(); + + expect.that(mCountryDetectorService.getCountryDetector()) + .isInstanceOf(ComprehensiveCountryDetector.class); + } } diff --git a/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java b/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java new file mode 100644 index 000000000000..e159012f1b54 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import android.content.Context; +import android.location.Country; + +public class CustomCountryDetectorTestClass extends CountryDetectorBase { + public CustomCountryDetectorTestClass(Context ctx) { + super(ctx); + } + + @Override + public Country detectCountry() { + return null; + } + + @Override + public void stop() { + + } +} -- GitLab From d445aaf1e2e4c9e98f03d0726cd513a34952a693 Mon Sep 17 00:00:00 2001 From: kwaky Date: Wed, 5 Feb 2020 12:51:46 -0800 Subject: [PATCH 074/143] Add null check for voiceInteractorComponentName. Voice Assistant can be disabled on a user-level. Adding this null check prevents crash for when Assistant is enabled for the system in general but disabled for a specific user. Bug: 149112015 Test: Manual -- Change config_disableLockscreenByDefault to true to emulate the environment in which Volvo observed the bug. Verify that switching to user0 through adb shell switch-user 0 causes the same crash. Verify that the crash does not happen with the new null check. Change-Id: I5b8ede1e5bd8c1bc047bc6d6220b425dea8f50ea Merged-in: I5b8ede1e5bd8c1bc047bc6d6220b425dea8f50ea --- .../systemui/statusbar/phone/KeyguardBottomAreaView.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 80d36a1a4e54..c3244a4431d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -641,9 +641,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL if (previewBefore != null) { mPreviewContainer.removeView(previewBefore); } - if (mLeftIsVoiceAssist) { - mLeftPreview = mPreviewInflater.inflatePreviewFromService( - mAssistManager.getVoiceInteractorComponentName()); + ComponentName voiceInteractorComponentName = + mAssistManager.getVoiceInteractorComponentName(); + if (mLeftIsVoiceAssist && voiceInteractorComponentName != null) { + mLeftPreview = mPreviewInflater.inflatePreviewFromService(voiceInteractorComponentName); } else { mLeftPreview = mPreviewInflater.inflatePreview(mLeftButton.getIntent()); } -- GitLab From 6073f3c58b4b7585bc446c49cb1fa86f438d307c Mon Sep 17 00:00:00 2001 From: kwaky Date: Thu, 6 Feb 2020 13:45:57 -0800 Subject: [PATCH 075/143] DO NOT MERGE Adjust NotificationView bottom margin based on whether Keyboard is shown. If the Keyboard is shown, then margin bottom is 0. Otherwise, the margin is the height of the NavBar. Bug: 149022190 Test: Manual. Verify that NotificationView's margin adjusts based on whether keyboard or IME is shown. Change-Id: I96c50a4d773dfac9b57ab1c15cfc59d315da4605 --- .../res/layout/notification_center_activity.xml | 3 ++- .../com/android/systemui/statusbar/car/CarStatusBar.java | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/CarSystemUI/res/layout/notification_center_activity.xml b/packages/CarSystemUI/res/layout/notification_center_activity.xml index 0af74c4462a6..e5cc08a3b601 100644 --- a/packages/CarSystemUI/res/layout/notification_center_activity.xml +++ b/packages/CarSystemUI/res/layout/notification_center_activity.xml @@ -20,7 +20,8 @@ android:id="@+id/notification_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/notification_shade_background_color"> + android:background="@color/notification_shade_background_color" + android:visibility="invisible"> Date: Tue, 17 Dec 2019 00:33:18 +0800 Subject: [PATCH 076/143] Remove framework code that has moved to frameworks/libs/net Add srcs to framework and change import path. Remove the codes which are moved to frameworks/libs/net. Bug: 139268426 Bug: 135998869 Bug: 138306002 Bug: 143925787 Test: atest FrameworksNetTests atest FrameworksTelephonyTests atest ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I067cdc404e5a63947c19cb75069a39ae42faa3c8 Merged-In: Ieb8927f9af7f87a5ae038bd6c7daeb3d70117fef --- core/java/android/net/LinkProperties.java | 76 ++---------------- core/java/android/net/MacAddress.java | 79 ++----------------- core/java/android/net/NetworkUtils.java | 10 --- core/java/android/net/RouteInfo.java | 17 +--- .../android/server/ConnectivityService.java | 2 +- .../java/android/net/LinkPropertiesTest.java | 2 +- .../net/java/android/net/MacAddressTest.java | 12 +-- .../android/net/wifi/WifiConfiguration.java | 5 +- .../net/wifi/WifiConfigurationTest.java | 6 +- 9 files changed, 31 insertions(+), 178 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index d25ee0e69e88..732ceb560cab 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -21,6 +21,8 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; +import android.net.util.LinkPropertiesUtils; +import android.net.util.LinkPropertiesUtils.CompareResult; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -90,36 +92,6 @@ public final class LinkProperties implements Parcelable { // Indexed by interface name to allow modification and to prevent duplicates being added. private Hashtable mStackedLinks = new Hashtable<>(); - /** - * @hide - */ - public static class CompareResult { - public final List removed = new ArrayList<>(); - public final List added = new ArrayList<>(); - - public CompareResult() {} - - public CompareResult(Collection oldItems, Collection newItems) { - if (oldItems != null) { - removed.addAll(oldItems); - } - if (newItems != null) { - for (T newItem : newItems) { - if (!removed.remove(newItem)) { - added.add(newItem); - } - } - } - } - - @Override - public String toString() { - return "removed=[" + TextUtils.join(",", removed) - + "] added=[" + TextUtils.join(",", added) - + "]"; - } - } - /** * @hide */ @@ -1326,7 +1298,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) { - return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); + return LinkPropertiesUtils.isIdenticalInterfaceName(target, this); } /** @@ -1349,10 +1321,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalAddresses(@NonNull LinkProperties target) { - Collection targetAddresses = target.getAddresses(); - Collection sourceAddresses = getAddresses(); - return (sourceAddresses.size() == targetAddresses.size()) ? - sourceAddresses.containsAll(targetAddresses) : false; + return LinkPropertiesUtils.isIdenticalAddresses(target, this); } /** @@ -1364,15 +1333,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalDnses(@NonNull LinkProperties target) { - Collection targetDnses = target.getDnsServers(); - String targetDomains = target.getDomains(); - if (mDomains == null) { - if (targetDomains != null) return false; - } else { - if (!mDomains.equals(targetDomains)) return false; - } - return (mDnses.size() == targetDnses.size()) ? - mDnses.containsAll(targetDnses) : false; + return LinkPropertiesUtils.isIdenticalDnses(target, this); } /** @@ -1425,9 +1386,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage public boolean isIdenticalRoutes(@NonNull LinkProperties target) { - Collection targetRoutes = target.getRoutes(); - return (mRoutes.size() == targetRoutes.size()) ? - mRoutes.containsAll(targetRoutes) : false; + return LinkPropertiesUtils.isIdenticalRoutes(target, this); } /** @@ -1439,8 +1398,7 @@ public final class LinkProperties implements Parcelable { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) { - return getHttpProxy() == null ? target.getHttpProxy() == null : - getHttpProxy().equals(target.getHttpProxy()); + return LinkPropertiesUtils.isIdenticalHttpProxy(target, this); } /** @@ -1662,26 +1620,6 @@ public final class LinkProperties implements Parcelable { && isIdenticalCaptivePortalData(target); } - /** - * Compares the addresses in this LinkProperties with another - * LinkProperties, examining only addresses on the base link. - * - * @param target a LinkProperties with the new list of addresses - * @return the differences between the addresses. - * @hide - */ - public @NonNull CompareResult compareAddresses(@Nullable LinkProperties target) { - /* - * Duplicate the LinkAddresses into removed, we will be removing - * address which are common between mLinkAddresses and target - * leaving the addresses that are different. And address which - * are in target but not in mLinkAddresses are placed in the - * addedAddresses. - */ - return new CompareResult<>(mLinkAddresses, - target != null ? target.getLinkAddresses() : null); - } - /** * Compares the DNS addresses in this LinkProperties with another * LinkProperties, examining only DNS addresses on the base link. diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 74c9aac05b41..0e10c42e61db 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -20,11 +20,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.net.util.MacAddressUtils; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.util.BitUtils; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -33,7 +33,6 @@ import java.net.Inet6Address; import java.net.UnknownHostException; import java.security.SecureRandom; import java.util.Arrays; -import java.util.Random; /** * Representation of a MAC address. @@ -109,20 +108,12 @@ public final class MacAddress implements Parcelable { if (equals(BROADCAST_ADDRESS)) { return TYPE_BROADCAST; } - if (isMulticastAddress()) { + if ((mAddr & MULTICAST_MASK) != 0) { return TYPE_MULTICAST; } return TYPE_UNICAST; } - /** - * @return true if this MacAddress is a multicast address. - * @hide - */ - public boolean isMulticastAddress() { - return (mAddr & MULTICAST_MASK) != 0; - } - /** * @return true if this MacAddress is a locally assigned address. */ @@ -192,7 +183,7 @@ public final class MacAddress implements Parcelable { * @hide */ public static boolean isMacAddress(byte[] addr) { - return addr != null && addr.length == ETHER_ADDR_LEN; + return MacAddressUtils.isMacAddress(addr); } /** @@ -261,26 +252,11 @@ public final class MacAddress implements Parcelable { } private static byte[] byteAddrFromLongAddr(long addr) { - byte[] bytes = new byte[ETHER_ADDR_LEN]; - int index = ETHER_ADDR_LEN; - while (index-- > 0) { - bytes[index] = (byte) addr; - addr = addr >> 8; - } - return bytes; + return MacAddressUtils.byteAddrFromLongAddr(addr); } private static long longAddrFromByteAddr(byte[] addr) { - Preconditions.checkNotNull(addr); - if (!isMacAddress(addr)) { - throw new IllegalArgumentException( - Arrays.toString(addr) + " was not a valid MAC address"); - } - long longAddr = 0; - for (byte b : addr) { - longAddr = (longAddr << 8) + BitUtils.uint8(b); - } - return longAddr; + return MacAddressUtils.longAddrFromByteAddr(addr); } // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr)) @@ -350,50 +326,7 @@ public final class MacAddress implements Parcelable { * @hide */ public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() { - return createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); - } - - /** - * Returns a generated MAC address whose 46 bits, excluding the locally assigned bit and the - * unicast bit, are randomly selected. - * - * The locally assigned bit is always set to 1. The multicast bit is always set to 0. - * - * @return a random locally assigned, unicast MacAddress. - * - * @hide - */ - public static @NonNull MacAddress createRandomUnicastAddress() { - return createRandomUnicastAddress(null, new SecureRandom()); - } - - /** - * Returns a randomly generated MAC address using the given Random object and the same - * OUI values as the given MacAddress. - * - * The locally assigned bit is always set to 1. The multicast bit is always set to 0. - * - * @param base a base MacAddress whose OUI is used for generating the random address. - * If base == null then the OUI will also be randomized. - * @param r a standard Java Random object used for generating the random address. - * @return a random locally assigned MacAddress. - * - * @hide - */ - public static @NonNull MacAddress createRandomUnicastAddress(MacAddress base, Random r) { - long addr; - if (base == null) { - addr = r.nextLong() & VALID_LONG_MASK; - } else { - addr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()); - } - addr |= LOCALLY_ASSIGNED_MASK; - addr &= ~MULTICAST_MASK; - MacAddress mac = new MacAddress(addr); - if (mac.equals(DEFAULT_MAC_ADDRESS)) { - return createRandomUnicastAddress(base, r); - } - return mac; + return MacAddressUtils.createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom()); } // Convenience function for working around the lack of byte literals. diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 08cc4e24b245..779f7bc91e8f 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -31,7 +31,6 @@ import android.util.Pair; import java.io.FileDescriptor; import java.math.BigInteger; import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; @@ -312,15 +311,6 @@ public class NetworkUtils { return new Pair(address, prefixLength); } - /** - * Check if IP address type is consistent between two InetAddress. - * @return true if both are the same type. False otherwise. - */ - public static boolean addressTypeMatches(InetAddress left, InetAddress right) { - return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || - ((left instanceof Inet6Address) && (right instanceof Inet6Address))); - } - /** * Convert a 32 char hex string into a Inet6Address. * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 67bad532cd0d..2b9e9fe81b1b 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; +import android.net.util.NetUtils; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -483,21 +484,7 @@ public final class RouteInfo implements Parcelable { @UnsupportedAppUsage @Nullable public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { - if ((routes == null) || (dest == null)) return null; - - RouteInfo bestRoute = null; - // pick a longest prefix match under same address type - for (RouteInfo route : routes) { - if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { - if ((bestRoute != null) && - (bestRoute.mDestination.getPrefixLength() >= - route.mDestination.getPrefixLength())) { - continue; - } - if (route.matches(dest)) bestRoute = route; - } - } - return bestRoute; + return NetUtils.selectBestRoute(routes, dest); } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f06d50021288..376dd667bf38 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -89,7 +89,6 @@ import android.net.InetAddresses; import android.net.IpMemoryStore; import android.net.IpPrefix; import android.net.LinkProperties; -import android.net.LinkProperties.CompareResult; import android.net.MatchAllNetworkSpecifier; import android.net.NattSocketKeepalive; import android.net.Network; @@ -124,6 +123,7 @@ import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netlink.InetDiagMessage; import android.net.shared.PrivateDnsConfig; +import android.net.util.LinkPropertiesUtils.CompareResult; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; import android.os.Binder; diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index 3f311c951c7e..f25fd4daf829 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -27,8 +27,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.net.LinkProperties.CompareResult; import android.net.LinkProperties.ProvisioningChange; +import android.net.util.LinkPropertiesUtils.CompareResult; import android.system.OsConstants; import android.util.ArraySet; diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java index daf187d01533..91c9a2a38036 100644 --- a/tests/net/java/android/net/MacAddressTest.java +++ b/tests/net/java/android/net/MacAddressTest.java @@ -22,6 +22,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.net.util.MacAddressUtils; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -122,11 +124,11 @@ public class MacAddressTest { for (MacAddress mac : multicastAddresses) { String msg = mac.toString() + " expected to be a multicast address"; - assertTrue(msg, mac.isMulticastAddress()); + assertTrue(msg, MacAddressUtils.isMulticastAddress(mac)); } for (MacAddress mac : unicastAddresses) { String msg = mac.toString() + " expected not to be a multicast address"; - assertFalse(msg, mac.isMulticastAddress()); + assertFalse(msg, MacAddressUtils.isMulticastAddress(mac)); } } @@ -156,7 +158,7 @@ public class MacAddressTest { public void testMacAddressConversions() { final int iterations = 10000; for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddress.createRandomUnicastAddress(); + MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); String stringRepr = mac.toString(); byte[] bytesRepr = mac.toByteArray(); @@ -188,7 +190,7 @@ public class MacAddressTest { final String expectedLocalOui = "26:5f:78"; final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0"); for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddress.createRandomUnicastAddress(base, r); + MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r); String stringRepr = mac.toString(); assertTrue(stringRepr + " expected to be a locally assigned address", @@ -199,7 +201,7 @@ public class MacAddressTest { } for (int i = 0; i < iterations; i++) { - MacAddress mac = MacAddress.createRandomUnicastAddress(); + MacAddress mac = MacAddressUtils.createRandomUnicastAddress(); String stringRepr = mac.toString(); assertTrue(stringRepr + " expected to be a locally assigned address", diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 933dded815b9..ce49ab1208b0 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -28,6 +28,7 @@ import android.net.NetworkSpecifier; import android.net.ProxyInfo; import android.net.StaticIpConfiguration; import android.net.Uri; +import android.net.util.MacAddressUtils; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -1037,7 +1038,7 @@ public class WifiConfiguration implements Parcelable { * @return true if mac is good to use */ public static boolean isValidMacAddressForRandomization(MacAddress mac) { - return mac != null && !mac.isMulticastAddress() && mac.isLocallyAssigned() + return mac != null && !MacAddressUtils.isMulticastAddress(mac) && mac.isLocallyAssigned() && !MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS).equals(mac); } @@ -1051,7 +1052,7 @@ public class WifiConfiguration implements Parcelable { int randomMacGenerationCount = 0; while (!isValidMacAddressForRandomization(mRandomizedMacAddress) && randomMacGenerationCount < MAXIMUM_RANDOM_MAC_GENERATION_RETRY) { - mRandomizedMacAddress = MacAddress.createRandomUnicastAddress(); + mRandomizedMacAddress = MacAddressUtils.createRandomUnicastAddress(); randomMacGenerationCount++; } diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index ba9fc786afe7..f3e8351587bc 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import android.net.MacAddress; +import android.net.util.MacAddressUtils; import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.os.Parcel; @@ -62,7 +63,8 @@ public class WifiConfigurationTest { config.updateIdentifier = "1234"; config.fromWifiNetworkSpecifier = true; config.fromWifiNetworkSuggestion = true; - MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress(); + config.setRandomizedMacAddress(MacAddressUtils.createRandomUnicastAddress()); + MacAddress macBeforeParcel = config.getRandomizedMacAddress(); Parcel parcelW = Parcel.obtain(); config.writeToParcel(parcelW, 0); byte[] bytes = parcelW.marshall(); @@ -211,7 +213,7 @@ public class WifiConfigurationTest { MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); assertEquals(defaultMac, config.getRandomizedMacAddress()); - MacAddress macToChangeInto = MacAddress.createRandomUnicastAddress(); + MacAddress macToChangeInto = MacAddressUtils.createRandomUnicastAddress(); config.setRandomizedMacAddress(macToChangeInto); MacAddress macAfterChange = config.getRandomizedMacAddress(); -- GitLab From ec879fa0f2198aad607c9ef46e31d8f89c281059 Mon Sep 17 00:00:00 2001 From: Ahan Wu Date: Fri, 22 Nov 2019 15:54:56 +0800 Subject: [PATCH 077/143] Fix potential NPE while releasing worker thread of ImageWallpaper We nullify mWorker right in ImageWallpaper#destroy(), we might get NPE if postRender is invoked later. Thus, we add null check to avoid NPE. Bug: 144039509 Bug: 146167292 Test: atest com.android.systemui Test: atest CtsMultiUserHostTestCases Change-Id: I209673bdac7dcfee765006568583b5a9d6037b95 Merged-In: I243274af54538fc89268c448aa2c5a95f63c7ae3 --- .../src/com/android/systemui/ImageWallpaper.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index c0c14fb01222..319d1177622d 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -121,12 +121,13 @@ public class ImageWallpaper extends WallpaperService { @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { + if (mWorker == null) return; mWorker.getThreadHandler().post(() -> mRenderer.updateOffsets(xOffset, yOffset)); } @Override public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { - if (!mNeedTransition) return; + if (mWorker == null || !mNeedTransition) return; if (DEBUG) { Log.d(TAG, "onAmbientModeChanged: inAmbient=" + inAmbientMode + ", duration=" + animationDuration); @@ -174,6 +175,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceCreated(SurfaceHolder holder) { + if (mWorker == null) return; mWorker.getThreadHandler().post(() -> { mEglHelper.init(holder); mRenderer.onSurfaceCreated(); @@ -182,6 +184,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { + if (mWorker == null) return; mWorker.getThreadHandler().post(() -> { if (DEBUG) { Log.d(TAG, "onSurfaceChanged: w=" + width + ", h=" + height); @@ -194,6 +197,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceRedrawNeeded(SurfaceHolder holder) { + if (mWorker == null) return; mWorker.getThreadHandler().post(() -> { if (DEBUG) { Log.d(TAG, "onSurfaceRedrawNeeded: mNeedRedraw=" + mNeedRedraw); @@ -222,7 +226,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onStatePostChange() { // When back to home, we try to release EGL, which is preserved in lock screen or aod. - if (mController.getState() == StatusBarState.SHADE) { + if (mWorker != null && mController.getState() == StatusBarState.SHADE) { mWorker.getThreadHandler().post(this::scheduleFinishRendering); } } @@ -327,10 +331,12 @@ public class ImageWallpaper extends WallpaperService { } private void cancelFinishRenderingTask() { + if (mWorker == null) return; mWorker.getThreadHandler().removeCallbacks(mFinishRenderingTask); } private void scheduleFinishRendering() { + if (mWorker == null) return; cancelFinishRenderingTask(); mWorker.getThreadHandler().postDelayed(mFinishRenderingTask, DELAY_FINISH_RENDERING); } -- GitLab From c26e4fa64f75ee3224026a284741a197a1e1ed0c Mon Sep 17 00:00:00 2001 From: kwaky Date: Mon, 27 Jan 2020 16:03:19 -0800 Subject: [PATCH 078/143] Add vertical type check to prevent non-Automotive Androids from force displaying system bars. Force displaying system bars can cause app screen compatibility issues in non-Automotive Android. Bug: 148407132 Test: CTS Test + Unit Tests Change-Id: Ia433572650760e3b85954724c63084dca769eaa0 Merged-In: Ia433572650760e3b85954724c63084dca769eaa0 --- .../server/wm/WindowManagerService.java | 6 ++ services/tests/wmtests/AndroidManifest.xml | 1 + .../server/wm/WindowManagerServiceTests.java | 59 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f67b4fe78f58..529936a6c899 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -5702,6 +5702,12 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void setForceShowSystemBars(boolean show) { + boolean isAutomotive = mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE); + if (!isAutomotive) { + throw new UnsupportedOperationException("Force showing system bars is only supported" + + "for Automotive use cases."); + } if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Caller does not hold permission " diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 8c4544249b5c..123bb079dbbb 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -37,6 +37,7 @@ + Date: Tue, 18 Feb 2020 12:21:15 -0500 Subject: [PATCH 079/143] Add cutout support in QSDetail Add padding from cornerCutoutMargins. Test: manual on device with and without cutout Fixes: 147708367 Change-Id: I21a9b71c34664982b4e14dd4372638e405a5046e Merged-In: I665c8c76a2a057e9a30bce7c28fdbe7a249bb5c2 --- .../src/com/android/systemui/qs/QSDetail.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java index 496aa0e572ae..837f90ec23c6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java @@ -25,9 +25,12 @@ import android.content.Intent; import android.content.res.Configuration; import android.graphics.drawable.Animatable; import android.util.AttributeSet; +import android.util.Pair; import android.util.SparseArray; +import android.view.DisplayCutout; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.accessibility.AccessibilityEvent; import android.widget.ImageView; import android.widget.LinearLayout; @@ -42,6 +45,7 @@ import com.android.systemui.SysUiServiceProvider; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.PhoneStatusBarView; public class QSDetail extends LinearLayout { @@ -142,6 +146,25 @@ public class QSDetail extends LinearLayout { } } + @Override + public WindowInsets onApplyWindowInsets(WindowInsets insets) { + DisplayCutout cutout = insets.getDisplayCutout(); + Pair padding = PhoneStatusBarView.cornerCutoutMargins( + cutout, getDisplay()); + if (padding == null) { + mQsDetailHeader.setPaddingRelative( + getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding), + getPaddingTop(), + getResources().getDimensionPixelSize(R.dimen.qs_detail_header_padding), + getPaddingBottom() + ); + } else { + mQsDetailHeader.setPadding(padding.first, getPaddingTop(), + padding.second, getPaddingBottom()); + } + return super.onApplyWindowInsets(insets); + } + private void updateDetailText() { mDetailDoneButton.setText(R.string.quick_settings_done); mDetailSettingsButton.setText(R.string.quick_settings_more_settings); -- GitLab From 3cc9758323cb6779a02618cb9bf2015e7b4f9fba Mon Sep 17 00:00:00 2001 From: kwaky Date: Tue, 18 Feb 2020 14:52:10 -0800 Subject: [PATCH 080/143] DO NOT MERGE Reflect the selection state that reflects the current task stack upon restarting the Navigation Bar. Previously, while restarting the Navigation Bar, we omitted the step where we apply the selection state that reflects the current task stack. This omission caused CarFacetButtons to lose their selection state on certain events, such as the day/night toggle. Bug: 148211695 Test: Manual -- Verify that the selection state is preserved between day/night toggle. adb shell dumpsys activity service com.android.car/.CarService day-night-mode day adb shell dumpsys activity service com.android.car/.CarService day-night-mode night Change-Id: Ic07b8b66aa531436ce4f23d56bb3c11a79b7cb46 --- .../com/android/systemui/statusbar/car/CarStatusBar.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index e0f398742ebc..4e1f552f7f99 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -486,6 +486,15 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt // CarFacetButtonController was reset therefore we need to re-add the status bar elements // to the controller. mCarFacetButtonController.addAllFacetButtons(mStatusBarWindow); + + // Upon restarting the Navigation Bar, CarFacetButtonController should immediately apply the + // selection state that reflects the current task stack. + try { + mCarFacetButtonController.taskChanged( + ActivityTaskManager.getService().getAllStackInfos()); + } catch (Exception e) { + Log.e(TAG, "Getting StackInfo from activity manager failed", e); + } } private void addTemperatureViewToController(View v) { -- GitLab From 07af69531c817fda7f57a655f960cf00c73e71c6 Mon Sep 17 00:00:00 2001 From: Lin Guo Date: Sat, 15 Jun 2019 14:19:48 -0700 Subject: [PATCH 081/143] DO NOT MERGE Dismiss system dialog This fixed the keypad remains ON when switch facet issue. BUG: 130573446, 149228466 Test: Manual Change-Id: Ia449fb41a03bc02498471ded660d573d5b1ad141 (cherry picked from commit 82298783683ebe82a5847dfd35fc8b3528709930) (cherry picked from commit ebff32a5d61cdf6f6812588ab4e60ba869dad306) --- .../android/systemui/statusbar/car/CarFacetButton.java | 8 +++++++- .../systemui/statusbar/car/CarNavigationButton.java | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java index 90d20ba19d0e..01b153c979ee 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java @@ -125,13 +125,19 @@ public class CarFacetButton extends LinearLayout { /** Defines the behavior of a button click. */ protected OnClickListener getButtonClickListener(Intent toSend) { - return v -> mContext.startActivityAsUser(toSend, UserHandle.CURRENT); + return v -> { + mContext.startActivityAsUser(toSend, UserHandle.CURRENT); + mContext.sendBroadcastAsUser( + new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT); + }; } /** Defines the behavior of a long click. */ protected OnLongClickListener getButtonLongClickListener(Intent toSend) { return v -> { mContext.startActivityAsUser(toSend, UserHandle.CURRENT); + mContext.sendBroadcastAsUser( + new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT); return true; }; } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java index bdf23c56797b..afca2701aa5d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java @@ -112,6 +112,9 @@ public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImag try { if (mBroadcastIntent) { mContext.sendBroadcastAsUser(toSend, UserHandle.CURRENT); + mContext.sendBroadcastAsUser( + new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), + UserHandle.CURRENT); return; } mContext.startActivityAsUser(toSend, UserHandle.CURRENT); -- GitLab From 0d3a5aa2aa16fb469a6f10042e53c6dc61c09437 Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Tue, 4 Feb 2020 19:01:25 -0800 Subject: [PATCH 082/143] Add carrier config to skip validation if recently validate. Bug: 148611362 Test: unittest Change-Id: I4f4e1f698bf883e6eaf80959f3592562015c70f5 Merged-In: I4f4e1f698bf883e6eaf80959f3592562015c70f5 --- .../telephony/CarrierConfigManager.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 1994ccc74b74..81042f4a34bf 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3150,6 +3150,25 @@ public class CarrierConfigManager { public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING = "subscription_group_uuid_string"; + /** + * Data switch validation minimal gap time, in milliseconds. + * + * Which means, if the same subscription on the same network (based on MCC+MNC+TAC+subId) + * was recently validated (within this time gap), and Telephony receives a request to switch to + * it again, Telephony will skip the validation part and switch to it as soon as connection + * is setup, as if it's already validated. + * + * If the network was validated within the gap but the latest validation result is false, the + * validation will not be skipped. + * + * If not set or set to 0, validation will never be skipped. + * The max acceptable value of this config is 24 hours. + * + * @hide + */ + public static final String KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG = + "data_switch_validation_min_gap_LONG"; + /** * A boolean property indicating whether this subscription should be managed as an opportunistic * subscription. @@ -3628,6 +3647,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_SUPPORT_WPS_OVER_IMS_BOOL, true); sDefaults.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, null); sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000); + sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0); } /** -- GitLab From cbfe702556fea02b6a2d467419cb719274c154fc Mon Sep 17 00:00:00 2001 From: Eric Berglund Date: Mon, 10 Feb 2020 12:35:29 -0800 Subject: [PATCH 083/143] DO NOT MERGE Hold onto NotificationListener when reconnecting notifications UI. Bug: 149342387 Test: manual Change-Id: I1bc4046ce1e6792699eaa87b9d50cfaa231e806f --- .../systemui/statusbar/car/CarStatusBar.java | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index e0f398742ebc..4b4b73dae91e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -41,7 +41,6 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; -import android.os.RemoteException; import android.util.Log; import android.view.Display; import android.view.GestureDetector; @@ -645,20 +644,22 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } }); - if (mCarNotificationListener != null) { - try { - // If we already had a notification listener we need to unreigster is before - // making a new one - mCarNotificationListener.unregisterAsSystemService(); - } catch (RemoteException e) { - Log.e(TAG, "Error unregistering notification listener."); - } - } - - mCarNotificationListener = new CarNotificationListener(); mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper(); - mNotificationDataManager = new NotificationDataManager(); + if (mCarNotificationListener == null) { + // Only make and register a listener if we don't already have one since + // #connectNotificationsUI can be called multiple times on locale change. + mCarNotificationListener = new CarNotificationListener(); + mNotificationDataManager = new NotificationDataManager(); + + CarHeadsUpNotificationManager carHeadsUpNotificationManager = + new CarSystemUIHeadsUpNotificationManager(mContext, + mNotificationClickHandlerFactory, mNotificationDataManager); + mCarNotificationListener.registerAsSystemService(mContext, + mCarUxRestrictionManagerWrapper, + carHeadsUpNotificationManager, mNotificationDataManager); + } + mNotificationDataManager.setOnUnseenCountUpdateListener(() -> { if (mNavigationBarView != null && mNotificationDataManager != null) { onUseenCountUpdate(mNotificationDataManager.getUnseenNotificationCount()); @@ -667,13 +668,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mEnableHeadsUpNotificationWhenNotificationShadeOpen = mContext.getResources().getBoolean( R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen); - CarHeadsUpNotificationManager carHeadsUpNotificationManager = - new CarSystemUIHeadsUpNotificationManager(mContext, - mNotificationClickHandlerFactory, mNotificationDataManager); - mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager); - mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper, - carHeadsUpNotificationManager, mNotificationDataManager); + mNotificationClickHandlerFactory.setNotificationDataManager(mNotificationDataManager); mNotificationView = mStatusBarWindow.findViewById(R.id.notification_view); View glassPane = mStatusBarWindow.findViewById(R.id.glass_pane); -- GitLab From 7c7f3dc678ab43bfb45cef6a14bd4959b120b8d9 Mon Sep 17 00:00:00 2001 From: Jay Aliomer Date: Tue, 18 Feb 2020 11:48:29 -0500 Subject: [PATCH 084/143] Back porting Dark theme bug fixes from R Applying theme on start update system properties on startup to apply the updates Fixes: 149441632 Fixes: 149385662 Test: UiModeManager tests Change-Id: I7f71e27a43eb24be833b3003340653fefc75d0cc Merged-In: I0bee6517b39216146681097262cf55c7192b0131 --- .../android/server/UiModeManagerService.java | 128 +++++++++++------- .../server/UiModeManagerServiceTest.java | 5 +- 2 files changed, 85 insertions(+), 48 deletions(-) diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 978cc577f1eb..17742b7f634f 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -16,6 +16,7 @@ package com.android.server; +import android.annotation.IntRange; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; @@ -41,6 +42,7 @@ import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; @@ -67,6 +69,10 @@ import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Map; + +import static android.app.UiModeManager.MODE_NIGHT_AUTO; +import static android.app.UiModeManager.MODE_NIGHT_YES; final class UiModeManagerService extends SystemService { private static final String TAG = UiModeManager.class.getSimpleName(); @@ -124,6 +130,7 @@ final class UiModeManagerService extends SystemService { private NotificationManager mNotificationManager; private StatusBarManager mStatusBarManager; private WindowManagerInternal mWindowManager; + private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; @@ -136,11 +143,12 @@ final class UiModeManagerService extends SystemService { @VisibleForTesting protected UiModeManagerService(Context context, WindowManagerInternal wm, PowerManager.WakeLock wl, TwilightManager tm, - boolean setupWizardComplete) { + PowerManager pm, boolean setupWizardComplete) { super(context); mWindowManager = wm; mWakeLock = wl; mTwilightManager = tm; + mPowerManager = pm; mSetupWizardComplete = setupWizardComplete; } @@ -261,14 +269,19 @@ final class UiModeManagerService extends SystemService { private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri) { - int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, - mNightMode, 0); - mode = mode == UiModeManager.MODE_NIGHT_AUTO - ? UiModeManager.MODE_NIGHT_YES : mode; - SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); + updateSystemProperties(); } }; + private void updateSystemProperties() { + int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, + mNightMode, 0); + if (mode == MODE_NIGHT_AUTO) { + mode = MODE_NIGHT_YES; + } + SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); + } + @Override public void onSwitchUser(int userHandle) { super.onSwitchUser(userHandle); @@ -280,9 +293,9 @@ final class UiModeManagerService extends SystemService { public void onStart() { final Context context = getContext(); - final PowerManager powerManager = + mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); + mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); mWindowManager = LocalServices.getService(WindowManagerInternal.class); // If setup isn't complete for this user listen for completion so we can unblock @@ -349,6 +362,7 @@ final class UiModeManagerService extends SystemService { context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE), false, mDarkThemeObserver, 0); + mHandler.post(() -> updateSystemProperties()); } @VisibleForTesting @@ -406,6 +420,7 @@ final class UiModeManagerService extends SystemService { } private void registerScreenOffEvent() { + if (mPowerSave) return; mWaitForScreenOff = true; final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); @@ -510,7 +525,9 @@ final class UiModeManagerService extends SystemService { persistNightMode(user); } // on screen off will update configuration instead - if (mNightMode != UiModeManager.MODE_NIGHT_AUTO || mCar) { + if ((mNightMode != MODE_NIGHT_AUTO) + || shouldApplyAutomaticChangesImmediately()) { + unregisterScreenOffEvent(); updateLocked(0, 0); } else { registerScreenOffEvent(); @@ -587,19 +604,20 @@ final class UiModeManagerService extends SystemService { synchronized (mLock) { pw.println("Current UI Mode Service state:"); pw.print(" mDockState="); pw.print(mDockState); - pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" ("); - pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); - pw.print(" mNightModeLocked="); pw.print(mNightModeLocked); - pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); - pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); - pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); - pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); + pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); + pw.print(" mNightModeLocked="); pw.print(mNightModeLocked); + pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); + pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); + pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); + pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); - pw.print(" mUiModeLocked="); pw.print(mUiModeLocked); - pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); + pw.print(" mUiModeLocked="); pw.print(mUiModeLocked); + pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); - pw.print(" mSystemReady="); pw.println(mSystemReady); + pw.print(" mSystemReady="); pw.println(mSystemReady); + if (mTwilightManager != null) { // We may not have a TwilightManager. pw.print(" mTwilightService.getLastTwilightState()="); @@ -615,7 +633,6 @@ final class UiModeManagerService extends SystemService { mTwilightManager = getLocalService(TwilightManager.class); mSystemReady = true; mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - updateComputedNightModeLocked(); registerVrStateListener(); updateLocked(0, 0); } @@ -683,40 +700,56 @@ final class UiModeManagerService extends SystemService { uiMode = Configuration.UI_MODE_TYPE_VR_HEADSET; } - if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + if (mNightMode == MODE_NIGHT_YES || mNightMode == UiModeManager.MODE_NIGHT_NO) { + mComputedNightMode = mNightMode == MODE_NIGHT_YES; + } + + if (mNightMode == MODE_NIGHT_AUTO) { + boolean activateNightMode = mComputedNightMode; if (mTwilightManager != null) { mTwilightManager.registerListener(mTwilightListener, mHandler); + final TwilightState lastState = mTwilightManager.getLastTwilightState(); + activateNightMode = lastState == null ? mComputedNightMode : lastState.isNight(); } - updateComputedNightModeLocked(); - uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES - : Configuration.UI_MODE_NIGHT_NO; + + updateComputedNightModeLocked(activateNightMode); } else { if (mTwilightManager != null) { mTwilightManager.unregisterListener(mTwilightListener); } - uiMode |= mNightMode << 4; } // Override night mode in power save mode if not in car mode if (mPowerSave && !mCarModeEnabled) { uiMode &= ~Configuration.UI_MODE_NIGHT_NO; uiMode |= Configuration.UI_MODE_NIGHT_YES; + } else { + uiMode = getComputedUiModeConfiguration(uiMode); } if (LOG) { Slog.d(TAG, - "updateConfigurationLocked: mDockState=" + mDockState + "updateConfigurationLocked: mDockState=" + mDockState + "; mCarMode=" + mCarModeEnabled + "; mNightMode=" + mNightMode + "; uiMode=" + uiMode); } mCurUiMode = uiMode; - if (!mHoldingConfiguration || !mWaitForScreenOff) { + if (!mHoldingConfiguration && (!mWaitForScreenOff || mPowerSave)) { mConfiguration.uiMode = uiMode; } } + @UiModeManager.NightMode + private int getComputedUiModeConfiguration(@UiModeManager.NightMode int uiMode) { + uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES + : Configuration.UI_MODE_NIGHT_NO; + uiMode &= mComputedNightMode ? ~Configuration.UI_MODE_NIGHT_NO + : ~Configuration.UI_MODE_NIGHT_YES; + return uiMode; + } + private void applyConfigurationExternallyLocked() { if (mSetUiMode != mConfiguration.uiMode) { mSetUiMode = mConfiguration.uiMode; @@ -724,10 +757,16 @@ final class UiModeManagerService extends SystemService { ActivityTaskManager.getService().updateConfiguration(mConfiguration); } catch (RemoteException e) { Slog.w(TAG, "Failure communicating with activity manager", e); + } catch (SecurityException e) { + Slog.e(TAG, "Activity does not have the ", e); } } } + private boolean shouldApplyAutomaticChangesImmediately() { + return mCar || !mPowerManager.isInteractive(); + } + void updateLocked(int enableFlags, int disableFlags) { String action = null; String oldAction = null; @@ -958,26 +997,21 @@ final class UiModeManagerService extends SystemService { } } - private void updateComputedNightModeLocked() { - if (mTwilightManager != null) { - TwilightState state = mTwilightManager.getLastTwilightState(); - if (state != null) { - mComputedNightMode = state.isNight(); - } - if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) { - mComputedNightMode = true; - return; - } - if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) { - mComputedNightMode = false; - return; - } - - mNightModeOverride = mNightMode; - final int user = UserHandle.getCallingUserId(); - Secure.putIntForUser(getContext().getContentResolver(), - OVERRIDE_NIGHT_MODE, mNightModeOverride, user); + private void updateComputedNightModeLocked(boolean activate) { + mComputedNightMode = activate; + if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) { + mComputedNightMode = true; + return; + } + if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) { + mComputedNightMode = false; + return; } + + mNightModeOverride = mNightMode; + final int user = UserHandle.getCallingUserId(); + Secure.putIntForUser(getContext().getContentResolver(), + OVERRIDE_NIGHT_MODE, mNightModeOverride, user); } private void registerVrStateListener() { @@ -1098,7 +1132,7 @@ final class UiModeManagerService extends SystemService { final boolean isIt = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_YES) != 0; if (LOG) { Slog.d(TAG, - "LocalService.isNightMode(): mNightMode=" + mNightMode + "LocalService.isNightMode(): mNightMode=" + mNightMode + "; mComputedNightMode=" + mComputedNightMode + "; uiMode=" + mConfiguration.uiMode + "; isIt=" + isIt); diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index 338f837b9b44..3fce5ebc8432 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -24,6 +24,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.os.PowerManager; +import android.os.PowerManagerInternal; import android.os.RemoteException; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -66,12 +67,14 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { TwilightManager mTwilightManager; @Mock PowerManager.WakeLock mWakeLock; + @Mock + PowerManager mPowerManager; private Set mScreenOffRecievers; @Before public void setUp() { mUiManagerService = new UiModeManagerService(mContext, mWindowManager, mWakeLock, - mTwilightManager, true); + mTwilightManager, mPowerManager, true); mScreenOffRecievers = new HashSet<>(); mService = mUiManagerService.getService(); when(mContext.checkCallingOrSelfPermission(anyString())) -- GitLab From f9418dbb2c2469dd271e4aebefda5b6a4b485f3a Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Tue, 5 Nov 2019 10:15:36 +0000 Subject: [PATCH 085/143] RESTRICT AUTOMERGE Update keyguard locked state from TrustManagerService TrustManagerService holds the ground truth about whether a user is locked or not, so update keystore using the information there, instead of doing it from KeyguardStateMonitor. This fixes the issue of work profile locked state not being correctly pushed to keystore. Note: since this change is likely to be backported as a security patch, I'm refraining from doing major refactoring right now. Bug: 141329041 Bug: 144430870 Test: manually with KeyPairSampleApp Change-Id: I3472ece73d573a775345ebcceeeb2cc460374c9b --- keystore/java/android/security/KeyStore.java | 11 +++++ .../policy/keyguard/KeyguardStateMonitor.java | 28 ----------- .../server/trust/TrustManagerService.java | 48 +++++++++++++++++++ 3 files changed, 59 insertions(+), 28 deletions(-) diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 646aa13664c4..9866c3053714 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -1067,6 +1067,17 @@ public class KeyStore { return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword); } + /** + * Notify keystore about the latest user locked state. This is to support keyguard-bound key. + */ + public void onUserLockedStateChanged(int userHandle, boolean locked) { + try { + mBinder.onKeyguardVisibilityChanged(locked, userHandle); + } catch (RemoteException e) { + Log.w(TAG, "Failed to update user locked state " + userHandle, e); + } + } + private class KeyAttestationCallbackResult { private KeystoreResponse keystoreResponse; private KeymasterCertificateChain certificateChain; diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index f78d2639df1a..add0b01f1879 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -19,8 +19,6 @@ package com.android.server.policy.keyguard; import android.app.ActivityManager; import android.content.Context; import android.os.RemoteException; -import android.os.ServiceManager; -import android.security.keystore.IKeystoreService; import android.util.Slog; import com.android.internal.policy.IKeyguardService; @@ -53,16 +51,11 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { private final LockPatternUtils mLockPatternUtils; private final StateCallback mCallback; - IKeystoreService mKeystoreService; - public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) { mLockPatternUtils = new LockPatternUtils(context); mCurrentUserId = ActivityManager.getCurrentUser(); mCallback = callback; - mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager - .getService("android.security.keystore")); - try { service.addStateMonitorCallback(this); } catch (RemoteException e) { @@ -95,23 +88,6 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { mIsShowing = showing; mCallback.onShowingChanged(); - int retry = 2; - while (retry > 0) { - try { - mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId); - break; - } catch (RemoteException e) { - if (retry == 2) { - Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died" - + " -> refreshing service token and retrying"); - mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager - .getService("android.security.keystore")); - } else { - Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e); - } - --retry; - } - } } @Override // Binder interface @@ -123,10 +99,6 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub { mCurrentUserId = userId; } - private synchronized int getCurrentUser() { - return mCurrentUserId; - } - @Override // Binder interface public void onInputRestrictedStateChanged(boolean inputRestricted) { mInputRestricted = inputRestricted; diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 7408dd40b5ca..5f5cd3c46117 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -53,6 +53,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.KeyStore; import android.service.trust.TrustAgentService; import android.text.TextUtils; import android.util.ArrayMap; @@ -135,6 +136,33 @@ public class TrustManagerService extends SystemService { @GuardedBy("mUserIsTrusted") private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray(); + /** + * Stores the locked state for users on the device. There are three different type of users + * which are handled slightly differently: + *
    + *
  • Users with real keyguard + * These are users who can be switched to ({@link UserInfo#supportsSwitchToByUser()}). Their + * locked state is derived by a combination of user secure state, keyguard state, trust agent + * decision and biometric authentication result. These are updated via + * {@link #refreshDeviceLockedForUser(int)} and result stored in {@link #mDeviceLockedForUser}. + *
  • Managed profiles with unified challenge + * Managed profile with unified challenge always shares the same locked state as their parent, + * so their locked state is not recorded in {@link #mDeviceLockedForUser}. Instead, + * {@link ITrustManager#isDeviceLocked(int)} always resolves their parent user handle and + * queries its locked state instead. + *
  • Managed profiles with separate challenge + * Locked state for profile with separate challenge is determined by other parts of the + * framework (mostly PowerManager) and pushed to TrustManagerService via + * {@link ITrustManager#setDeviceLockedForUser(int, boolean)}. Although in a corner case when + * the profile has a separate but empty challenge, setting its {@link #mDeviceLockedForUser} to + * {@code false} is actually done by {@link #refreshDeviceLockedForUser(int)}. + *
+ * TODO: Rename {@link ITrustManager#setDeviceLockedForUser(int, boolean)} to + * {@code setDeviceLockedForProfile} to better reflect its purpose. Unifying + * {@code setDeviceLockedForProfile} and {@link #setDeviceLockedForUser} would also be nice. + * At the moment they both update {@link #mDeviceLockedForUser} but have slightly different + * side-effects: one notifies trust agents while the other sends out a broadcast. + */ @GuardedBy("mDeviceLockedForUser") private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray(); @@ -601,6 +629,10 @@ public class TrustManagerService extends SystemService { } } + /** + * Update the user's locked state. Only applicable to users with a real keyguard + * ({@link UserInfo#supportsSwitchToByUser}) and unsecured managed profiles. + */ private void refreshDeviceLockedForUser(int userId) { if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) { Log.e(TAG, "refreshDeviceLockedForUser(userId=" + userId + "): Invalid user handle," @@ -661,6 +693,15 @@ public class TrustManagerService extends SystemService { } if (changed) { dispatchDeviceLocked(userId, locked); + + KeyStore.getInstance().onUserLockedStateChanged(userId, locked); + // Also update the user's profiles who have unified challenge, since they + // share the same unlocked state (see {@link #isDeviceLocked(int)}) + for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) { + if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) { + KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked); + } + } } } @@ -1194,6 +1235,10 @@ public class TrustManagerService extends SystemService { return "0x" + Integer.toHexString(i); } + /** + * Changes the lock status for the given user. This is only applicable to managed profiles, + * other users should be handled by Keyguard. + */ @Override public void setDeviceLockedForUser(int userId, boolean locked) { enforceReportPermission(); @@ -1204,6 +1249,9 @@ public class TrustManagerService extends SystemService { synchronized (mDeviceLockedForUser) { mDeviceLockedForUser.put(userId, locked); } + + KeyStore.getInstance().onUserLockedStateChanged(userId, locked); + if (locked) { try { ActivityManager.getService().notifyLockedProfile(userId); -- GitLab From 25400fdcb92305814e1ee614f05947e51b502375 Mon Sep 17 00:00:00 2001 From: Abhijoy Saha Date: Tue, 18 Feb 2020 12:54:33 -0800 Subject: [PATCH 086/143] DO NOT MERGE Have volume UI dismiss on home button press. Register a receiver that listens for Intent.ACTION_CLOSE_SYSTEM_DIALOGS and dismisses the volume UI when such an intent is received. Bug: 149228466 Test: Manual Change-Id: Iabb706b1d4cc54cb84f228aad95bfdb7e6f75851 --- .../systemui/volume/CarVolumeDialogImpl.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index f91c90ec636f..b87844ea74a1 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -26,8 +26,11 @@ import android.app.KeyguardManager; import android.car.Car; import android.car.Car.CarServiceLifecycleListener; import android.car.media.CarAudioManager; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.Color; @@ -39,6 +42,7 @@ import android.os.Debug; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -175,6 +179,17 @@ public class CarVolumeDialogImpl implements VolumeDialog { mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback); }; + private final BroadcastReceiver mHomeButtonPressedBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (!intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { + return; + } + + dismiss(Events.DISMISS_REASON_VOLUME_CONTROLLER); + } + }; + public CarVolumeDialogImpl(Context context) { mContext = context; mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); @@ -204,6 +219,10 @@ public class CarVolumeDialogImpl implements VolumeDialog { public void init(int windowType, Callback callback) { initDialog(); + mContext.registerReceiverAsUser(mHomeButtonPressedBroadcastReceiver, UserHandle.CURRENT, + new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), /* broadcastPermission= */ + null, /* scheduler= */ null); + ((CarSystemUIFactory) SystemUIFactory.getInstance()).getCarServiceProvider(mContext) .addListener(mCarServiceLifecycleListener); } @@ -212,6 +231,8 @@ public class CarVolumeDialogImpl implements VolumeDialog { public void destroy() { mHandler.removeCallbacksAndMessages(/* token= */ null); + mContext.unregisterReceiver(mHomeButtonPressedBroadcastReceiver); + cleanupAudioManager(); } -- GitLab From cb45d588e15243d28af595442383fe21bd567b10 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Thu, 13 Feb 2020 16:15:39 -0500 Subject: [PATCH 087/143] RESTRICT AUTOMERGE Use Alternative Prox Sensor for Falsing This allows new phones to use a sensor with a different theshold when attempting to determine the devices proximity to surfaces. Bug: 149420648 Test: manual Change-Id: Iee8568f7d9f58359dc1e72fd195a42abeaf2ddf3 --- packages/SystemUI/res/values/config.xml | 8 ++++ .../android/systemui/doze/DozeSensors.java | 18 ++++---- .../android/systemui/doze/DozeTriggers.java | 13 +++--- .../systemui/util/ProximitySensor.java | 43 +++++++++++++++---- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 78318cb7e858..87461bbccf12 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -201,6 +201,14 @@ always-on display) --> + + @string/doze_brightness_sensor_type + + + + 0 + 130 diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 026a62528c8d..b7c8f707b850 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -43,11 +43,11 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; -import com.android.systemui.R; import com.android.systemui.plugins.SensorManagerPlugin; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.AlarmTimeout; import com.android.systemui.util.AsyncSensorManager; +import com.android.systemui.util.ProximitySensor; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; @@ -288,6 +288,7 @@ public class DozeSensors { final AlarmTimeout mCooldownTimer; final AlwaysOnDisplayPolicy mPolicy; final Sensor mSensor; + private final float mSensorThreshold; final boolean mUsingBrightnessSensor; public ProxSensor(AlwaysOnDisplayPolicy policy) { @@ -297,11 +298,14 @@ public class DozeSensors { // The default prox sensor can be noisy, so let's use a prox gated brightness sensor // if available. - Sensor sensor = DozeSensors.findSensorWithType(mSensorManager, - mContext.getString(R.string.doze_brightness_sensor_type)); + Sensor sensor = ProximitySensor.findCustomProxSensor(mContext, mSensorManager); mUsingBrightnessSensor = sensor != null; - if (sensor == null) { + if (mUsingBrightnessSensor) { + mSensorThreshold = ProximitySensor.getBrightnessSensorThreshold( + mContext.getResources()); + } else { sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + mSensorThreshold = sensor.getMaximumRange(); } mSensor = sensor; } @@ -343,11 +347,9 @@ public class DozeSensors { if (DEBUG) Log.d(TAG, "onSensorChanged " + event); if (mUsingBrightnessSensor) { - // The custom brightness sensor is gated by the proximity sensor and will return 0 - // whenever prox is covered. - mCurrentlyFar = event.values[0] > 0; + mCurrentlyFar = event.values[0] > mSensorThreshold; } else { - mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange(); + mCurrentlyFar = event.values[0] >= mSensorThreshold; } mProxCallback.accept(mCurrentlyFar); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 6199a0deb31f..c7a133dc530a 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -41,10 +41,10 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.Preconditions; import com.android.systemui.Dependency; -import com.android.systemui.R; import com.android.systemui.dock.DockManager; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.Assert; +import com.android.systemui.util.ProximitySensor; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; @@ -431,15 +431,18 @@ public class DozeTriggers implements DozeMachine.Part { private boolean mFinished; private float mMaxRange; private boolean mUsingBrightnessSensor; + private float mSensorThreshold; protected abstract void onProximityResult(int result); public void check() { Preconditions.checkState(!mFinished && !mRegistered); - Sensor sensor = DozeSensors.findSensorWithType(mSensorManager, - mContext.getString(R.string.doze_brightness_sensor_type)); + Sensor sensor = ProximitySensor.findCustomProxSensor(mContext, mSensorManager); mUsingBrightnessSensor = sensor != null; - if (sensor == null) { + if (mUsingBrightnessSensor) { + mSensorThreshold = ProximitySensor.getBrightnessSensorThreshold( + mContext.getResources()); + } else { sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); } if (sensor == null) { @@ -473,7 +476,7 @@ public class DozeTriggers implements DozeMachine.Part { if (mUsingBrightnessSensor) { // The custom brightness sensor is gated by the proximity sensor and will // return 0 whenever prox is covered. - isNear = event.values[0] == 0; + isNear = event.values[0] <= mSensorThreshold; } else { isNear = event.values[0] < mMaxRange; } diff --git a/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java index a905eba1f0ed..4cd38febc5dd 100644 --- a/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java +++ b/packages/SystemUI/src/com/android/systemui/util/ProximitySensor.java @@ -17,6 +17,7 @@ package com.android.systemui.util; import android.content.Context; +import android.content.res.Resources; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -40,7 +41,7 @@ public class ProximitySensor { private final Sensor mSensor; private final AsyncSensorManager mSensorManager; private final boolean mUsingBrightnessSensor; - private final float mMaxRange; + private final float mThreshold; private SensorEventListener mSensorEventListener = new SensorEventListener() { @Override @@ -59,7 +60,7 @@ public class ProximitySensor { @Inject public ProximitySensor(Context context, AsyncSensorManager sensorManager) { mSensorManager = sensorManager; - Sensor sensor = findBrightnessSensor(context, sensorManager); + Sensor sensor = findCustomProxSensor(context, sensorManager); if (sensor == null) { mUsingBrightnessSensor = false; @@ -69,9 +70,13 @@ public class ProximitySensor { } mSensor = sensor; if (mSensor != null) { - mMaxRange = mSensor.getMaximumRange(); + if (mUsingBrightnessSensor) { + mThreshold = getBrightnessSensorThreshold(context.getResources()); + } else { + mThreshold = mSensor.getMaximumRange(); + } } else { - mMaxRange = 0; + mThreshold = 0; } } @@ -79,8 +84,18 @@ public class ProximitySensor { mTag = tag; } - private Sensor findBrightnessSensor(Context context, SensorManager sensorManager) { - String sensorType = context.getString(R.string.doze_brightness_sensor_type); + /** + * Returns a brightness sensor that can be used for proximity purposes. + * + * @deprecated This method exists for legacy purposes. Use the containing class directly. + */ + @Deprecated + public static Sensor findCustomProxSensor(Context context, SensorManager sensorManager) { + String sensorType = context.getString(R.string.proximity_sensor_type); + if (sensorType.isEmpty()) { + return null; + } + List sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL); Sensor sensor = null; for (Sensor s : sensorList) { @@ -93,6 +108,16 @@ public class ProximitySensor { return sensor; } + /** + * Returns a threshold value that can be used along with {@link #findCustomProxSensor} + * + * @deprecated This method exists for legacy purposes. Use the containing class directly. + */ + @Deprecated + public static float getBrightnessSensorThreshold(Resources resources) { + return resources.getFloat(R.dimen.proximity_sensor_threshold); + } + /** * Returns {@code false} if a Proximity sensor is not available. */ @@ -141,11 +166,11 @@ public class ProximitySensor { } private void onSensorEvent(SensorEvent event) { - boolean near = event.values[0] < mMaxRange; if (mUsingBrightnessSensor) { - near = event.values[0] == 0; + mNear = event.values[0] <= mThreshold; + } else { + mNear = event.values[0] < mThreshold; } - mNear = near; mListeners.forEach(proximitySensorListener -> proximitySensorListener.onProximitySensorEvent( new ProximityEvent(mNear, event.timestamp))); -- GitLab From fbf32a013d7821ee3cf75b64fa40876f8ca6bf4a Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 16 Jan 2020 12:17:17 -0800 Subject: [PATCH 088/143] DO NOT MERGE: RELAND: NetworkRequest: Embed requestor uid & packageName Add the requestorUid & requestorPackageName fields to NetworkCapabilities. This is populated by CS when a new network request is received. These 2 requestor fields are also optionally used for network matching. All of the regular app initiated requests will have the requestor uid and package name set by connectivity service. Network agents can optionally set the requestorUid and requestorPackageName to restrict the network created only to the app that requested the network. This will help removing the necessity for the various specifiers to embed the uid & package name info in the specifier for network matching. Note: NetworkSpecifier.assertValidFromUid() is deprecated & removed in favor of setting the uid/package name on the agent to restrict the network to a certain app (useful for wifi peer to peer API & wifi aware). Bug: 144102365 Test: Verified that wifi network request related CTS verifier tests pass. Test: Device boots up and connects to wifi networks Merged-In: I207c446108afdac7ee2c25e6bbcbc37c4e3f6529 Change-Id: I58775e82aa7725aac5aa27ca9d2b5ee8f0be4242 --- api/current.txt | 2 +- api/system-current.txt | 7 +- .../java/android/net/ConnectivityManager.java | 14 +- .../android/net/IConnectivityManager.aidl | 9 +- .../java/android/net/NetworkCapabilities.java | 161 +++++++++++++++++- core/java/android/net/NetworkRequest.java | 26 +++ core/java/android/net/NetworkSpecifier.java | 17 -- .../android/server/ConnectivityService.java | 54 +++--- .../android/net/NetworkCapabilitiesTest.java | 16 +- .../android/net/ConnectivityManagerTest.java | 12 +- .../server/ConnectivityServiceTest.java | 31 +--- .../net/wifi/WifiNetworkAgentSpecifier.java | 6 - .../net/wifi/WifiNetworkSpecifier.java | 8 - .../aware/WifiAwareAgentNetworkSpecifier.java | 6 - .../wifi/aware/WifiAwareNetworkSpecifier.java | 8 - .../wifi/WifiNetworkAgentSpecifierTest.java | 10 -- .../WifiAwareAgentNetworkSpecifierTest.java | 11 -- 17 files changed, 263 insertions(+), 135 deletions(-) diff --git a/api/current.txt b/api/current.txt index 7a06cb7e9093..b0878d7c5c62 100644 --- a/api/current.txt +++ b/api/current.txt @@ -29162,7 +29162,7 @@ package android.net { method @NonNull public android.net.NetworkCapabilities setLinkDownstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities setLinkUpstreamBandwidthKbps(int); method @NonNull public android.net.NetworkCapabilities setNetworkSpecifier(@NonNull android.net.NetworkSpecifier); - method public void setOwnerUid(int); + method @NonNull public android.net.NetworkCapabilities setOwnerUid(int); method @NonNull public android.net.NetworkCapabilities setSignalStrength(int); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; diff --git a/api/system-current.txt b/api/system-current.txt index ef5c838faa25..971ea08651b4 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4656,7 +4656,9 @@ package android.net { method @Nullable public String getSSID(); method @NonNull public int[] getTransportTypes(); method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities); - method public void setAdministratorUids(@NonNull java.util.List); + method @NonNull public android.net.NetworkCapabilities setAdministratorUids(@NonNull java.util.List); + method @NonNull public android.net.NetworkCapabilities setRequestorPackageName(@NonNull String); + method @NonNull public android.net.NetworkCapabilities setRequestorUid(int); method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String); method @NonNull public android.net.NetworkCapabilities setTransportInfo(@NonNull android.net.TransportInfo); field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16 @@ -4708,6 +4710,8 @@ package android.net { } public class NetworkRequest implements android.os.Parcelable { + method @Nullable public String getRequestorPackageName(); + method public int getRequestorUid(); method public boolean satisfiedBy(@Nullable android.net.NetworkCapabilities); } @@ -4742,7 +4746,6 @@ package android.net { } public abstract class NetworkSpecifier { - method public void assertValidFromUid(int); method @Nullable public android.net.NetworkSpecifier redact(); method public abstract boolean satisfiedBy(@Nullable android.net.NetworkSpecifier); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6d8565025fd4..f1b5d3298b9b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3747,6 +3747,7 @@ public class ConnectivityManager { checkCallbackNotNull(callback); Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities"); final NetworkRequest request; + final String callingPackageName = mContext.getOpPackageName(); try { synchronized(sCallbacks) { if (callback.networkRequest != null @@ -3758,10 +3759,11 @@ public class ConnectivityManager { Messenger messenger = new Messenger(handler); Binder binder = new Binder(); if (action == LISTEN) { - request = mService.listenForNetwork(need, messenger, binder); + request = mService.listenForNetwork( + need, messenger, binder, callingPackageName); } else { request = mService.requestNetwork( - need, messenger, timeoutMs, binder, legacyType); + need, messenger, timeoutMs, binder, legacyType, callingPackageName); } if (request != null) { sCallbacks.put(request, callback); @@ -4034,8 +4036,10 @@ public class ConnectivityManager { @NonNull PendingIntent operation) { printStackTrace(); checkPendingIntentNotNull(operation); + final String callingPackageName = mContext.getOpPackageName(); try { - mService.pendingRequestForNetwork(request.networkCapabilities, operation); + mService.pendingRequestForNetwork( + request.networkCapabilities, operation, callingPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { @@ -4147,8 +4151,10 @@ public class ConnectivityManager { @NonNull PendingIntent operation) { printStackTrace(); checkPendingIntentNotNull(operation); + final String callingPackageName = mContext.getOpPackageName(); try { - mService.pendingListenForNetwork(request.networkCapabilities, operation); + mService.pendingListenForNetwork( + request.networkCapabilities, operation, callingPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c871c456dc66..3a55461a77d2 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -166,18 +166,19 @@ interface IConnectivityManager in int factorySerialNumber); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, int timeoutSec, in IBinder binder, int legacy); + in Messenger messenger, int timeoutSec, in IBinder binder, int legacy, + String callingPackageName); NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, - in PendingIntent operation); + in PendingIntent operation, String callingPackageName); void releasePendingNetworkRequest(in PendingIntent operation); NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, in IBinder binder); + in Messenger messenger, in IBinder binder, String callingPackageName); void pendingListenForNetwork(in NetworkCapabilities networkCapabilities, - in PendingIntent operation); + in PendingIntent operation, String callingPackageName); void releaseNetworkRequest(in NetworkRequest networkRequest); diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 38f7390abffd..ef4a9e5f3b5d 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -27,6 +27,7 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.Process; +import android.text.TextUtils; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; @@ -63,6 +64,16 @@ public final class NetworkCapabilities implements Parcelable { // Set to true when private DNS is broken. private boolean mPrivateDnsBroken; + /** + * Uid of the app making the request. + */ + private int mRequestorUid; + + /** + * Package name of the app making the request. + */ + private String mRequestorPackageName; + public NetworkCapabilities() { clearAll(); mNetworkCapabilities = DEFAULT_CAPABILITIES; @@ -89,6 +100,8 @@ public final class NetworkCapabilities implements Parcelable { mOwnerUid = Process.INVALID_UID; mSSID = null; mPrivateDnsBroken = false; + mRequestorUid = Process.INVALID_UID; + mRequestorPackageName = null; } /** @@ -109,6 +122,8 @@ public final class NetworkCapabilities implements Parcelable { mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; mSSID = nc.mSSID; mPrivateDnsBroken = nc.mPrivateDnsBroken; + mRequestorUid = nc.mRequestorUid; + mRequestorPackageName = nc.mRequestorPackageName; } /** @@ -810,7 +825,7 @@ public final class NetworkCapabilities implements Parcelable { } /** - * UID of the app that owns this network, or INVALID_UID if none/unknown. + * UID of the app that owns this network, or Process#INVALID_UID if none/unknown. * *

This field keeps track of the UID of the app that created this network and is in charge of * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running @@ -821,8 +836,9 @@ public final class NetworkCapabilities implements Parcelable { /** * Set the UID of the owner app. */ - public void setOwnerUid(final int uid) { + public @NonNull NetworkCapabilities setOwnerUid(final int uid) { mOwnerUid = uid; + return this; } /** @@ -865,9 +881,11 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ @SystemApi - public void setAdministratorUids(@NonNull final List administratorUids) { + public @NonNull NetworkCapabilities setAdministratorUids( + @NonNull final List administratorUids) { mAdministratorUids.clear(); mAdministratorUids.addAll(administratorUids); + return this; } /** @@ -1385,6 +1403,7 @@ public final class NetworkCapabilities implements Parcelable { combineSignalStrength(nc); combineUids(nc); combineSSIDs(nc); + combineRequestor(nc); } /** @@ -1404,7 +1423,8 @@ public final class NetworkCapabilities implements Parcelable { && satisfiedBySpecifier(nc) && (onlyImmutable || satisfiedBySignalStrength(nc)) && (onlyImmutable || satisfiedByUids(nc)) - && (onlyImmutable || satisfiedBySSID(nc))); + && (onlyImmutable || satisfiedBySSID(nc))) + && (onlyImmutable || satisfiedByRequestor(nc)); } /** @@ -1488,7 +1508,7 @@ public final class NetworkCapabilities implements Parcelable { public boolean equals(@Nullable Object obj) { if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; NetworkCapabilities that = (NetworkCapabilities) obj; - return (equalsNetCapabilities(that) + return equalsNetCapabilities(that) && equalsTransportTypes(that) && equalsLinkBandwidths(that) && equalsSignalStrength(that) @@ -1496,7 +1516,8 @@ public final class NetworkCapabilities implements Parcelable { && equalsTransportInfo(that) && equalsUids(that) && equalsSSID(that) - && equalsPrivateDnsBroken(that)); + && equalsPrivateDnsBroken(that) + && equalsRequestor(that); } @Override @@ -1514,7 +1535,9 @@ public final class NetworkCapabilities implements Parcelable { + Objects.hashCode(mUids) * 31 + Objects.hashCode(mSSID) * 37 + Objects.hashCode(mTransportInfo) * 41 - + Objects.hashCode(mPrivateDnsBroken) * 43; + + Objects.hashCode(mPrivateDnsBroken) * 43 + + Objects.hashCode(mRequestorUid) * 47 + + Objects.hashCode(mRequestorPackageName) * 53; } @Override @@ -1537,6 +1560,8 @@ public final class NetworkCapabilities implements Parcelable { dest.writeBoolean(mPrivateDnsBroken); dest.writeList(mAdministratorUids); dest.writeInt(mOwnerUid); + dest.writeInt(mRequestorUid); + dest.writeString(mRequestorPackageName); } public static final @android.annotation.NonNull Creator CREATOR = @@ -1559,6 +1584,8 @@ public final class NetworkCapabilities implements Parcelable { netCap.mPrivateDnsBroken = in.readBoolean(); netCap.setAdministratorUids(in.readArrayList(null)); netCap.mOwnerUid = in.readInt(); + netCap.mRequestorUid = in.readInt(); + netCap.mRequestorPackageName = in.readString(); return netCap; } @Override @@ -1624,6 +1651,9 @@ public final class NetworkCapabilities implements Parcelable { sb.append(" Private DNS is broken"); } + sb.append(" RequestorUid: ").append(mRequestorUid); + sb.append(" RequestorPackageName: ").append(mRequestorPackageName); + sb.append("]"); return sb.toString(); } @@ -1632,6 +1662,7 @@ public final class NetworkCapabilities implements Parcelable { private interface NameOf { String nameOf(int value); } + /** * @hide */ @@ -1799,4 +1830,120 @@ public final class NetworkCapabilities implements Parcelable { private boolean equalsPrivateDnsBroken(NetworkCapabilities nc) { return mPrivateDnsBroken == nc.mPrivateDnsBroken; } + + /** + * Set the uid of the app making the request. + * + * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in + * via the public {@link ConnectivityManager} API's will have this field overwritten. + * + * @param uid UID of the app. + * @hide + */ + @SystemApi + public @NonNull NetworkCapabilities setRequestorUid(int uid) { + mRequestorUid = uid; + return this; + } + + /** + * @return the uid of the app making the request. + * + * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest} + * object was not obtained from {@link ConnectivityManager}. + * @hide + */ + public int getRequestorUid() { + return mRequestorUid; + } + + /** + * Set the package name of the app making the request. + * + * Note: This works only for {@link NetworkAgent} instances. Any capabilities passed in + * via the public {@link ConnectivityManager} API's will have this field overwritten. + * + * @param packageName package name of the app. + * @hide + */ + @SystemApi + public @NonNull NetworkCapabilities setRequestorPackageName(@NonNull String packageName) { + mRequestorPackageName = packageName; + return this; + } + + /** + * @return the package name of the app making the request. + * + * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained + * from {@link ConnectivityManager}. + * @hide + */ + @Nullable + public String getRequestorPackageName() { + return mRequestorPackageName; + } + + /** + * Set the uid and package name of the app making the request. + * + * Note: This is intended to be only invoked from within connectivitiy service. + * + * @param uid UID of the app. + * @param packageName package name of the app. + * @hide + */ + public @NonNull NetworkCapabilities setRequestorUidAndPackageName( + int uid, @NonNull String packageName) { + return setRequestorUid(uid).setRequestorPackageName(packageName); + } + + /** + * Test whether the passed NetworkCapabilities satisfies the requestor restrictions of this + * capabilities. + * + * This method is called on the NetworkCapabilities embedded in a request with the + * capabilities of an available network. If the available network, sets a specific + * requestor (by uid and optionally package name), then this will only match a request from the + * same app. If either of the capabilities have an unset uid or package name, then it matches + * everything. + *

+ * nc is assumed nonnull. Else, NPE. + */ + private boolean satisfiedByRequestor(NetworkCapabilities nc) { + // No uid set, matches everything. + if (mRequestorUid == Process.INVALID_UID || nc.mRequestorUid == Process.INVALID_UID) { + return true; + } + // uids don't match. + if (mRequestorUid != nc.mRequestorUid) return false; + // No package names set, matches everything + if (null == nc.mRequestorPackageName || null == mRequestorPackageName) return true; + // check for package name match. + return TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName); + } + + /** + * Combine requestor info of the capabilities. + *

+ * This is only legal if either the requestor info of this object is reset, or both info are + * equal. + * nc is assumed nonnull. + */ + private void combineRequestor(@NonNull NetworkCapabilities nc) { + if (mRequestorUid != Process.INVALID_UID && mRequestorUid != nc.mOwnerUid) { + throw new IllegalStateException("Can't combine two uids"); + } + if (mRequestorPackageName != null + && !mRequestorPackageName.equals(nc.mRequestorPackageName)) { + throw new IllegalStateException("Can't combine two package names"); + } + setRequestorUid(nc.mRequestorUid); + setRequestorPackageName(nc.mRequestorPackageName); + } + + private boolean equalsRequestor(NetworkCapabilities nc) { + return mRequestorUid == nc.mRequestorUid + && TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName); + } } diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index ee4379a85b6b..b0bf64ecec56 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -380,6 +380,7 @@ public class NetworkRequest implements Parcelable { dest.writeInt(requestId); dest.writeString(type.name()); } + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public NetworkRequest createFromParcel(Parcel in) { @@ -494,6 +495,31 @@ public class NetworkRequest implements Parcelable { return networkCapabilities.getNetworkSpecifier(); } + /** + * @return the uid of the app making the request. + * + * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest} object was + * not obtained from {@link ConnectivityManager}. + * @hide + */ + @SystemApi + public int getRequestorUid() { + return networkCapabilities.getRequestorUid(); + } + + /** + * @return the package name of the app making the request. + * + * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained + * from {@link ConnectivityManager}. + * @hide + */ + @SystemApi + @Nullable + public String getRequestorPackageName() { + return networkCapabilities.getRequestorPackageName(); + } + public String toString() { return "NetworkRequest [ " + type + " id=" + requestId + (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") + diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java index cf31d217c967..2dd0c4e207fe 100644 --- a/core/java/android/net/NetworkSpecifier.java +++ b/core/java/android/net/NetworkSpecifier.java @@ -37,23 +37,6 @@ public abstract class NetworkSpecifier { @SystemApi public abstract boolean satisfiedBy(@Nullable NetworkSpecifier other); - /** - * Optional method which can be overridden by concrete implementations of NetworkSpecifier to - * check a self-reported UID. A concrete implementation may contain a UID which would be self- - * reported by the caller (since NetworkSpecifier implementations should be non-mutable). This - * function is called by ConnectivityService and is passed the actual UID of the caller - - * allowing the verification of the self-reported UID. In cases of mismatch the implementation - * should throw a SecurityException. - * - * @param requestorUid The UID of the requestor as obtained from its binder. - * - * @hide - */ - @SystemApi - public void assertValidFromUid(int requestorUid) { - // empty - } - /** * Optional method which can be overridden by concrete implementations of NetworkSpecifier to * perform any redaction of information from the NetworkSpecifier, e.g. if it contains diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index e91918ac6dbb..52a2ca974d40 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -615,7 +615,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private Set mWolSupportedInterfaces; - private TelephonyManager mTelephonyManager; + private final TelephonyManager mTelephonyManager; private final AppOpsManager mAppOpsManager; private final LocationPermissionChecker mLocationPermissionChecker; @@ -966,6 +966,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mDeps = checkNotNull(deps, "missing Dependencies"); mSystemProperties = mDeps.getSystemProperties(); mNetIdManager = mDeps.makeNetIdManager(); + mContext = checkNotNull(context, "missing Context"); mMetricsLog = logger; mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST); @@ -995,7 +996,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS); - mContext = checkNotNull(context, "missing Context"); mNMS = checkNotNull(netManager, "missing INetworkManagementService"); mStatsService = checkNotNull(statsService, "missing INetworkStatsService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); @@ -1175,6 +1175,7 @@ public class ConnectivityService extends IConnectivityManager.Stub int transportType, NetworkRequest.Type type) { final NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); + netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName()); if (transportType > -1) { netCap.addTransportType(transportType); } @@ -1705,10 +1706,12 @@ public class ConnectivityService extends IConnectivityManager.Stub return newLp; } - private void restrictRequestUidsForCaller(NetworkCapabilities nc) { + private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc, + int callerUid, String callerPackageName) { if (!checkSettingsPermission()) { - nc.setSingleUid(Binder.getCallingUid()); + nc.setSingleUid(callerUid); } + nc.setRequestorUidAndPackageName(callerUid, callerPackageName); nc.setAdministratorUids(Collections.EMPTY_LIST); // Clear owner UID; this can never come from an app. @@ -5334,7 +5337,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // This checks that the passed capabilities either do not request a // specific SSID/SignalStrength, or the calling app has permission to do so. private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc, - int callerPid, int callerUid) { + int callerPid, int callerUid, String callerPackageName) { if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) { throw new SecurityException("Insufficient permissions to request a specific SSID"); } @@ -5344,6 +5347,7 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new SecurityException( "Insufficient permissions to request a specific signal strength"); } + mAppOpsManager.checkPackage(callerUid, callerPackageName); } private ArrayList getSignalStrengthThresholds(NetworkAgentInfo nai) { @@ -5390,7 +5394,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(ns); - ns.assertValidFromUid(Binder.getCallingUid()); } private void ensureValid(NetworkCapabilities nc) { @@ -5402,7 +5405,9 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, int timeoutMs, IBinder binder, int legacyType) { + Messenger messenger, int timeoutMs, IBinder binder, int legacyType, + @NonNull String callingPackageName) { + final int callingUid = Binder.getCallingUid(); final NetworkRequest.Type type = (networkCapabilities == null) ? NetworkRequest.Type.TRACK_DEFAULT : NetworkRequest.Type.REQUEST; @@ -5410,7 +5415,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // the default network request. This allows callers to keep track of // the system default network. if (type == NetworkRequest.Type.TRACK_DEFAULT) { - networkCapabilities = createDefaultNetworkCapabilitiesForUid(Binder.getCallingUid()); + networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid); enforceAccessPermission(); } else { networkCapabilities = new NetworkCapabilities(networkCapabilities); @@ -5422,13 +5427,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } ensureRequestableCapabilities(networkCapabilities); ensureSufficientPermissionsForRequest(networkCapabilities, - Binder.getCallingPid(), Binder.getCallingUid()); + Binder.getCallingPid(), callingUid, callingPackageName); // Set the UID range for this request to the single UID of the requester, or to an empty // set of UIDs if the caller has the appropriate permission and UIDs have not been set. // This will overwrite any allowed UIDs in the requested capabilities. Though there // are no visible methods to set the UIDs, an app could use reflection to try and get // networks for other apps so it's essential that the UIDs are overwritten. - restrictRequestUidsForCaller(networkCapabilities); + restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities, + callingUid, callingPackageName); if (timeoutMs < 0) { throw new IllegalArgumentException("Bad timeout specified"); @@ -5503,16 +5509,18 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, - PendingIntent operation) { + PendingIntent operation, @NonNull String callingPackageName) { checkNotNull(operation, "PendingIntent cannot be null."); + final int callingUid = Binder.getCallingUid(); networkCapabilities = new NetworkCapabilities(networkCapabilities); enforceNetworkRequestPermissions(networkCapabilities); enforceMeteredApnPolicy(networkCapabilities); ensureRequestableCapabilities(networkCapabilities); ensureSufficientPermissionsForRequest(networkCapabilities, - Binder.getCallingPid(), Binder.getCallingUid()); + Binder.getCallingPid(), callingUid, callingPackageName); ensureValidNetworkSpecifier(networkCapabilities); - restrictRequestUidsForCaller(networkCapabilities); + restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities, + callingUid, callingPackageName); NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.REQUEST); @@ -5560,15 +5568,16 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, IBinder binder) { + Messenger messenger, IBinder binder, @NonNull String callingPackageName) { + final int callingUid = Binder.getCallingUid(); if (!hasWifiNetworkListenPermission(networkCapabilities)) { enforceAccessPermission(); } NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); ensureSufficientPermissionsForRequest(networkCapabilities, - Binder.getCallingPid(), Binder.getCallingUid()); - restrictRequestUidsForCaller(nc); + Binder.getCallingPid(), callingUid, callingPackageName); + restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName); // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get // onLost and onAvailable callbacks when networks move in and out of the background. @@ -5588,17 +5597,17 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void pendingListenForNetwork(NetworkCapabilities networkCapabilities, - PendingIntent operation) { + PendingIntent operation, @NonNull String callingPackageName) { checkNotNull(operation, "PendingIntent cannot be null."); + final int callingUid = Binder.getCallingUid(); if (!hasWifiNetworkListenPermission(networkCapabilities)) { enforceAccessPermission(); } ensureValid(networkCapabilities); ensureSufficientPermissionsForRequest(networkCapabilities, - Binder.getCallingPid(), Binder.getCallingUid()); - + Binder.getCallingPid(), callingUid, callingPackageName); final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); - restrictRequestUidsForCaller(nc); + restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName); NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); @@ -7897,12 +7906,13 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated." + " Please use NetworkCapabilities instead."); } - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackageName); + final int callingUid = Binder.getCallingUid(); + mAppOpsManager.checkPackage(callingUid, callingPackageName); // This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid // and administrator uids to be safe. final NetworkCapabilities nc = new NetworkCapabilities(request.networkCapabilities); - restrictRequestUidsForCaller(nc); + restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName); final NetworkRequest requestWithId = new NetworkRequest( diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index 3e4f3d818840..efea91ab91f0 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -272,9 +272,23 @@ public class NetworkCapabilitiesTest { netCap.setOwnerUid(123); assertParcelingIsLossless(netCap); netCap.setSSID(TEST_SSID); - assertParcelSane(netCap, 13); + assertParcelSane(netCap, 15); } + @Test + public void testParcelNetworkCapabilitiesWithRequestorUidAndPackageName() { + final NetworkCapabilities netCap = new NetworkCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .setRequestorUid(9304) + .setRequestorPackageName("com.android.test") + .addCapability(NET_CAPABILITY_EIMS) + .addCapability(NET_CAPABILITY_NOT_METERED); + assertParcelingIsLossless(netCap); + netCap.setSSID(TEST_SSID); + assertParcelSane(netCap, 15); + } + + @Test public void testOemPaid() { NetworkCapabilities nc = new NetworkCapabilities(); diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index 7ede14428a4f..d6bf334ee56a 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/tests/net/java/android/net/ConnectivityManagerTest.java @@ -212,7 +212,8 @@ public class ConnectivityManagerTest { ArgumentCaptor captor = ArgumentCaptor.forClass(Messenger.class); // register callback - when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt())) + when(mService.requestNetwork( + any(), captor.capture(), anyInt(), any(), anyInt(), any())) .thenReturn(request); manager.requestNetwork(request, callback, handler); @@ -240,7 +241,8 @@ public class ConnectivityManagerTest { ArgumentCaptor captor = ArgumentCaptor.forClass(Messenger.class); // register callback - when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt())) + when(mService.requestNetwork( + any(), captor.capture(), anyInt(), any(), anyInt(), any())) .thenReturn(req1); manager.requestNetwork(req1, callback, handler); @@ -258,7 +260,8 @@ public class ConnectivityManagerTest { verify(callback, timeout(100).times(0)).onLosing(any(), anyInt()); // callback can be registered again - when(mService.requestNetwork(any(), captor.capture(), anyInt(), any(), anyInt())) + when(mService.requestNetwork( + any(), captor.capture(), anyInt(), any(), anyInt(), any())) .thenReturn(req2); manager.requestNetwork(req2, callback, handler); @@ -282,7 +285,8 @@ public class ConnectivityManagerTest { info.targetSdkVersion = VERSION_CODES.N_MR1 + 1; when(mCtx.getApplicationInfo()).thenReturn(info); - when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt())).thenReturn(request); + when(mService.requestNetwork(any(), any(), anyInt(), any(), anyInt(), any())) + .thenReturn(request); Handler handler = new Handler(Looper.getMainLooper()); manager.requestNetwork(request, callback, handler); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index a906805d3a0c..77147c8a35af 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -108,6 +108,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -311,6 +312,7 @@ public class ConnectivityServiceTest { private static final String MOBILE_IFNAME = "test_rmnet_data0"; private static final String WIFI_IFNAME = "test_wlan0"; private static final String WIFI_WOL_IFNAME = "test_wlan_wol"; + private static final String TEST_PACKAGE_NAME = "com.android.test.package"; private static final String[] EMPTY_STRING_ARRAY = new String[0]; private MockContext mServiceContext; @@ -666,7 +668,7 @@ public class ConnectivityServiceTest { if (mNmValidationRedirectUrl != null) { mNmCallbacks.showProvisioningNotification( - "test_provisioning_notif_action", "com.android.test.package"); + "test_provisioning_notif_action", TEST_PACKAGE_NAME); mNmProvNotificationRequested = true; } } @@ -3039,7 +3041,7 @@ public class ConnectivityServiceTest { networkCapabilities.addTransportType(TRANSPORT_WIFI) .setNetworkSpecifier(new MatchAllNetworkSpecifier()); mService.requestNetwork(networkCapabilities, null, 0, null, - ConnectivityManager.TYPE_WIFI); + ConnectivityManager.TYPE_WIFI, TEST_PACKAGE_NAME); }); class NonParcelableSpecifier extends NetworkSpecifier { @@ -3078,31 +3080,12 @@ public class ConnectivityServiceTest { } @Test - public void testNetworkSpecifierUidSpoofSecurityException() throws Exception { - class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable { - @Override - public boolean satisfiedBy(NetworkSpecifier other) { - return true; - } - - @Override - public void assertValidFromUid(int requestorUid) { - throw new SecurityException("failure"); - } - - @Override - public int describeContents() { return 0; } - @Override - public void writeToParcel(Parcel dest, int flags) {} - } - + public void testNetworkRequestUidSpoofSecurityException() throws Exception { mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); - - UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier(); - NetworkRequest networkRequest = newWifiRequestBuilder().setNetworkSpecifier( - networkSpecifier).build(); + NetworkRequest networkRequest = newWifiRequestBuilder().build(); TestNetworkCallback networkCallback = new TestNetworkCallback(); + doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString()); assertThrows(SecurityException.class, () -> { mCm.requestNetwork(networkRequest, networkCallback); }); diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java index 24aa23aec7ae..20fbc9f61a17 100644 --- a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java +++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java @@ -199,12 +199,6 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements return sb.toString(); } - @Override - public void assertValidFromUid(int requestorUid) { - throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used " - + "for requests."); - } - @Override public NetworkSpecifier redact() { return null; diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java index 6c2d7ff882d3..e1d3c434acdb 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java @@ -598,12 +598,4 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc // not make much sense! return equals(other); } - - /** @hide */ - @Override - public void assertValidFromUid(int requestorUid) { - if (this.requestorUid != requestorUid) { - throw new SecurityException("mismatched UIDs"); - } - } } diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java index 9164d04885b3..282fda8e1b14 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java @@ -143,12 +143,6 @@ public class WifiAwareAgentNetworkSpecifier extends NetworkSpecifier implements return mNetworkSpecifiers.contains(nsBytes); } - @Override - public void assertValidFromUid(int requestorUid) { - throw new SecurityException( - "WifiAwareAgentNetworkSpecifier should not be used in network requests"); - } - @Override public NetworkSpecifier redact() { return null; diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java index 0511f2411647..ad656e1476b2 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java @@ -289,14 +289,6 @@ public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements return sb.toString(); } - /** @hide */ - @Override - public void assertValidFromUid(int requestorUid) { - if (this.requestorUid != requestorUid) { - throw new SecurityException("mismatched UIDs"); - } - } - /** * A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a * peer. diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java index e6eece85cb19..38040ea08eba 100644 --- a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java +++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java @@ -70,16 +70,6 @@ public class WifiNetworkAgentSpecifierTest { assertEquals(specifier, parcelSpecifier); } - /** - * Validate that the NetworkAgentSpecifier cannot be used in a {@link NetworkRequest} by apps. - */ - @Test(expected = IllegalStateException.class) - public void testWifiNetworkAgentSpecifierNotUsedInNetworkRequest() { - WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier(); - - specifier.assertValidFromUid(TEST_UID); - } - /** * Validate NetworkAgentSpecifier equals with itself. * a) Create network agent specifier 1 for WPA_PSK network diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java index c3b62854f12c..ef9c6a389db7 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java @@ -162,17 +162,6 @@ public class WifiAwareAgentNetworkSpecifierTest { collector.checkThat("Match unexpected", oldNs.satisfiedBy(newNs), equalTo(false)); } - /** - * Validate that agent network specifier cannot be used as in network requests - i.e. that - * throws an exception when queried for UID validity. - */ - @Test(expected = SecurityException.class) - public void testNoUsageInRequest() { - WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(); - - dut.assertValidFromUid(0); - } - // utilities /** -- GitLab From dd12316b0d6795f4d952110a04890c231dfa6da3 Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Tue, 18 Feb 2020 15:00:39 +0800 Subject: [PATCH 089/143] Add DEBUG flag for rounded corner and display cutout path There wasn't a good approach for engineers to distignlish bounds between H/W display component and S/W anti-aliasing. Allow enable color to review the anti-aliasing effect. Test: adb root; adb shell setprop debug.screenshot_rounded_corners true; Test: adb shell pidof com.android.systemui |xargs -i adb shell kill -9 {} Test: check visual following above steps Test: atest SystemUITests Test: atest ScreenDecorationsTest Change-Id: I87f04b50945e1500babdf9fa7ba9cdb37010fde8 Merged-In: I87f04b50945e1500babdf9fa7ba9cdb37010fde8 --- .../SystemUI/src/com/android/systemui/ScreenDecorations.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index f38b4f259c88..6f597e83bda8 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -105,6 +105,7 @@ public class ScreenDecorations extends SystemUI implements Tunable, private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS = SystemProperties.getBoolean("debug.screenshot_rounded_corners", false); private static final boolean VERBOSE = false; + private static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS; private DisplayManager mDisplayManager; private DisplayManager.DisplayListener mDisplayListener; @@ -457,6 +458,9 @@ public class ScreenDecorations extends SystemUI implements Tunable, private void updateColorInversion(int colorsInvertedValue) { int tint = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK; + if (DEBUG_COLOR) { + tint = Color.RED; + } ColorStateList tintList = ColorStateList.valueOf(tint); ((ImageView) mOverlay.findViewById(R.id.left)).setImageTintList(tintList); ((ImageView) mOverlay.findViewById(R.id.right)).setImageTintList(tintList); -- GitLab From b85c9eaa2478ba8a4ca37a2e7628984fbd88ada1 Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 20 Feb 2020 13:45:36 -0500 Subject: [PATCH 090/143] DO NOT MERGE Set background drawable on status_bar_container Put the background drawable on status_bar_container instead of status_bar because we always want the status bar background to fill the entire container. status_bar receives new margins when corner display cutouts are enabled which may prevent status_bar from taking up the entire status_bar_container space. Test: atest SystemUITests Bug: 148355955 Change-Id: Ic7e0c0a79908d2a58d4595d239062435253edfda --- packages/SystemUI/res/layout/status_bar.xml | 1 - .../SystemUI/res/layout/super_status_bar.xml | 3 ++- .../phone/PhoneStatusBarTransitions.java | 22 +++++++++---------- .../statusbar/phone/PhoneStatusBarView.java | 7 ------ .../systemui/statusbar/phone/StatusBar.java | 14 ++++++------ .../statusbar/phone/StatusBarWindowView.java | 9 ++++++-- 6 files changed, 26 insertions(+), 30 deletions(-) diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 4fae3c500a45..f8db97dbf800 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -24,7 +24,6 @@ android:layout_width="match_parent" android:layout_height="@dimen/status_bar_height" android:id="@+id/status_bar" - android:background="@drawable/system_bar_background" android:orientation="vertical" android:focusable="false" android:descendantFocusability="afterDescendants" diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index a91493003bb5..9d56e08bc555 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -54,7 +54,8 @@ + android:layout_height="wrap_content" + android:background="@drawable/system_bar_background" /> Date: Fri, 14 Feb 2020 15:08:13 +0800 Subject: [PATCH 091/143] DO NOT MERGE Respect rounded.xml size in ScreenDecorations Suppose vendors will customize rounded.xml with corresponding multiple radius path and size, ScreenDecorations should not resize it by rounded_corner_radius in case jagged edges problem Test: atest SystemUITests Test: atest ScreenDecorationsTest Bug: 145707162 Bug: 148912090 Change-Id: Ie33526214072ad324ca00a10074ad212dfbf4258 --- packages/SystemUI/res/values/config.xml | 3 + .../android/systemui/ScreenDecorations.java | 24 +++++-- .../systemui/ScreenDecorationsTest.java | 65 +++++++++++++++++++ 3 files changed, 86 insertions(+), 6 deletions(-) diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 78318cb7e858..7fd9d3c7e1e8 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -480,4 +480,7 @@ -1 + + false + diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index f38b4f259c88..953e9f54ba28 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -45,6 +45,7 @@ import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; +import android.graphics.drawable.VectorDrawable; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.HandlerThread; @@ -129,6 +130,7 @@ public class ScreenDecorations extends SystemUI implements Tunable, private boolean mAssistHintBlocked = false; private boolean mIsReceivingNavBarColor = false; private boolean mInGesturalMode; + private boolean mIsRoundedCornerMultipleRadius; /** * Converts a set of {@link Rect}s into a {@link Region} @@ -323,6 +325,8 @@ public class ScreenDecorations extends SystemUI implements Tunable, private void startOnScreenDecorationsThread() { mRotation = RotationUtils.getExactRotation(mContext); mWindowManager = mContext.getSystemService(WindowManager.class); + mIsRoundedCornerMultipleRadius = mContext.getResources().getBoolean( + R.bool.config_roundedCornerMultipleRadius); updateRoundedCornerRadii(); if (hasRoundedCorners() || shouldDrawCutout() || shouldHostHandles()) { setupDecorations(); @@ -528,17 +532,24 @@ public class ScreenDecorations extends SystemUI implements Tunable, com.android.internal.R.dimen.rounded_corner_radius_top); final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.rounded_corner_radius_bottom); - final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault || mRoundedDefaultBottom != newRoundedDefaultBottom || mRoundedDefaultTop != newRoundedDefaultTop; if (roundedCornersChanged) { - mRoundedDefault = newRoundedDefault; - mRoundedDefaultTop = newRoundedDefaultTop; - mRoundedDefaultBottom = newRoundedDefaultBottom; - onTuningChanged(SIZE, null); + // If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the + // max(width, height) size of drawable/rounded.xml instead of rounded_corner_radius + if (mIsRoundedCornerMultipleRadius) { + final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); + mRoundedDefault = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight()); + mRoundedDefaultTop = mRoundedDefaultBottom = mRoundedDefault; + } else { + mRoundedDefault = newRoundedDefault; + mRoundedDefaultTop = newRoundedDefaultTop; + mRoundedDefaultBottom = newRoundedDefaultBottom; + } } + onTuningChanged(SIZE, null); } private void updateViews() { @@ -637,7 +648,8 @@ public class ScreenDecorations extends SystemUI implements Tunable, } private boolean hasRoundedCorners() { - return mRoundedDefault > 0 || mRoundedDefaultBottom > 0 || mRoundedDefaultTop > 0; + return mRoundedDefault > 0 || mRoundedDefaultBottom > 0 || mRoundedDefaultTop > 0 + || mIsRoundedCornerMultipleRadius; } private boolean shouldDrawCutout() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java index 3b5e12c4ef96..11b256a4da01 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java @@ -20,6 +20,8 @@ import static com.android.systemui.ScreenDecorations.rectsToRegion; import static com.android.systemui.tuner.TunablePadding.FLAG_END; import static com.android.systemui.tuner.TunablePadding.FLAG_START; +import static com.google.common.truth.Truth.assertThat; + import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -38,6 +40,7 @@ import static org.mockito.Mockito.when; import android.app.Fragment; import android.content.res.Configuration; import android.graphics.Rect; +import android.graphics.drawable.VectorDrawable; import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -148,6 +151,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { com.android.internal.R.dimen.rounded_corner_radius_bottom, 0); mContext.getOrCreateTestableResources() .addOverride(dimen.rounded_corner_content_padding, 0); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); mScreenDecorations.start(); // No views added. @@ -166,6 +171,55 @@ public class ScreenDecorationsTest extends SysuiTestCase { com.android.internal.R.dimen.rounded_corner_radius, 20); mContext.getOrCreateTestableResources() .addOverride(dimen.rounded_corner_content_padding, 20); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); + + mScreenDecorations.start(); + // Add 2 windows for rounded corners (top and bottom). + verify(mWindowManager, times(2)).addView(any(), any()); + + // Add 2 tag listeners for each of the fragments that are needed. + verify(mFragmentHostManager, times(2)).addTagListener(any(), any()); + // One tunable. + verify(mTunerService, times(1)).addTunable(any(), any()); + // One TunablePadding. + verify(mTunablePaddingService, times(1)).add(any(), anyString(), anyInt(), anyInt()); + } + + @Test + public void testRoundingRadius() { + final int testRadius = 1; + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius, testRadius); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius_top, testRadius); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius_bottom, testRadius); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); + + mScreenDecorations.start(); + // Size of corner view should same as rounded_corner_radius{_top|_bottom} + assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(testRadius); + assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(testRadius); + assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(testRadius); + } + + @Test + public void testRoundingMultipleRadius() { + final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded); + final int multipleRadiusSize = Math.max(d.getIntrinsicWidth(), d.getIntrinsicHeight()); + + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.dimen.rounded_corner_radius, 9999); + mContext.getOrCreateTestableResources() + .addOverride(dimen.rounded_corner_content_padding, 9999); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, true); mScreenDecorations.start(); // Add 2 windows for rounded corners (top and bottom). @@ -177,6 +231,10 @@ public class ScreenDecorationsTest extends SysuiTestCase { verify(mTunerService, times(1)).addTunable(any(), any()); // One TunablePadding. verify(mTunablePaddingService, times(1)).add(any(), anyString(), anyInt(), anyInt()); + // Size of corner view should exactly match max(width, height) of R.drawable.rounded + assertThat(mScreenDecorations.mRoundedDefault).isEqualTo(multipleRadiusSize); + assertThat(mScreenDecorations.mRoundedDefaultTop).isEqualTo(multipleRadiusSize); + assertThat(mScreenDecorations.mRoundedDefaultBottom).isEqualTo(multipleRadiusSize); } @Test @@ -224,6 +282,9 @@ public class ScreenDecorationsTest extends SysuiTestCase { com.android.internal.R.dimen.rounded_corner_radius_bottom, 0); mContext.getOrCreateTestableResources() .addOverride(dimen.rounded_corner_content_padding, 0); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); + when(mNavigationModeController.addListener(any())).thenReturn( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL); @@ -245,6 +306,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { com.android.internal.R.dimen.rounded_corner_radius_bottom, 0); mContext.getOrCreateTestableResources() .addOverride(dimen.rounded_corner_content_padding, 0); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); when(mNavigationModeController.addListener(any())).thenReturn( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON); @@ -296,6 +359,8 @@ public class ScreenDecorationsTest extends SysuiTestCase { com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false); mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.dimen.rounded_corner_radius, 20); + mContext.getOrCreateTestableResources() + .addOverride(R.bool.config_roundedCornerMultipleRadius, false); mScreenDecorations.start(); assertEquals(mScreenDecorations.mRoundedDefault, 20); -- GitLab From ba42f4a80a0a3d5419a01e7820a88a1690d21a57 Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Thu, 20 Feb 2020 16:22:21 -0800 Subject: [PATCH 092/143] DO NOT MERGE Fix Autohide functionality Make sure that opening the notification panel doesn't result in a "blip" in the nav bar visibility Bug: 147427386 Bug: 149021759 Bug: 149115608 Test: on hawk adb shell settings put global policy_control "immersive.navigation=*" swipe up from bottom of screen - make sure it autohides pull down notification panel - make sure the panel doesn't blip on sdk_gphone_x86 - atest SystemUITests Change-Id: I4b5244e5ff26fb23e687cd46bc105d4fb8251bc6 --- .../systemui/statusbar/car/CarStatusBar.java | 84 +++++++++++++++++++ .../statusbar/phone/AutoHideController.java | 17 ++-- .../statusbar/phone/AutoHideElement.java | 32 +++++++ .../phone/NavigationBarFragment.java | 10 ++- .../systemui/statusbar/phone/StatusBar.java | 8 ++ 5 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideElement.java diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index e0f398742ebc..228111aeabcb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.car; +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE; +import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -99,6 +102,8 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.phone.AutoHideElement; +import com.android.systemui.statusbar.phone.BarTransitions; import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; @@ -122,6 +127,7 @@ import java.util.Map; */ public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler { private static final String TAG = "CarStatusBar"; + private static final int MODE_INVALID = -1; // used to calculate how fast to open or close the window private static final float DEFAULT_FLING_VELOCITY = 0; // max time a fling animation takes @@ -268,6 +274,9 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } }; + private int mNavigationBarMode; + private BarTransitions mNavBarTransitions; + @Override public void start() { // Non blocking call to connect to car service. Call this early so that we'll be connected @@ -382,6 +391,18 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt Log.wtf(TAG, " mVolumeChangeCallback failed to connect to car ", e); } }); + + mAutoHideController.setNavigationBar(new AutoHideElement() { + @Override + public void synchronizeState() { + checkNavBarModes(); + } + + @Override + public boolean isSemiTransparent() { + return mNavigationBarMode == MODE_SEMI_TRANSPARENT; + } + }); } @Override @@ -421,6 +442,65 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mUserSwitcherController = Dependency.get(UserSwitcherController.class); } + @Override + public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, + int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, + boolean navbarColorManagedByIme) { + // Ensure we store the systemUiVisibility flags before the super call overwrites it. + int oldVal = getSystemUiVisibility(); + + super.setSystemUiVisibility(displayId, vis, fullscreenStackVis, dockedStackVis, mask, + fullscreenStackBounds, dockedStackBounds, navbarColorManagedByIme); + + if (displayId != getDisplayId()) { + return; + } + + int newVal = (oldVal & ~mask) | (vis & mask); + + // update navigation bar mode + int nbMode = mNavigationBarWindow == null ? MODE_INVALID : computeNavBarMode(oldVal, + newVal); + boolean nbModeChanged = nbMode != MODE_INVALID; + if (nbModeChanged) { + if (mNavigationBarMode != nbMode) { + mNavigationBarMode = nbMode; + checkNavBarModes(); + } + mAutoHideController.touchAutoHide(); + } + + mLightBarController.onNavigationVisibilityChanged( + vis, mask, nbModeChanged, mNavigationBarMode, navbarColorManagedByIme); + } + + @BarTransitions.TransitionMode + private int computeNavBarMode(int oldVis, int newVis) { + int oldMode = navBarMode(oldVis); + int newMode = navBarMode(newVis); + if (oldMode == newMode) { + return -1; // no mode change + } + return newMode; + } + + @BarTransitions.TransitionMode + private int navBarMode(int vis) { + if ((vis & View.NAVIGATION_BAR_TRANSIENT) != 0) { + return MODE_SEMI_TRANSPARENT; + } else { + return MODE_OPAQUE; + } + } + + /** + * Checks current navigation bar mode and make transitions. + */ + private void checkNavBarModes() { + boolean anim = isDeviceInteractive() && mBottomNavBarVisible; + mNavBarTransitions.transitionTo(mNavigationBarMode, anim); + } + @Override protected void setUpQuickSettingsTilePanel() { // ignore. @@ -920,7 +1000,9 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mNotificationViewController.setIsInForeground(false); // let the status bar know that the panel is closed setPanelExpanded(false); + mAutoHideController.userAutoHide(); } else { + mAutoHideController.cancelAutoHide(); mNotificationViewController.setIsInForeground(true); // let the status bar know that the panel is open mNotificationView.setVisibleNotificationsAsSeen(); @@ -995,6 +1077,8 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt if (mShowBottom) { mNavigationBarWindow = (ViewGroup) View.inflate(mContext, R.layout.navigation_bar_window, null); + mNavBarTransitions = new BarTransitions(mNavigationBarWindow, + R.drawable.nav_background); } if (mShowLeft) { mLeftNavigationBarWindow = (ViewGroup) View.inflate(mContext, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index 5912cd7b6433..1042b61ab4f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -47,7 +47,7 @@ public class AutoHideController implements CommandQueue.Callbacks { private final NotificationRemoteInputManager mRemoteInputManager; private final CommandQueue mCommandQueue; private StatusBar mStatusBar; - private NavigationBarFragment mNavigationBar; + private AutoHideElement mNavigationBar; @VisibleForTesting int mDisplayId; @@ -85,11 +85,11 @@ public class AutoHideController implements CommandQueue.Callbacks { } } - void setStatusBar(StatusBar statusBar) { + public void setStatusBar(StatusBar statusBar) { mStatusBar = statusBar; } - void setNavigationBar(NavigationBarFragment navigationBar) { + public void setNavigationBar(AutoHideElement navigationBar) { mNavigationBar = navigationBar; } @@ -158,7 +158,8 @@ public class AutoHideController implements CommandQueue.Callbacks { mAutoHideSuspended = (mSystemUiVisibility & getTransientMask()) != 0; } - void touchAutoHide() { + /** Schedule auto hide if necessary otherwise cancel any pending runnables. */ + public void touchAutoHide() { // update transient bar auto hide if ((hasStatusBar() && mStatusBar.getStatusBarMode() == MODE_SEMI_TRANSPARENT) || hasNavigationBar() && mNavigationBar.isSemiTransparent()) { @@ -172,13 +173,14 @@ public class AutoHideController implements CommandQueue.Callbacks { if (hasStatusBar()) { return () -> mStatusBar.checkBarModes(); } else if (hasNavigationBar()) { - return () -> mNavigationBar.checkNavBarModes(); + return () -> mNavigationBar.synchronizeState(); } else { return null; } } - private void cancelAutoHide() { + /** Remove any scheduled auto hide runnables. */ + public void cancelAutoHide() { mAutoHideSuspended = false; mHandler.removeCallbacks(mAutoHide); } @@ -202,7 +204,8 @@ public class AutoHideController implements CommandQueue.Callbacks { } } - private void userAutoHide() { + /** Schedule auto hide. */ + public void userAutoHide() { cancelAutoHide(); mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideElement.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideElement.java new file mode 100644 index 000000000000..8849519ba477 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideElement.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +/** An interface for a UI element controlled by the {@link AutoHideController}. */ +public interface AutoHideElement { + /** + * Synchronizes the UI State of this {@link AutoHideElement}. This method is posted as a + * {@link Runnable} on the main thread. + */ + void synchronizeState(); + + /** + * Returns {@code true} if the {@link AutoHideElement} is in a + * {@link BarTransitions#MODE_SEMI_TRANSPARENT} state. + */ + boolean isSemiTransparent(); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 9a5f35a979eb..cd27c827fce5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -120,7 +120,7 @@ import javax.inject.Inject; * on clicks and view states of the nav bar. */ public class NavigationBarFragment extends LifecycleFragment implements Callbacks, - NavigationModeController.ModeChangedListener { + NavigationModeController.ModeChangedListener, AutoHideElement { public static final String TAG = "NavigationBar"; private static final boolean DEBUG = false; @@ -970,10 +970,18 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mAutoHideController.setNavigationBar(this); } + // AutoHideElement + @Override public boolean isSemiTransparent() { return mNavigationBarMode == MODE_SEMI_TRANSPARENT; } + // AutoHideElement + @Override + public void synchronizeState() { + checkNavBarModes(); + } + private void checkBarModes() { // We only have status bar on default display now. if (mIsOnDefaultDisplay) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index c6dee5e9bdf5..7cae81b1996a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -2205,6 +2205,14 @@ public class StatusBar extends SystemUI implements DemoMode, navbarColorManagedByIme); } + protected final int getSystemUiVisibility() { + return mSystemUiVisibility; + } + + protected final int getDisplayId() { + return mDisplayId; + } + @Override public void showWirelessChargingAnimation(int batteryLevel) { if (mDozing || mKeyguardManager.isKeyguardLocked()) { -- GitLab From 48d8d370f3d1dac06719ca6a52bda5f45a1a533a Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 19 Feb 2020 15:13:56 +0800 Subject: [PATCH 093/143] RESTRICT AUTOMERGE Create separated tasks for different apps from startActivities Assume there are 2 applications A, B with different uids. There are 4 activities A1, A2, B1, B2 with default task affinity and launch mode. After A1 called startActivities(B1, A2, B2): Original : Task(A1, B1, A2, B2) This Change: Task(A1, B1), Task(A2, B2) In other words, the source caller cannot launch its activity above the activity of other application in the same task, and it can still launch activity of other application in its task. Bug: 145669109 Test: atest StartActivityTests# \ testStartActivitiesWithDiffUidNotInSameTask Change-Id: I97bd875146a52f62b8fe82235487ccefb2955e8e --- .../server/am/ActivityStartController.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index c926503da27d..240f01d159a7 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -334,6 +334,9 @@ public class ActivityStartController { } else { callingPid = callingUid = -1; } + boolean forceNewTask = false; + final int filterCallingUid = ActivityStarter.computeResolveFilterUid( + callingUid, realCallingUid, UserHandle.USER_NULL); final long origId = Binder.clearCallingIdentity(); try { synchronized (mService) { @@ -353,11 +356,13 @@ public class ActivityStartController { // Don't modify the client's object! intent = new Intent(intent); + if (forceNewTask) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } // Collect information about the target of the Intent. ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0, - null, userId, ActivityStarter.computeResolveFilterUid( - callingUid, realCallingUid, UserHandle.USER_NULL)); + null, userId, filterCallingUid); // TODO: New, check if this is correct aInfo = mService.getActivityInfoForUser(aInfo, userId); @@ -397,7 +402,17 @@ public class ActivityStartController { return res; } - resultTo = outActivity[0] != null ? outActivity[0].appToken : null; + final ActivityRecord started = outActivity[0]; + if (started != null && started.getUid() == filterCallingUid) { + // Only the started activity which has the same uid as the source caller can + // be the caller of next activity. + resultTo = started.appToken; + forceNewTask = false; + } else { + // Different apps not adjacent to the caller are forced to be new task. + resultTo = null; + forceNewTask = true; + } } } } finally { -- GitLab From b06dc6aa5b0a118cc8c836b64f661c7aa89a6631 Mon Sep 17 00:00:00 2001 From: Joshua Duong Date: Mon, 3 Dec 2018 15:21:46 -0800 Subject: [PATCH 094/143] [adbwifi] Make AdbManager changes for adb over WiFi. This CL has a couple of notable changes: - Add communication layer between adbd, system server, and Settings UI - Add system notification (Wireless debugging connected) when at least one device is connected. - Add trusted networks (BSSID) to the keystore. - Changed the keystore format to: - Currently, trusted networks don't have a expiration time. Also, only way to clear it is by blowing up the keystore (revoke permissions). - Add pairing mechanism: - Using libadbwifi_pairing_connection C++ library to pair a device using SPAKE2 protocol over TLS. - Register MDNS service for client discovery. - Removed ability to ctl.start/stop adbd from UsbDeviceManager - AdbService now controls when to do this Bug: 111434128, 119490154, 119492574 Test: Manual. From developer options: 1) USB debugging off, WiFi Debugging off - Ensure both transports are disabled by trying to connect via WiFi and USB. 2) USB debugging on, WiFi Debugging off - Connections via USB are available, WiFi is disabled 3) USB debugging off, WiFi Debugging on - Connections via WiFi are available (IP + port), USB is not available 4) USB debugging on, WiFi Debugging on - Check both transports work Change-Id: I9f87679d195da99a55b6faf7131da1f1af65fe01 Exempt-From-Owner-Approval: approved in aosp master (cherry picked from commit a5969b5a1d9fe08783c32ea23bead56252a74383) --- proto/src/system_messages.proto | 4 + .../server/adb/AdbDebuggingManager.java | 1267 ++++++++++++++++- .../com/android/server/adb/AdbService.java | 146 +- services/core/jni/Android.bp | 3 + ...android_server_adb_AdbDebuggingManager.cpp | 168 +++ services/core/jni/onload.cpp | 2 + .../android/server/usb/UsbDeviceManager.java | 27 +- 7 files changed, 1517 insertions(+), 100 deletions(-) create mode 100644 services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index ef071a43aa3e..2c7ea31043a2 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -230,6 +230,10 @@ message SystemMessage { // Package: android NOTE_TEST_HARNESS_MODE_ENABLED = 54; + // Display the Android Debug Protocol status + // Package: android + NOTE_ADB_WIFI_ACTIVE = 62; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java index 7cbb515fd03d..8a3f11206abe 100644 --- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java +++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java @@ -20,19 +20,36 @@ import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull; import android.annotation.TestApi; import android.app.ActivityManager; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; +import android.debug.AdbManager; import android.debug.AdbProtoEnums; import android.debug.AdbTransportType; +import android.debug.PairDevice; +import android.net.ConnectivityManager; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.net.NetworkInfo; import android.net.Uri; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; @@ -52,6 +69,8 @@ import android.util.Xml; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; +import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; import com.android.internal.util.dump.DualDumpOutputStream; @@ -71,6 +90,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -79,6 +100,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; /** * Provides communication to the Android Debug Bridge daemon to allow, deny, or clear public keysi @@ -87,6 +109,7 @@ import java.util.Set; public class AdbDebuggingManager { private static final String TAG = "AdbDebuggingManager"; private static final boolean DEBUG = false; + private static final boolean MDNS_DEBUG = false; private static final String ADBD_SOCKET = "adbd"; private static final String ADB_DIRECTORY = "misc/adb"; @@ -98,19 +121,39 @@ public class AdbDebuggingManager { private static final int BUFFER_SIZE = 65536; private final Context mContext; + private final ContentResolver mContentResolver; private final Handler mHandler; private AdbDebuggingThread mThread; - private boolean mAdbEnabled = false; + private boolean mAdbUsbEnabled = false; + private boolean mAdbWifiEnabled = false; private String mFingerprints; - private final List mConnectedKeys; + // A key can be used more than once (e.g. USB, wifi), so need to keep a refcount + private final Map mConnectedKeys; private String mConfirmComponent; private final File mTestUserKeyFile; + private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = + "persist.adb.tls_server.enable"; + private static final String WIFI_PERSISTENT_GUID = + "persist.adb.wifi.guid"; + private static final int PAIRING_CODE_LENGTH = 6; + private PairingThread mPairingThread = null; + // A list of keys connected via wifi + private final Set mWifiConnectedKeys; + // The current info of the adbwifi connection. + private AdbConnectionInfo mAdbConnectionInfo; + // Polls for a tls port property when adb wifi is enabled + private AdbConnectionPortPoller mConnectionPortPoller; + private final PortListenerImpl mPortListener = new PortListenerImpl(); + public AdbDebuggingManager(Context context) { mHandler = new AdbDebuggingHandler(FgThread.get().getLooper()); mContext = context; + mContentResolver = mContext.getContentResolver(); mTestUserKeyFile = null; - mConnectedKeys = new ArrayList<>(1); + mConnectedKeys = new HashMap(); + mWifiConnectedKeys = new HashSet(); + mAdbConnectionInfo = new AdbConnectionInfo(); } /** @@ -121,9 +164,178 @@ public class AdbDebuggingManager { protected AdbDebuggingManager(Context context, String confirmComponent, File testUserKeyFile) { mHandler = new AdbDebuggingHandler(FgThread.get().getLooper()); mContext = context; + mContentResolver = mContext.getContentResolver(); mConfirmComponent = confirmComponent; mTestUserKeyFile = testUserKeyFile; - mConnectedKeys = new ArrayList<>(); + mConnectedKeys = new HashMap(); + mWifiConnectedKeys = new HashSet(); + mAdbConnectionInfo = new AdbConnectionInfo(); + } + + class PairingThread extends Thread implements NsdManager.RegistrationListener { + private NsdManager mNsdManager; + private String mPublicKey; + private String mPairingCode; + private String mGuid; + private String mServiceName; + private final String mServiceType = "_adb_secure_pairing._tcp."; + private int mPort; + + private native int native_pairing_start(String guid, String password); + private native void native_pairing_cancel(); + private native boolean native_pairing_wait(); + + PairingThread(String pairingCode, String serviceName) { + super(TAG); + mPairingCode = pairingCode; + mGuid = SystemProperties.get(WIFI_PERSISTENT_GUID); + mServiceName = serviceName; + if (serviceName == null || serviceName.isEmpty()) { + mServiceName = mGuid; + } + mPort = -1; + mNsdManager = (NsdManager) mContext.getSystemService(Context.NSD_SERVICE); + } + + @Override + public void run() { + if (mGuid.isEmpty()) { + Slog.e(TAG, "adbwifi guid was not set"); + return; + } + mPort = native_pairing_start(mGuid, mPairingCode); + if (mPort <= 0 || mPort > 65535) { + Slog.e(TAG, "Unable to start pairing server"); + return; + } + + // Register the mdns service + NsdServiceInfo serviceInfo = new NsdServiceInfo(); + serviceInfo.setServiceName(mServiceName); + serviceInfo.setServiceType(mServiceType); + serviceInfo.setPort(mPort); + mNsdManager.registerService(serviceInfo, NsdManager.PROTOCOL_DNS_SD, this); + + // Send pairing port to UI + Message msg = mHandler.obtainMessage( + AdbDebuggingHandler.MSG_RESPONSE_PAIRING_PORT); + msg.obj = mPort; + mHandler.sendMessage(msg); + + boolean paired = native_pairing_wait(); + if (DEBUG) { + if (mPublicKey != null) { + Slog.i(TAG, "Pairing succeeded key=" + mPublicKey); + } else { + Slog.i(TAG, "Pairing failed"); + } + } + + mNsdManager.unregisterService(this); + + Bundle bundle = new Bundle(); + bundle.putString("publicKey", paired ? mPublicKey : null); + Message message = Message.obtain(mHandler, + AdbDebuggingHandler.MSG_RESPONSE_PAIRING_RESULT, + bundle); + mHandler.sendMessage(message); + } + + public void cancelPairing() { + native_pairing_cancel(); + } + + @Override + public void onServiceRegistered(NsdServiceInfo serviceInfo) { + if (MDNS_DEBUG) Slog.i(TAG, "Registered pairing service: " + serviceInfo); + } + + @Override + public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + Slog.e(TAG, "Failed to register pairing service(err=" + errorCode + + "): " + serviceInfo); + cancelPairing(); + } + + @Override + public void onServiceUnregistered(NsdServiceInfo serviceInfo) { + if (MDNS_DEBUG) Slog.i(TAG, "Unregistered pairing service: " + serviceInfo); + } + + @Override + public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { + Slog.w(TAG, "Failed to unregister pairing service(err=" + errorCode + + "): " + serviceInfo); + } + } + + interface AdbConnectionPortListener { + void onPortReceived(int port); + } + + /** + * This class will poll for a period of time for adbd to write the port + * it connected to. + * + * TODO(joshuaduong): The port is being sent via system property because the adbd socket + * (AdbDebuggingManager) is not created when ro.adb.secure=0. Thus, we must communicate the + * port through different means. A better fix would be to always start AdbDebuggingManager, but + * it needs to adjust accordingly on whether ro.adb.secure is set. + */ + static class AdbConnectionPortPoller extends Thread { + private final String mAdbPortProp = "service.adb.tls.port"; + private AdbConnectionPortListener mListener; + private final int mDurationSecs = 10; + private AtomicBoolean mCanceled = new AtomicBoolean(false); + + AdbConnectionPortPoller(AdbConnectionPortListener listener) { + mListener = listener; + } + + @Override + public void run() { + if (DEBUG) Slog.d(TAG, "Starting adb port property poller"); + // Once adbwifi is enabled, we poll the service.adb.tls.port + // system property until we get the port, or -1 on failure. + // Let's also limit the polling to 10 seconds, just in case + // something went wrong. + for (int i = 0; i < mDurationSecs; ++i) { + if (mCanceled.get()) { + return; + } + + // If the property is set to -1, then that means adbd has failed + // to start the server. Otherwise we should have a valid port. + int port = SystemProperties.getInt(mAdbPortProp, Integer.MAX_VALUE); + if (port == -1 || (port > 0 && port <= 65535)) { + mListener.onPortReceived(port); + return; + } + SystemClock.sleep(1000); + } + Slog.w(TAG, "Failed to receive adb connection port"); + mListener.onPortReceived(-1); + } + + public void cancelAndWait() { + mCanceled.set(true); + if (this.isAlive()) { + try { + this.join(); + } catch (InterruptedException e) { + } + } + } + } + + class PortListenerImpl implements AdbConnectionPortListener { + public void onPortReceived(int port) { + Message msg = mHandler.obtainMessage(port > 0 + ? AdbDebuggingHandler.MSG_SERVER_CONNECTED + : AdbDebuggingHandler.MSG_SERVER_DISCONNECTED); + msg.obj = port; + mHandler.sendMessage(msg); + } } class AdbDebuggingThread extends Thread { @@ -213,6 +425,46 @@ public class AdbDebuggingManager { AdbDebuggingHandler.MESSAGE_ADB_CONNECTED_KEY); msg.obj = key; mHandler.sendMessage(msg); + } else if (buffer[0] == 'W' && buffer[1] == 'E') { + // adbd_auth.h and AdbTransportType.aidl need to be kept in + // sync. + byte transportType = buffer[2]; + String key = new String(Arrays.copyOfRange(buffer, 3, count)); + if (transportType == AdbTransportType.USB) { + Slog.d(TAG, "Received USB TLS connected key message: " + key); + Message msg = mHandler.obtainMessage( + AdbDebuggingHandler.MESSAGE_ADB_CONNECTED_KEY); + msg.obj = key; + mHandler.sendMessage(msg); + } else if (transportType == AdbTransportType.WIFI) { + Slog.d(TAG, "Received WIFI TLS connected key message: " + key); + Message msg = mHandler.obtainMessage( + AdbDebuggingHandler.MSG_WIFI_DEVICE_CONNECTED); + msg.obj = key; + mHandler.sendMessage(msg); + } else { + Slog.e(TAG, "Got unknown transport type from adbd (" + transportType + + ")"); + } + } else if (buffer[0] == 'W' && buffer[1] == 'F') { + byte transportType = buffer[2]; + String key = new String(Arrays.copyOfRange(buffer, 3, count)); + if (transportType == AdbTransportType.USB) { + Slog.d(TAG, "Received USB TLS disconnect message: " + key); + Message msg = mHandler.obtainMessage( + AdbDebuggingHandler.MESSAGE_ADB_DISCONNECT); + msg.obj = key; + mHandler.sendMessage(msg); + } else if (transportType == AdbTransportType.WIFI) { + Slog.d(TAG, "Received WIFI TLS disconnect key message: " + key); + Message msg = mHandler.obtainMessage( + AdbDebuggingHandler.MSG_WIFI_DEVICE_DISCONNECTED); + msg.obj = key; + mHandler.sendMessage(msg); + } else { + Slog.e(TAG, "Got unknown transport type from adbd (" + transportType + + ")"); + } } else { Slog.e(TAG, "Wrong message: " + (new String(Arrays.copyOfRange(buffer, 0, 2)))); @@ -268,7 +520,156 @@ public class AdbDebuggingManager { } } + class AdbConnectionInfo { + private String mBssid; + private String mSsid; + private int mPort; + + AdbConnectionInfo() { + mBssid = ""; + mSsid = ""; + mPort = -1; + } + + AdbConnectionInfo(String bssid, String ssid) { + mBssid = bssid; + mSsid = ssid; + } + + AdbConnectionInfo(AdbConnectionInfo other) { + mBssid = other.mBssid; + mSsid = other.mSsid; + mPort = other.mPort; + } + + public String getBSSID() { + return mBssid; + } + + public String getSSID() { + return mSsid; + } + + public int getPort() { + return mPort; + } + + public void setPort(int port) { + mPort = port; + } + + public void clear() { + mBssid = ""; + mSsid = ""; + mPort = -1; + } + } + + private void setAdbConnectionInfo(AdbConnectionInfo info) { + synchronized (mAdbConnectionInfo) { + if (info == null) { + mAdbConnectionInfo.clear(); + return; + } + mAdbConnectionInfo = info; + } + } + + private AdbConnectionInfo getAdbConnectionInfo() { + synchronized (mAdbConnectionInfo) { + return new AdbConnectionInfo(mAdbConnectionInfo); + } + } + class AdbDebuggingHandler extends Handler { + private NotificationManager mNotificationManager; + private boolean mAdbNotificationShown; + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + // We only care about when wifi is disabled, and when there is a wifi network + // change. + if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { + int state = intent.getIntExtra( + WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED); + if (state == WifiManager.WIFI_STATE_DISABLED) { + Slog.i(TAG, "Wifi disabled. Disabling adbwifi."); + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + } + } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { + // We only care about wifi type connections + NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra( + WifiManager.EXTRA_NETWORK_INFO); + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { + // Check for network disconnect + if (!networkInfo.isConnected()) { + Slog.i(TAG, "Network disconnected. Disabling adbwifi."); + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + return; + } + + WifiManager wifiManager = + (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + if (wifiInfo == null || wifiInfo.getNetworkId() == -1) { + Slog.i(TAG, "Not connected to any wireless network." + + " Not enabling adbwifi."); + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + } + + // Check for network change + String bssid = wifiInfo.getBSSID(); + if (bssid == null || bssid.isEmpty()) { + Slog.e(TAG, "Unable to get the wifi ap's BSSID. Disabling adbwifi."); + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + } + synchronized (mAdbConnectionInfo) { + if (!bssid.equals(mAdbConnectionInfo.getBSSID())) { + Slog.i(TAG, "Detected wifi network change. Disabling adbwifi."); + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + } + } + } + } + } + }; + + private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv"; + + private boolean isTv() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK); + } + + private void setupNotifications() { + if (mNotificationManager != null) { + return; + } + mNotificationManager = (NotificationManager) + mContext.getSystemService(Context.NOTIFICATION_SERVICE); + if (mNotificationManager == null) { + Slog.e(TAG, "Unable to setup notifications for wireless debugging"); + return; + } + + // Ensure that the notification channels are set up + if (isTv()) { + // TV-specific notification channel + mNotificationManager.createNotificationChannel( + new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV, + mContext.getString( + com.android.internal.R.string + .adb_debugging_notification_channel_tv), + NotificationManager.IMPORTANCE_HIGH)); + } + } + // The default time to schedule the job to keep the keystore updated with a currently // connected key as well as to removed expired keys. static final long UPDATE_KEYSTORE_JOB_INTERVAL = 86400000; @@ -288,8 +689,50 @@ public class AdbDebuggingManager { static final int MESSAGE_ADB_UPDATE_KEYSTORE = 9; static final int MESSAGE_ADB_CONNECTED_KEY = 10; + // === Messages from the UI ============== + // UI asks adbd to enable adbdwifi + static final int MSG_ADBDWIFI_ENABLE = 11; + // UI asks adbd to disable adbdwifi + static final int MSG_ADBDWIFI_DISABLE = 12; + // Cancel pairing + static final int MSG_PAIRING_CANCEL = 14; + // Enable pairing by pairing code + static final int MSG_PAIR_PAIRING_CODE = 15; + // Enable pairing by QR code + static final int MSG_PAIR_QR_CODE = 16; + // UI asks to unpair (forget) a device. + static final int MSG_REQ_UNPAIR = 17; + // User allows debugging on the current network + static final int MSG_ADBWIFI_ALLOW = 18; + // User denies debugging on the current network + static final int MSG_ADBWIFI_DENY = 19; + + // === Messages from the PairingThread =========== + // Result of the pairing + static final int MSG_RESPONSE_PAIRING_RESULT = 20; + // The port opened for pairing + static final int MSG_RESPONSE_PAIRING_PORT = 21; + + // === Messages from adbd ================ + // Notifies us a wifi device connected. + static final int MSG_WIFI_DEVICE_CONNECTED = 22; + // Notifies us a wifi device disconnected. + static final int MSG_WIFI_DEVICE_DISCONNECTED = 23; + // Notifies us the TLS server is connected and listening + static final int MSG_SERVER_CONNECTED = 24; + // Notifies us the TLS server is disconnected + static final int MSG_SERVER_DISCONNECTED = 25; + + // === Messages we can send to adbd =========== + static final String MSG_DISCONNECT_DEVICE = "DD"; + static final String MSG_DISABLE_ADBDWIFI = "DA"; + private AdbKeyStore mAdbKeyStore; + // Usb, Wi-Fi transports can be enabled together or separately, so don't break the framework + // connection unless all transport types are disconnected. + private int mAdbEnabledRefCount = 0; + private ContentObserver mAuthTimeObserver = new ContentObserver(this) { @Override public void onChange(boolean selfChange, Uri uri) { @@ -314,44 +757,111 @@ public class AdbDebuggingManager { mAdbKeyStore = adbKeyStore; } + // Show when at least one device is connected. + public void showAdbConnectedNotification(boolean show) { + final int id = SystemMessage.NOTE_ADB_WIFI_ACTIVE; + final int titleRes = com.android.internal.R.string.adbwifi_active_notification_title; + if (show == mAdbNotificationShown) { + return; + } + setupNotifications(); + if (!mAdbNotificationShown) { + Resources r = mContext.getResources(); + CharSequence title = r.getText(titleRes); + CharSequence message = r.getText( + com.android.internal.R.string.adbwifi_active_notification_message); + + Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, + intent, 0, null, UserHandle.CURRENT); + + Notification notification = + new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER) + .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) + .setWhen(0) + .setOngoing(true) + .setTicker(title) + .setDefaults(0) // please be quiet + .setColor(mContext.getColor( + com.android.internal.R.color + .system_notification_accent_color)) + .setContentTitle(title) + .setContentText(message) + .setContentIntent(pi) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .extend(new Notification.TvExtender() + .setChannelId(ADB_NOTIFICATION_CHANNEL_ID_TV)) + .build(); + mAdbNotificationShown = true; + mNotificationManager.notifyAsUser(null, id, notification, + UserHandle.ALL); + } else { + mAdbNotificationShown = false; + mNotificationManager.cancelAsUser(null, id, UserHandle.ALL); + } + } + + private void startAdbDebuggingThread() { + ++mAdbEnabledRefCount; + if (DEBUG) Slog.i(TAG, "startAdbDebuggingThread ref=" + mAdbEnabledRefCount); + if (mAdbEnabledRefCount > 1) { + return; + } + + registerForAuthTimeChanges(); + mThread = new AdbDebuggingThread(); + mThread.start(); + + mAdbKeyStore.updateKeyStore(); + scheduleJobToUpdateAdbKeyStore(); + } + + private void stopAdbDebuggingThread() { + --mAdbEnabledRefCount; + if (DEBUG) Slog.i(TAG, "stopAdbDebuggingThread ref=" + mAdbEnabledRefCount); + if (mAdbEnabledRefCount > 0) { + return; + } + + if (mThread != null) { + mThread.stopListening(); + mThread = null; + } + + if (!mConnectedKeys.isEmpty()) { + for (Map.Entry entry : mConnectedKeys.entrySet()) { + mAdbKeyStore.setLastConnectionTime(entry.getKey(), + System.currentTimeMillis()); + } + sendPersistKeyStoreMessage(); + mConnectedKeys.clear(); + mWifiConnectedKeys.clear(); + } + scheduleJobToUpdateAdbKeyStore(); + } + public void handleMessage(Message msg) { + if (mAdbKeyStore == null) { + mAdbKeyStore = new AdbKeyStore(); + } + switch (msg.what) { case MESSAGE_ADB_ENABLED: - if (mAdbEnabled) { + if (mAdbUsbEnabled) { break; } - registerForAuthTimeChanges(); - mAdbEnabled = true; - - mThread = new AdbDebuggingThread(); - mThread.start(); - - mAdbKeyStore = new AdbKeyStore(); - mAdbKeyStore.updateKeyStore(); - scheduleJobToUpdateAdbKeyStore(); + startAdbDebuggingThread(); + mAdbUsbEnabled = true; break; case MESSAGE_ADB_DISABLED: - if (!mAdbEnabled) { + if (!mAdbUsbEnabled) { break; } - - mAdbEnabled = false; - - if (mThread != null) { - mThread.stopListening(); - mThread = null; - } - - if (!mConnectedKeys.isEmpty()) { - for (String connectedKey : mConnectedKeys) { - mAdbKeyStore.setLastConnectionTime(connectedKey, - System.currentTimeMillis()); - } - sendPersistKeyStoreMessage(); - mConnectedKeys.clear(); - } - scheduleJobToUpdateAdbKeyStore(); + stopAdbDebuggingThread(); + mAdbUsbEnabled = false; break; case MESSAGE_ADB_ALLOW: { @@ -367,8 +877,8 @@ public class AdbDebuggingManager { if (mThread != null) { mThread.sendResponse("OK"); if (alwaysAllow) { - if (!mConnectedKeys.contains(key)) { - mConnectedKeys.add(key); + if (!mConnectedKeys.containsKey(key)) { + mConnectedKeys.put(key, 1); } mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); sendPersistKeyStoreMessage(); @@ -407,7 +917,7 @@ public class AdbDebuggingManager { } logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false); mFingerprints = fingerprints; - startConfirmation(key, mFingerprints); + startConfirmationForKey(key, mFingerprints); break; } @@ -419,6 +929,7 @@ public class AdbDebuggingManager { if (mAdbKeyStore == null) { mAdbKeyStore = new AdbKeyStore(); } + mWifiConnectedKeys.clear(); mAdbKeyStore.deleteKeyStore(); cancelJobToUpdateAdbKeyStore(); break; @@ -428,12 +939,17 @@ public class AdbDebuggingManager { String key = (String) msg.obj; boolean alwaysAllow = false; if (key != null && key.length() > 0) { - if (mConnectedKeys.contains(key)) { + if (mConnectedKeys.containsKey(key)) { alwaysAllow = true; - mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); - sendPersistKeyStoreMessage(); - scheduleJobToUpdateAdbKeyStore(); - mConnectedKeys.remove(key); + int refcount = mConnectedKeys.get(key) - 1; + if (refcount == 0) { + mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); + sendPersistKeyStoreMessage(); + scheduleJobToUpdateAdbKeyStore(); + mConnectedKeys.remove(key); + } else { + mConnectedKeys.put(key, refcount); + } } } else { Slog.w(TAG, "Received a disconnected key message with an empty key"); @@ -451,8 +967,8 @@ public class AdbDebuggingManager { case MESSAGE_ADB_UPDATE_KEYSTORE: { if (!mConnectedKeys.isEmpty()) { - for (String connectedKey : mConnectedKeys) { - mAdbKeyStore.setLastConnectionTime(connectedKey, + for (Map.Entry entry : mConnectedKeys.entrySet()) { + mAdbKeyStore.setLastConnectionTime(entry.getKey(), System.currentTimeMillis()); } sendPersistKeyStoreMessage(); @@ -469,8 +985,10 @@ public class AdbDebuggingManager { if (key == null || key.length() == 0) { Slog.w(TAG, "Received a connected key message with an empty key"); } else { - if (!mConnectedKeys.contains(key)) { - mConnectedKeys.add(key); + if (!mConnectedKeys.containsKey(key)) { + mConnectedKeys.put(key, 1); + } else { + mConnectedKeys.put(key, mConnectedKeys.get(key) + 1); } mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis()); sendPersistKeyStoreMessage(); @@ -479,6 +997,199 @@ public class AdbDebuggingManager { } break; } + case MSG_ADBDWIFI_ENABLE: { + if (mAdbWifiEnabled) { + break; + } + + AdbConnectionInfo currentInfo = getCurrentWifiApInfo(); + if (currentInfo == null) { + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + break; + } + + if (!verifyWifiNetwork(currentInfo.getBSSID(), + currentInfo.getSSID())) { + // This means that the network is not in the list of trusted networks. + // We'll give user a prompt on whether to allow wireless debugging on + // the current wifi network. + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + break; + } + + setAdbConnectionInfo(currentInfo); + IntentFilter intentFilter = + new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); + intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mContext.registerReceiver(mBroadcastReceiver, intentFilter); + + SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1"); + mConnectionPortPoller = + new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener); + mConnectionPortPoller.start(); + + startAdbDebuggingThread(); + mAdbWifiEnabled = true; + + if (DEBUG) Slog.i(TAG, "adb start wireless adb"); + break; + } + case MSG_ADBDWIFI_DISABLE: + if (!mAdbWifiEnabled) { + break; + } + mAdbWifiEnabled = false; + setAdbConnectionInfo(null); + mContext.unregisterReceiver(mBroadcastReceiver); + + if (mThread != null) { + mThread.sendResponse(MSG_DISABLE_ADBDWIFI); + } + onAdbdWifiServerDisconnected(-1); + stopAdbDebuggingThread(); + break; + case MSG_ADBWIFI_ALLOW: + if (mAdbWifiEnabled) { + break; + } + String bssid = (String) msg.obj; + boolean alwaysAllow = msg.arg1 == 1; + if (alwaysAllow) { + mAdbKeyStore.addTrustedNetwork(bssid); + } + + // Let's check again to make sure we didn't switch networks while verifying + // the wifi bssid. + AdbConnectionInfo newInfo = getCurrentWifiApInfo(); + if (newInfo == null || !bssid.equals(newInfo.getBSSID())) { + break; + } + + setAdbConnectionInfo(newInfo); + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 1); + IntentFilter intentFilter = + new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); + intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mContext.registerReceiver(mBroadcastReceiver, intentFilter); + + SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1"); + mConnectionPortPoller = + new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener); + mConnectionPortPoller.start(); + + startAdbDebuggingThread(); + mAdbWifiEnabled = true; + + if (DEBUG) Slog.i(TAG, "adb start wireless adb"); + break; + case MSG_ADBWIFI_DENY: + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + sendServerConnectionState(false, -1); + break; + case MSG_REQ_UNPAIR: { + String fingerprint = (String) msg.obj; + // Tell adbd to disconnect the device if connected. + String publicKey = mAdbKeyStore.findKeyFromFingerprint(fingerprint); + if (publicKey == null || publicKey.isEmpty()) { + Slog.e(TAG, "Not a known fingerprint [" + fingerprint + "]"); + break; + } + String cmdStr = MSG_DISCONNECT_DEVICE + publicKey; + if (mThread != null) { + mThread.sendResponse(cmdStr); + } + mAdbKeyStore.removeKey(publicKey); + // Send the updated paired devices list to the UI. + sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); + break; + } + case MSG_RESPONSE_PAIRING_RESULT: { + Bundle bundle = (Bundle) msg.obj; + String publicKey = bundle.getString("publicKey"); + onPairingResult(publicKey); + // Send the updated paired devices list to the UI. + sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); + break; + } + case MSG_RESPONSE_PAIRING_PORT: { + int port = (int) msg.obj; + sendPairingPortToUI(port); + break; + } + case MSG_PAIR_PAIRING_CODE: { + String pairingCode = createPairingCode(PAIRING_CODE_LENGTH); + updateUIPairCode(pairingCode); + mPairingThread = new PairingThread(pairingCode, null); + mPairingThread.start(); + break; + } + case MSG_PAIR_QR_CODE: { + Bundle bundle = (Bundle) msg.obj; + String serviceName = bundle.getString("serviceName"); + String password = bundle.getString("password"); + mPairingThread = new PairingThread(password, serviceName); + mPairingThread.start(); + break; + } + case MSG_PAIRING_CANCEL: + if (mPairingThread != null) { + mPairingThread.cancelPairing(); + try { + mPairingThread.join(); + } catch (InterruptedException e) { + Slog.w(TAG, "Error while waiting for pairing thread to quit."); + e.printStackTrace(); + } + mPairingThread = null; + } + break; + case MSG_WIFI_DEVICE_CONNECTED: { + String key = (String) msg.obj; + if (mWifiConnectedKeys.add(key)) { + sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); + showAdbConnectedNotification(true); + } + break; + } + case MSG_WIFI_DEVICE_DISCONNECTED: { + String key = (String) msg.obj; + if (mWifiConnectedKeys.remove(key)) { + sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); + if (mWifiConnectedKeys.isEmpty()) { + showAdbConnectedNotification(false); + } + } + break; + } + case MSG_SERVER_CONNECTED: { + int port = (int) msg.obj; + onAdbdWifiServerConnected(port); + synchronized (mAdbConnectionInfo) { + mAdbConnectionInfo.setPort(port); + } + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 1); + break; + } + case MSG_SERVER_DISCONNECTED: { + if (!mAdbWifiEnabled) { + break; + } + int port = (int) msg.obj; + onAdbdWifiServerDisconnected(port); + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + stopAdbDebuggingThread(); + if (mConnectionPortPoller != null) { + mConnectionPortPoller.cancelAndWait(); + mConnectionPortPoller = null; + } + break; + } } } @@ -540,6 +1251,142 @@ public class AdbDebuggingManager { private void cancelJobToUpdateAdbKeyStore() { removeMessages(AdbDebuggingHandler.MESSAGE_ADB_UPDATE_KEYSTORE); } + + // Generates a random string of digits with size |size|. + private String createPairingCode(int size) { + String res = ""; + SecureRandom rand = new SecureRandom(); + for (int i = 0; i < size; ++i) { + res += rand.nextInt(10); + } + + return res; + } + + private void sendServerConnectionState(boolean connected, int port) { + Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION); + intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, connected + ? AdbManager.WIRELESS_STATUS_CONNECTED + : AdbManager.WIRELESS_STATUS_DISCONNECTED); + intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } + + private void onAdbdWifiServerConnected(int port) { + // Send the paired devices list to the UI + sendPairedDevicesToUI(mAdbKeyStore.getPairedDevices()); + sendServerConnectionState(true, port); + } + + private void onAdbdWifiServerDisconnected(int port) { + // The TLS server disconnected while we had wireless debugging enabled. + // Let's disable it. + mWifiConnectedKeys.clear(); + showAdbConnectedNotification(false); + sendServerConnectionState(false, port); + } + + /** + * Returns the [bssid, ssid] of the current access point. + */ + private AdbConnectionInfo getCurrentWifiApInfo() { + WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + if (wifiInfo == null || wifiInfo.getNetworkId() == -1) { + Slog.i(TAG, "Not connected to any wireless network. Not enabling adbwifi."); + return null; + } + + String ssid = null; + if (wifiInfo.isPasspointAp() || wifiInfo.isOsuAp()) { + ssid = wifiInfo.getPasspointProviderFriendlyName(); + } else { + ssid = wifiInfo.getSSID(); + if (ssid == null || WifiManager.UNKNOWN_SSID.equals(ssid)) { + // OK, it's not in the connectionInfo; we have to go hunting for it + List networks = wifiManager.getConfiguredNetworks(); + int length = networks.size(); + for (int i = 0; i < length; i++) { + if (networks.get(i).networkId == wifiInfo.getNetworkId()) { + ssid = networks.get(i).SSID; + } + } + if (ssid == null) { + Slog.e(TAG, "Unable to get ssid of the wifi AP."); + return null; + } + } + } + + String bssid = wifiInfo.getBSSID(); + if (bssid == null || bssid.isEmpty()) { + Slog.e(TAG, "Unable to get the wifi ap's BSSID."); + return null; + } + return new AdbConnectionInfo(bssid, ssid); + } + + private boolean verifyWifiNetwork(String bssid, String ssid) { + // Check against a list of user-trusted networks. + if (mAdbKeyStore.isTrustedNetwork(bssid)) { + return true; + } + + // Ask user to confirm using wireless debugging on this network. + startConfirmationForNetwork(ssid, bssid); + return false; + } + + private void onPairingResult(String publicKey) { + if (publicKey == null) { + Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); + intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, AdbManager.WIRELESS_STATUS_FAIL); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } else { + Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); + intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, + AdbManager.WIRELESS_STATUS_SUCCESS); + String fingerprints = getFingerprints(publicKey); + String hostname = "nouser@nohostname"; + String[] args = publicKey.split("\\s+"); + if (args.length > 1) { + hostname = args[1]; + } + PairDevice device = new PairDevice(fingerprints, hostname, false); + intent.putExtra(AdbManager.WIRELESS_PAIR_DEVICE_EXTRA, device); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + // Add the key into the keystore + mAdbKeyStore.setLastConnectionTime(publicKey, + System.currentTimeMillis()); + sendPersistKeyStoreMessage(); + scheduleJobToUpdateAdbKeyStore(); + } + } + + private void sendPairingPortToUI(int port) { + Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); + intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, + AdbManager.WIRELESS_STATUS_CONNECTED); + intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } + + private void sendPairedDevicesToUI(Map devices) { + Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRED_DEVICES_ACTION); + // Map is not serializable, so need to downcast + intent.putExtra(AdbManager.WIRELESS_DEVICES_EXTRA, (HashMap) devices); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } + + private void updateUIPairCode(String code) { + if (DEBUG) Slog.i(TAG, "updateUIPairCode: " + code); + + Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_PAIRING_RESULT_ACTION); + intent.putExtra(AdbManager.WIRELESS_PAIRING_CODE_EXTRA, code); + intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, + AdbManager.WIRELESS_STATUS_PAIRING_CODE); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } } private String getFingerprints(String key) { @@ -576,7 +1423,34 @@ public class AdbDebuggingManager { return sb.toString(); } - private void startConfirmation(String key, String fingerprints) { + private void startConfirmationForNetwork(String ssid, String bssid) { + List> extras = new ArrayList>(); + extras.add(new AbstractMap.SimpleEntry("ssid", ssid)); + extras.add(new AbstractMap.SimpleEntry("bssid", bssid)); + int currentUserId = ActivityManager.getCurrentUser(); + UserInfo userInfo = UserManager.get(mContext).getUserInfo(currentUserId); + String componentString; + if (userInfo.isAdmin()) { + componentString = Resources.getSystem().getString( + com.android.internal.R.string.config_customAdbWifiNetworkConfirmationComponent); + } else { + componentString = Resources.getSystem().getString( + com.android.internal.R.string.config_customAdbWifiNetworkConfirmationComponent); + } + ComponentName componentName = ComponentName.unflattenFromString(componentString); + if (startConfirmationActivity(componentName, userInfo.getUserHandle(), extras) + || startConfirmationService(componentName, userInfo.getUserHandle(), + extras)) { + return; + } + Slog.e(TAG, "Unable to start customAdbWifiNetworkConfirmation[SecondaryUser]Component " + + componentString + " as an Activity or a Service"); + } + + private void startConfirmationForKey(String key, String fingerprints) { + List> extras = new ArrayList>(); + extras.add(new AbstractMap.SimpleEntry("key", key)); + extras.add(new AbstractMap.SimpleEntry("fingerprints", fingerprints)); int currentUserId = ActivityManager.getCurrentUser(); UserInfo userInfo = UserManager.get(mContext).getUserInfo(currentUserId); String componentString; @@ -591,9 +1465,9 @@ public class AdbDebuggingManager { R.string.config_customAdbPublicKeyConfirmationSecondaryUserComponent); } ComponentName componentName = ComponentName.unflattenFromString(componentString); - if (startConfirmationActivity(componentName, userInfo.getUserHandle(), key, fingerprints) + if (startConfirmationActivity(componentName, userInfo.getUserHandle(), extras) || startConfirmationService(componentName, userInfo.getUserHandle(), - key, fingerprints)) { + extras)) { return; } Slog.e(TAG, "unable to start customAdbPublicKeyConfirmation[SecondaryUser]Component " @@ -604,9 +1478,9 @@ public class AdbDebuggingManager { * @return true if the componentName led to an Activity that was started. */ private boolean startConfirmationActivity(ComponentName componentName, UserHandle userHandle, - String key, String fingerprints) { + List> extras) { PackageManager packageManager = mContext.getPackageManager(); - Intent intent = createConfirmationIntent(componentName, key, fingerprints); + Intent intent = createConfirmationIntent(componentName, extras); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) { try { @@ -623,8 +1497,8 @@ public class AdbDebuggingManager { * @return true if the componentName led to a Service that was started. */ private boolean startConfirmationService(ComponentName componentName, UserHandle userHandle, - String key, String fingerprints) { - Intent intent = createConfirmationIntent(componentName, key, fingerprints); + List> extras) { + Intent intent = createConfirmationIntent(componentName, extras); try { if (mContext.startServiceAsUser(intent, userHandle) != null) { return true; @@ -635,12 +1509,13 @@ public class AdbDebuggingManager { return false; } - private Intent createConfirmationIntent(ComponentName componentName, String key, - String fingerprints) { + private Intent createConfirmationIntent(ComponentName componentName, + List> extras) { Intent intent = new Intent(); intent.setClassName(componentName.getPackageName(), componentName.getClassName()); - intent.putExtra("key", key); - intent.putExtra("fingerprints", fingerprints); + for (Map.Entry entry : extras) { + intent.putExtra(entry.getKey(), entry.getValue()); + } return intent; } @@ -733,7 +1608,8 @@ public class AdbDebuggingManager { mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MESSAGE_ADB_ENABLED : AdbDebuggingHandler.MESSAGE_ADB_DISABLED); } else if (transportType == AdbTransportType.WIFI) { - // TODO(joshuaduong): Not implemented + mHandler.sendEmptyMessage(enabled ? AdbDebuggingHandler.MSG_ADBDWIFI_ENABLE + : AdbDebuggingHandler.MSG_ADBDWIFI_DISABLE); } else { throw new IllegalArgumentException( "setAdbEnabled called with unimplemented transport type=" + transportType); @@ -766,6 +1642,87 @@ public class AdbDebuggingManager { mHandler.sendEmptyMessage(AdbDebuggingHandler.MESSAGE_ADB_CLEAR); } + /** + * Allows wireless debugging on the network identified by {@code bssid} either once + * or always if {@code alwaysAllow} is {@code true}. + */ + public void allowWirelessDebugging(boolean alwaysAllow, String bssid) { + Message msg = mHandler.obtainMessage(AdbDebuggingHandler.MSG_ADBWIFI_ALLOW); + msg.arg1 = alwaysAllow ? 1 : 0; + msg.obj = bssid; + mHandler.sendMessage(msg); + } + + /** + * Denies wireless debugging connection on the last requested network. + */ + public void denyWirelessDebugging() { + mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_ADBWIFI_DENY); + } + + /** + * Returns the port adbwifi is currently opened on. + */ + public int getAdbWirelessPort() { + AdbConnectionInfo info = getAdbConnectionInfo(); + if (info == null) { + return 0; + } + return info.getPort(); + } + + /** + * Returns the list of paired devices. + */ + public Map getPairedDevices() { + AdbKeyStore keystore = new AdbKeyStore(); + return keystore.getPairedDevices(); + } + + /** + * Unpair with device + */ + public void unpairDevice(String fingerprint) { + Message message = Message.obtain(mHandler, + AdbDebuggingHandler.MSG_REQ_UNPAIR, + fingerprint); + mHandler.sendMessage(message); + } + + /** + * Enable pairing by pairing code + */ + public void enablePairingByPairingCode() { + mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_PAIR_PAIRING_CODE); + } + + /** + * Enable pairing by pairing code + */ + public void enablePairingByQrCode(String serviceName, String password) { + Bundle bundle = new Bundle(); + bundle.putString("serviceName", serviceName); + bundle.putString("password", password); + Message message = Message.obtain(mHandler, + AdbDebuggingHandler.MSG_PAIR_QR_CODE, + bundle); + mHandler.sendMessage(message); + } + + /** + * Disables pairing + */ + public void disablePairing() { + mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_PAIRING_CANCEL); + } + + /** + * Status enabled/disabled check + */ + public boolean isAdbWifiEnabled() { + return mAdbWifiEnabled; + } + /** * Sends a message to the handler to persist the keystore. */ @@ -819,9 +1776,19 @@ public class AdbDebuggingManager { private File mKeyFile; private AtomicFile mAtomicKeyFile; + private List mTrustedNetworks; + private static final int KEYSTORE_VERSION = 1; + private static final int MAX_SUPPORTED_KEYSTORE_VERSION = 1; + private static final String XML_KEYSTORE_START_TAG = "keyStore"; + private static final String XML_ATTRIBUTE_VERSION = "version"; private static final String XML_TAG_ADB_KEY = "adbKey"; private static final String XML_ATTRIBUTE_KEY = "key"; private static final String XML_ATTRIBUTE_LAST_CONNECTION = "lastConnection"; + // A list of trusted networks a device can always wirelessly debug on (always allow). + // TODO: Move trusted networks list into a different file? + private static final String XML_TAG_WIFI_ACCESS_POINT = "wifiAP"; + private static final String XML_ATTRIBUTE_WIFI_BSSID = "bssid"; + private static final String SYSTEM_KEY_FILE = "/adb_keys"; /** @@ -848,10 +1815,48 @@ public class AdbDebuggingManager { private void init() { initKeyFile(); mKeyMap = getKeyMap(); + mTrustedNetworks = getTrustedNetworks(); mSystemKeys = getSystemKeysFromFile(SYSTEM_KEY_FILE); addUserKeysToKeyStore(); } + public void addTrustedNetwork(String bssid) { + mTrustedNetworks.add(bssid); + sendPersistKeyStoreMessage(); + } + + public Map getPairedDevices() { + Map pairedDevices = new HashMap(); + for (Map.Entry keyEntry : mKeyMap.entrySet()) { + String fingerprints = getFingerprints(keyEntry.getKey()); + String hostname = "nouser@nohostname"; + String[] args = keyEntry.getKey().split("\\s+"); + if (args.length > 1) { + hostname = args[1]; + } + pairedDevices.put(keyEntry.getKey(), new PairDevice( + hostname, fingerprints, mWifiConnectedKeys.contains(keyEntry.getKey()))); + } + return pairedDevices; + } + + public String findKeyFromFingerprint(String fingerprint) { + for (Map.Entry entry : mKeyMap.entrySet()) { + String f = getFingerprints(entry.getKey()); + if (fingerprint.equals(f)) { + return entry.getKey(); + } + } + return null; + } + + public void removeKey(String key) { + if (mKeyMap.containsKey(key)) { + mKeyMap.remove(key); + sendPersistKeyStoreMessage(); + } + } + /** * Initializes the key file that will be used to persist the adb grants. */ @@ -905,6 +1910,78 @@ public class AdbDebuggingManager { * Returns the key map with the keys and last connection times from the key file. */ private Map getKeyMap() { + Map keyMap = new HashMap(); + // if the AtomicFile could not be instantiated before attempt again; if it still fails + // return an empty key map. + if (mAtomicKeyFile == null) { + initKeyFile(); + if (mAtomicKeyFile == null) { + Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); + return keyMap; + } + } + if (!mAtomicKeyFile.exists()) { + return keyMap; + } + try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(keyStream, StandardCharsets.UTF_8.name()); + // Check for supported keystore version. + XmlUtils.beginDocument(parser, XML_KEYSTORE_START_TAG); + if (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null || !XML_KEYSTORE_START_TAG.equals(tagName)) { + Slog.e(TAG, "Expected " + XML_KEYSTORE_START_TAG + ", but got tag=" + + tagName); + return keyMap; + } + int keystoreVersion = Integer.parseInt( + parser.getAttributeValue(null, XML_ATTRIBUTE_VERSION)); + if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) { + Slog.e(TAG, "Keystore version=" + keystoreVersion + + " not supported (max_supported=" + + MAX_SUPPORTED_KEYSTORE_VERSION + ")"); + return keyMap; + } + } + while (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null) { + break; + } else if (!tagName.equals(XML_TAG_ADB_KEY)) { + XmlUtils.skipCurrentTag(parser); + continue; + } + String key = parser.getAttributeValue(null, XML_ATTRIBUTE_KEY); + long connectionTime; + try { + connectionTime = Long.valueOf( + parser.getAttributeValue(null, XML_ATTRIBUTE_LAST_CONNECTION)); + } catch (NumberFormatException e) { + Slog.e(TAG, + "Caught a NumberFormatException parsing the last connection time: " + + e); + XmlUtils.skipCurrentTag(parser); + continue; + } + keyMap.put(key, connectionTime); + } + } catch (IOException e) { + Slog.e(TAG, "Caught an IOException parsing the XML key file: ", e); + } catch (XmlPullParserException e) { + Slog.w(TAG, "Caught XmlPullParserException parsing the XML key file: ", e); + // The file could be written in a format prior to introducing keystore tag. + return getKeyMapBeforeKeystoreVersion(); + } + return keyMap; + } + + + /** + * Returns the key map with the keys and last connection times from the key file. + * This implementation was prior to adding the XML_KEYSTORE_START_TAG. + */ + private Map getKeyMapBeforeKeystoreVersion() { Map keyMap = new HashMap(); // if the AtomicFile could not be instantiated before attempt again; if it still fails // return an empty key map. @@ -950,6 +2027,63 @@ public class AdbDebuggingManager { return keyMap; } + /** + * Returns the map of trusted networks from the keystore file. + * + * This was implemented in keystore version 1. + */ + private List getTrustedNetworks() { + List trustedNetworks = new ArrayList(); + // if the AtomicFile could not be instantiated before attempt again; if it still fails + // return an empty key map. + if (mAtomicKeyFile == null) { + initKeyFile(); + if (mAtomicKeyFile == null) { + Slog.e(TAG, "Unable to obtain the key file, " + mKeyFile + ", for reading"); + return trustedNetworks; + } + } + if (!mAtomicKeyFile.exists()) { + return trustedNetworks; + } + try (FileInputStream keyStream = mAtomicKeyFile.openRead()) { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(keyStream, StandardCharsets.UTF_8.name()); + // Check for supported keystore version. + XmlUtils.beginDocument(parser, XML_KEYSTORE_START_TAG); + if (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null || !XML_KEYSTORE_START_TAG.equals(tagName)) { + Slog.e(TAG, "Expected " + XML_KEYSTORE_START_TAG + ", but got tag=" + + tagName); + return trustedNetworks; + } + int keystoreVersion = Integer.parseInt( + parser.getAttributeValue(null, XML_ATTRIBUTE_VERSION)); + if (keystoreVersion > MAX_SUPPORTED_KEYSTORE_VERSION) { + Slog.e(TAG, "Keystore version=" + keystoreVersion + + " not supported (max_supported=" + + MAX_SUPPORTED_KEYSTORE_VERSION); + return trustedNetworks; + } + } + while (parser.next() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (tagName == null) { + break; + } else if (!tagName.equals(XML_TAG_WIFI_ACCESS_POINT)) { + XmlUtils.skipCurrentTag(parser); + continue; + } + String bssid = parser.getAttributeValue(null, XML_ATTRIBUTE_WIFI_BSSID); + trustedNetworks.add(bssid); + } + } catch (IOException | XmlPullParserException | NumberFormatException e) { + Slog.e(TAG, "Caught an exception parsing the XML key file: ", e); + } + return trustedNetworks; + } + /** * Updates the keystore with keys that were previously set to be always allowed before the * connection time of keys was tracked. @@ -986,7 +2120,7 @@ public class AdbDebuggingManager { // if there is nothing in the key map then ensure any keys left in the keystore files // are deleted as well. filterOutOldKeys(); - if (mKeyMap.isEmpty()) { + if (mKeyMap.isEmpty() && mTrustedNetworks.isEmpty()) { deleteKeyStore(); return; } @@ -1004,6 +2138,8 @@ public class AdbDebuggingManager { serializer.setOutput(keyStream, StandardCharsets.UTF_8.name()); serializer.startDocument(null, true); + serializer.startTag(null, XML_KEYSTORE_START_TAG); + serializer.attribute(null, XML_ATTRIBUTE_VERSION, String.valueOf(KEYSTORE_VERSION)); for (Map.Entry keyEntry : mKeyMap.entrySet()) { serializer.startTag(null, XML_TAG_ADB_KEY); serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey()); @@ -1011,7 +2147,12 @@ public class AdbDebuggingManager { String.valueOf(keyEntry.getValue())); serializer.endTag(null, XML_TAG_ADB_KEY); } - + for (String bssid : mTrustedNetworks) { + serializer.startTag(null, XML_TAG_WIFI_ACCESS_POINT); + serializer.attribute(null, XML_ATTRIBUTE_WIFI_BSSID, bssid); + serializer.endTag(null, XML_TAG_WIFI_ACCESS_POINT); + } + serializer.endTag(null, XML_KEYSTORE_START_TAG); serializer.endDocument(); mAtomicKeyFile.finishWrite(keyStream); } catch (IOException e) { @@ -1072,6 +2213,7 @@ public class AdbDebuggingManager { */ public void deleteKeyStore() { mKeyMap.clear(); + mTrustedNetworks.clear(); deleteKeyFile(); if (mAtomicKeyFile == null) { return; @@ -1153,5 +2295,14 @@ public class AdbDebuggingManager { return false; } } + + /** + * Returns whether the specified bssid is in the list of trusted networks. This requires + * that the user previously allowed wireless debugging on this network and selected the + * option to 'Always allow'. + */ + public boolean isTrustedNetwork(String bssid) { + return mTrustedNetworks.contains(bssid); + } } } diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java index 0d161b943d15..7ccb28474604 100644 --- a/services/core/java/com/android/server/adb/AdbService.java +++ b/services/core/java/com/android/server/adb/AdbService.java @@ -21,8 +21,10 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.database.ContentObserver; +import android.debug.AdbManager; import android.debug.AdbManagerInternal; import android.debug.AdbTransportType; import android.debug.IAdbManager; @@ -34,6 +36,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemProperties; +import android.os.UserHandle; import android.provider.Settings; import android.service.adb.AdbServiceDumpProto; import android.sysprop.AdbProperties; @@ -44,6 +47,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.server.FgThread; import com.android.server.LocalServices; @@ -54,12 +58,34 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; /** * The Android Debug Bridge (ADB) service. This controls the availability of ADB and authorization * of devices allowed to connect to ADB. */ public class AdbService extends IAdbManager.Stub { + /** + * Adb native daemon. + */ + static final String ADBD = "adbd"; + + /** + * Command to start native service. + */ + static final String CTL_START = "ctl.start"; + + /** + * Command to start native service. + */ + static final String CTL_STOP = "ctl.stop"; + + // The tcp port adb is currently using + AtomicInteger mConnectionPort = new AtomicInteger(-1); + + private final AdbConnectionPortListener mPortListener = new AdbConnectionPortListener(); + private AdbDebuggingManager.AdbConnectionPortPoller mConnectionPortPoller; + /** * Manages the service lifecycle for {@code AdbService} in {@code SystemServer}. */ @@ -129,9 +155,8 @@ public class AdbService extends IAdbManager.Stub { mIsAdbUsbEnabled = containsFunction( SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""), UsbManager.USB_FUNCTION_ADB); - // TODO(joshuaduong): Read the adb wifi state from a persistent system - // property (persist.sys.adb.wifi). - mIsAdbWifiEnabled = false; + mIsAdbWifiEnabled = "1".equals( + SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0")); // register observer to listen for settings changes mObserver = new AdbSettingsObserver(); @@ -189,6 +214,7 @@ public class AdbService extends IAdbManager.Stub { * May also contain vendor-specific default functions for testing purposes. */ private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config"; + private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable"; private final Context mContext; private final ContentResolver mContentResolver; @@ -245,8 +271,9 @@ public class AdbService extends IAdbManager.Stub { } @Override - public void allowDebugging(boolean alwaysAllow, String publicKey) { + public void allowDebugging(boolean alwaysAllow, @NonNull String publicKey) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); + Preconditions.checkStringNotEmpty(publicKey); if (mDebuggingManager != null) { mDebuggingManager.allowDebugging(alwaysAllow, publicKey); } @@ -296,53 +323,118 @@ public class AdbService extends IAdbManager.Stub { } @Override - public void allowWirelessDebugging(boolean alwaysAllow, String bssid) { + public void allowWirelessDebugging(boolean alwaysAllow, @NonNull String bssid) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED + Preconditions.checkStringNotEmpty(bssid); + if (mDebuggingManager != null) { + mDebuggingManager.allowWirelessDebugging(alwaysAllow, bssid); + } } @Override public void denyWirelessDebugging() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED + if (mDebuggingManager != null) { + mDebuggingManager.denyWirelessDebugging(); + } } @Override public Map getPairedDevices() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED + if (mDebuggingManager != null) { + return mDebuggingManager.getPairedDevices(); + } return null; } @Override - public void unpairDevice(String fingerprint) { + public void unpairDevice(@NonNull String fingerprint) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED + Preconditions.checkStringNotEmpty(fingerprint); + if (mDebuggingManager != null) { + mDebuggingManager.unpairDevice(fingerprint); + } } @Override public void enablePairingByPairingCode() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED + if (mDebuggingManager != null) { + mDebuggingManager.enablePairingByPairingCode(); + } } @Override - public void enablePairingByQrCode(String serviceName, String password) { + public void enablePairingByQrCode(@NonNull String serviceName, @NonNull String password) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED + Preconditions.checkStringNotEmpty(serviceName); + Preconditions.checkStringNotEmpty(password); + if (mDebuggingManager != null) { + mDebuggingManager.enablePairingByQrCode(serviceName, password); + } } @Override public void disablePairing() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED + if (mDebuggingManager != null) { + mDebuggingManager.disablePairing(); + } } @Override public int getAdbWirelessPort() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null); - // TODO(joshuaduong): NOT IMPLEMENTED - return 0; + if (mDebuggingManager != null) { + return mDebuggingManager.getAdbWirelessPort(); + } + // If ro.adb.secure=0 + return mConnectionPort.get(); + } + + /** + * This listener is only used when ro.adb.secure=0. Otherwise, AdbDebuggingManager will + * do this. + */ + class AdbConnectionPortListener implements AdbDebuggingManager.AdbConnectionPortListener { + public void onPortReceived(int port) { + if (port > 0 && port <= 65535) { + mConnectionPort.set(port); + } else { + mConnectionPort.set(-1); + // Turn off wifi debugging, since the server did not start. + try { + Settings.Global.putInt(mContentResolver, + Settings.Global.ADB_WIFI_ENABLED, 0); + } catch (SecurityException e) { + // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't + // be changed. + Slog.d(TAG, "ADB_ENABLED is restricted."); + } + } + broadcastPortInfo(mConnectionPort.get()); + } + } + + private void broadcastPortInfo(int port) { + Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION); + intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, (port >= 0) + ? AdbManager.WIRELESS_STATUS_CONNECTED + : AdbManager.WIRELESS_STATUS_DISCONNECTED); + intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + Slog.i(TAG, "sent port broadcast port=" + port); + } + + private void startAdbd() { + SystemProperties.set(CTL_START, ADBD); + } + + private void stopAdbd() { + if (!mIsAdbUsbEnabled && !mIsAdbWifiEnabled) { + SystemProperties.set(CTL_STOP, ADBD); + } } private void setAdbEnabled(boolean enable, byte transportType) { @@ -356,11 +448,33 @@ public class AdbService extends IAdbManager.Stub { mIsAdbUsbEnabled = enable; } else if (transportType == AdbTransportType.WIFI && enable != mIsAdbWifiEnabled) { mIsAdbWifiEnabled = enable; + if (mIsAdbWifiEnabled) { + if (!AdbProperties.secure().orElse(false) && mDebuggingManager == null) { + // Start adbd. If this is secure adb, then we defer enabling adb over WiFi. + SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1"); + mConnectionPortPoller = + new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener); + mConnectionPortPoller.start(); + } + } else { + // Stop adb over WiFi. + SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"); + if (mConnectionPortPoller != null) { + mConnectionPortPoller.cancelAndWait(); + mConnectionPortPoller = null; + } + } } else { // No change return; } + if (enable) { + startAdbd(); + } else { + stopAdbd(); + } + for (IAdbTransport transport : mTransports.values()) { try { transport.onAdbEnabled(enable, transportType); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 81b42da7d953..153b006d8970 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -21,6 +21,7 @@ cc_library_static { "BroadcastRadio/convert.cpp", "BroadcastRadio/regions.cpp", "com_android_server_AlarmManagerService.cpp", + "com_android_server_adb_AdbDebuggingManager.cpp", "com_android_server_am_BatteryStatsService.cpp", "com_android_server_connectivity_Vpn.cpp", "com_android_server_ConsumerIrService.cpp", @@ -69,6 +70,8 @@ cc_library_static { cc_defaults { name: "libservices.core-libs", shared_libs: [ + "libadb_pairing_server", + "libadb_pairing_connection", "libandroid_runtime", "libandroidfw", "libaudioclient", diff --git a/services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp b/services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp new file mode 100644 index 000000000000..9c834aaece85 --- /dev/null +++ b/services/core/jni/com_android_server_adb_AdbDebuggingManager.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AdbDebuggingManager-JNI" + +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "jni.h" + +namespace android { + +// ---------------------------------------------------------------------------- +namespace { + +template +class JSmartWrapper { +public: + JSmartWrapper(JNIEnv* env, T* jData) : mEnv(env), mJData(jData) {} + + virtual ~JSmartWrapper() = default; + + const N* data() const { return mRawData; } + + jsize size() const { return mSize; } + +protected: + N* mRawData = nullptr; + JNIEnv* mEnv = nullptr; + T* mJData = nullptr; + jsize mSize = 0; +}; // JSmartWrapper + +class JStringUTFWrapper : public JSmartWrapper { +public: + explicit JStringUTFWrapper(JNIEnv* env, jstring* str) : JSmartWrapper(env, str) { + mRawData = env->GetStringUTFChars(*str, NULL); + mSize = env->GetStringUTFLength(*str); + } + + virtual ~JStringUTFWrapper() { + if (data()) { + mEnv->ReleaseStringUTFChars(*mJData, mRawData); + } + } +}; // JStringUTFWrapper + +struct ServerDeleter { + void operator()(PairingServerCtx* p) { pairing_server_destroy(p); } +}; +using PairingServerPtr = std::unique_ptr; +struct PairingResultWaiter { + std::mutex mutex_; + std::condition_variable cv_; + std::optional is_valid_; + PeerInfo peer_info_; + + static void ResultCallback(const PeerInfo* peer_info, void* opaque) { + auto* p = reinterpret_cast(opaque); + { + std::unique_lock lock(p->mutex_); + if (peer_info) { + memcpy(&(p->peer_info_), peer_info, sizeof(PeerInfo)); + } + p->is_valid_ = (peer_info != nullptr); + } + p->cv_.notify_one(); + } +}; + +PairingServerPtr sServer; +std::unique_ptr sWaiter; +} // namespace + +static jint native_pairing_start(JNIEnv* env, jobject thiz, jstring guid, jstring password) { + // Server-side only sends its GUID on success. + PeerInfo system_info = {}; + system_info.type = ADB_DEVICE_GUID; + JStringUTFWrapper guidWrapper(env, &guid); + memcpy(system_info.data, guidWrapper.data(), guidWrapper.size()); + + JStringUTFWrapper passwordWrapper(env, &password); + + // Create the pairing server + sServer = PairingServerPtr( + pairing_server_new_no_cert(reinterpret_cast(passwordWrapper.data()), + passwordWrapper.size(), &system_info, 0)); + + sWaiter.reset(new PairingResultWaiter); + uint16_t port = pairing_server_start(sServer.get(), sWaiter->ResultCallback, sWaiter.get()); + if (port == 0) { + ALOGE("Failed to start pairing server"); + return -1; + } + + return port; +} + +static void native_pairing_cancel(JNIEnv* /* env */, jclass /* clazz */) { + if (sServer != nullptr) { + sServer.reset(); + } +} + +static jboolean native_pairing_wait(JNIEnv* env, jobject thiz) { + ALOGI("Waiting for pairing server to complete"); + std::unique_lock lock(sWaiter->mutex_); + if (!sWaiter->is_valid_.has_value()) { + sWaiter->cv_.wait(lock, [&]() { return sWaiter->is_valid_.has_value(); }); + } + if (!*(sWaiter->is_valid_)) { + return JNI_FALSE; + } + + std::string peer_public_key = reinterpret_cast(sWaiter->peer_info_.data); + // Write to PairingThread's member variables + jclass clazz = env->GetObjectClass(thiz); + jfieldID mPublicKey = env->GetFieldID(clazz, "mPublicKey", "Ljava/lang/String;"); + jstring jpublickey = env->NewStringUTF(peer_public_key.c_str()); + env->SetObjectField(thiz, mPublicKey, jpublickey); + return JNI_TRUE; +} + +// ---------------------------------------------------------------------------- + +static const JNINativeMethod gPairingThreadMethods[] = { + /* name, signature, funcPtr */ + {"native_pairing_start", "(Ljava/lang/String;Ljava/lang/String;)I", + (void*)native_pairing_start}, + {"native_pairing_cancel", "()V", (void*)native_pairing_cancel}, + {"native_pairing_wait", "()Z", (void*)native_pairing_wait}, +}; + +int register_android_server_AdbDebuggingManager(JNIEnv* env) { + int res = jniRegisterNativeMethods(env, + "com/android/server/adb/AdbDebuggingManager$PairingThread", + gPairingThreadMethods, NELEM(gPairingThreadMethods)); + (void)res; // Faked use when LOG_NDEBUG. + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + return 0; +} + +} /* namespace android */ diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 692c9d25baa9..657920e9a9c6 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -56,6 +56,7 @@ int register_android_server_net_NetworkStatsService(JNIEnv* env); int register_android_server_security_VerityUtils(JNIEnv* env); int register_android_server_am_AppCompactor(JNIEnv* env); int register_android_server_am_LowMemDetector(JNIEnv* env); +int register_android_server_AdbDebuggingManager(JNIEnv* env); }; using namespace android; @@ -105,5 +106,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_security_VerityUtils(env); register_android_server_am_AppCompactor(env); register_android_server_am_LowMemDetector(env); + register_android_server_AdbDebuggingManager(env); return JNI_VERSION_1_4; } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 5bb75c92fd30..d2b30b2ff5ef 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -1717,21 +1717,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser */ private static final int ENUMERATION_TIME_OUT_MS = 2000; - /** - * Command to start native service. - */ - protected static final String CTL_START = "ctl.start"; - - /** - * Command to start native service. - */ - protected static final String CTL_STOP = "ctl.stop"; - - /** - * Adb native daemon. - */ - protected static final String ADBD = "adbd"; - /** * Gadget HAL fully qualified instance name for registering for ServiceNotification. */ @@ -1913,17 +1898,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser return; } try { - if ((config & UsbManager.FUNCTION_ADB) != 0) { - /** - * Start adbd if ADB function is included in the configuration. - */ - setSystemProperty(CTL_START, ADBD); - } else { - /** - * Stop adbd otherwise. - */ - setSystemProperty(CTL_STOP, ADBD); - } + // Adbd will be started by AdbService once Global.ADB_ENABLED is set. UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest, config, chargingFunctions); mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback, -- GitLab From 2be3ba49733df585bcfbf63d3b299d15dbfb0f13 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Sat, 22 Feb 2020 23:20:41 +0800 Subject: [PATCH 095/143] RESTRICT AUTOMERGE Create separated tasks for different apps from startActivities Assume there are 2 applications A, B with different uids. There are 4 activities A1, A2, B1, B2 with default task affinity and launch mode. After A1 called startActivities(B1, A2, B2): Original : Task(A1, B1, A2, B2) This Change: Task(A1, B1), Task(A2, B2) In other words, the source caller cannot launch its activity above the activity of other application in the same task, and it can still launch activity of other application in its task. Bug: 145669109 Test: run cts --test android.server.cts.StartActivityTests \ -m CtsServicesHostTestCases Change-Id: I97bd875146a52f62b8fe82235487ccefb2955e8e --- .../com/android/server/am/ActivityStarter.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 7ce80d33ed00..57a0756703d1 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -951,6 +951,8 @@ class ActivityStarter { } else { callingPid = callingUid = -1; } + boolean forceNewTask = false; + final int filterCallingUid = callingUid >= 0 ? callingUid : realCallingUid; final long origId = Binder.clearCallingIdentity(); try { synchronized (mService) { @@ -970,6 +972,9 @@ class ActivityStarter { // Don't modify the client's object! intent = new Intent(intent); + if (forceNewTask) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } // Collect information about the target of the Intent. ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0, @@ -995,7 +1000,17 @@ class ActivityStarter { return res; } - resultTo = outActivity[0] != null ? outActivity[0].appToken : null; + final ActivityRecord started = outActivity[0]; + if (started != null && started.getUid() == filterCallingUid) { + // Only the started activity which has the same uid as the source caller can + // be the caller of next activity. + resultTo = started.appToken; + forceNewTask = false; + } else { + // Different apps not adjacent to the caller are forced to be new task. + resultTo = null; + forceNewTask = true; + } } } } finally { -- GitLab From 6075dd7f58766902e06941552f27ff5ceacd369f Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Fri, 21 Feb 2020 14:33:42 -0500 Subject: [PATCH 096/143] DO NOT MERGE: Add SystemUI support for front-facing camera protection Devices with a DisplayCutout configured may want to add some extra area of turned-off pixels around the cutout in order to keep light from leaking into camera hardware. This CL adds two new config values to sysui to enable the configuration of this cutout protection, and listens for CameraManager events telling us that a relevant camera has turned on. Test: manual Bug: 145095085 Change-Id: Ifce67a593247e3a2151d41800ae46a50478e0b7d --- packages/SystemUI/res/values/config.xml | 17 +++ .../systemui/CameraAvailabilityListener.kt | 138 ++++++++++++++++++ .../android/systemui/ScreenDecorations.java | 83 ++++++++++- 3 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 8811ad57ab5a..6758efac7e2a 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -491,4 +491,21 @@ false + + + + + + + + false + diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt new file mode 100644 index 000000000000..24fa91b9e838 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui + +import android.content.Context +import android.graphics.Path +import android.graphics.Rect +import android.graphics.RectF +import android.hardware.camera2.CameraManager +import android.util.PathParser +import java.util.concurrent.Executor + +import kotlin.math.roundToInt + +const val TAG = "CameraOpTransitionController" + +/** + * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra + * protection around a display cutout based on config_frontBuiltInDisplayCutoutProtection and + * config_enableDisplayCutoutProtection + */ +class CameraAvailabilityListener( + private val cameraManager: CameraManager, + private val cutoutProtectionPath: Path, + private val targetCameraId: String, + private val executor: Executor +) { + private var cutoutBounds = Rect() + private val listeners = mutableListOf() + private val availabilityCallback: CameraManager.AvailabilityCallback = + object : CameraManager.AvailabilityCallback() { + override fun onCameraAvailable(cameraId: String) { + if (targetCameraId == cameraId) { + notifyCameraInactive() + } + } + + override fun onCameraUnavailable(cameraId: String) { + if (targetCameraId == cameraId) { + notifyCameraActive() + } + } + } + + init { + val computed = RectF() + cutoutProtectionPath.computeBounds(computed, false /* unused */) + cutoutBounds.set( + computed.left.roundToInt(), + computed.top.roundToInt(), + computed.right.roundToInt(), + computed.bottom.roundToInt()) + } + + /** + * Start listening for availability events, and maybe notify listeners + * + * @return true if we started listening + */ + fun startListening() { + registerCameraListener() + } + + fun stop() { + unregisterCameraListener() + } + + fun addTransitionCallback(callback: CameraTransitionCallback) { + listeners.add(callback) + } + + fun removeTransitionCallback(callback: CameraTransitionCallback) { + listeners.remove(callback) + } + + private fun registerCameraListener() { + cameraManager.registerAvailabilityCallback(executor, availabilityCallback) + } + + private fun unregisterCameraListener() { + cameraManager.unregisterAvailabilityCallback(availabilityCallback) + } + + private fun notifyCameraActive() { + listeners.forEach { it.onApplyCameraProtection(cutoutProtectionPath, cutoutBounds) } + } + + private fun notifyCameraInactive() { + listeners.forEach { it.onHideCameraProtection() } + } + + /** + * Callbacks to tell a listener that a relevant camera turned on and off. + */ + interface CameraTransitionCallback { + fun onApplyCameraProtection(protectionPath: Path, bounds: Rect) + fun onHideCameraProtection() + } + + companion object Factory { + fun build(context: Context, executor: Executor): CameraAvailabilityListener { + val manager = context + .getSystemService(Context.CAMERA_SERVICE) as CameraManager + val res = context.resources + val pathString = res.getString(R.string.config_frontBuiltInDisplayCutoutProtection) + val cameraId = res.getString(R.string.config_protectedCameraId) + + return CameraAvailabilityListener( + manager, pathFromString(pathString), cameraId, executor) + } + + private fun pathFromString(pathString: String): Path { + val spec = pathString.trim() + val p: Path + try { + p = PathParser.createPathFromPathData(spec) + } catch (e: Throwable) { + throw IllegalArgumentException("Invalid protection path", e) + } + + return p + } + } +} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 84cfd9318932..3a8524a3ee7d 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -29,6 +29,7 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.Dimension; +import android.annotation.NonNull; import android.app.ActivityManager; import android.app.Fragment; import android.content.BroadcastReceiver; @@ -37,6 +38,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.ColorStateList; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; @@ -110,6 +112,7 @@ public class ScreenDecorations extends SystemUI implements Tunable, private DisplayManager mDisplayManager; private DisplayManager.DisplayListener mDisplayListener; + private CameraAvailabilityListener mCameraListener; @VisibleForTesting protected int mRoundedDefault; @@ -133,6 +136,25 @@ public class ScreenDecorations extends SystemUI implements Tunable, private boolean mInGesturalMode; private boolean mIsRoundedCornerMultipleRadius; + private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback = + new CameraAvailabilityListener.CameraTransitionCallback() { + @Override + public void onApplyCameraProtection(@NonNull Path protectionPath, @NonNull Rect bounds) { + // Show the extra protection around the front facing camera if necessary + mCutoutTop.setProtection(protectionPath, bounds); + mCutoutTop.setShowProtection(true); + mCutoutBottom.setProtection(protectionPath, bounds); + mCutoutBottom.setShowProtection(true); + } + + @Override + public void onHideCameraProtection() { + // Go back to the regular anti-aliasing + mCutoutTop.setShowProtection(false); + mCutoutBottom.setShowProtection(false); + } + }; + /** * Converts a set of {@link Rect}s into a {@link Region} * @@ -331,6 +353,7 @@ public class ScreenDecorations extends SystemUI implements Tunable, updateRoundedCornerRadii(); if (hasRoundedCorners() || shouldDrawCutout() || shouldHostHandles()) { setupDecorations(); + setupCameraListener(); } mDisplayListener = new DisplayManager.DisplayListener() { @@ -446,6 +469,16 @@ public class ScreenDecorations extends SystemUI implements Tunable, new ValidatingPreDrawListener(mBottomOverlay)); } + private void setupCameraListener() { + Resources res = mContext.getResources(); + boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection); + if (enabled) { + mCameraListener = CameraAvailabilityListener.Factory.build(mContext, mHandler::post); + mCameraListener.addTransitionCallback(mCameraTransitionCallback); + mCameraListener.startListening(); + } + } + private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -841,6 +874,13 @@ public class ScreenDecorations extends SystemUI implements Tunable, private final List mBounds = new ArrayList(); private final Rect mBoundingRect = new Rect(); private final Path mBoundingPath = new Path(); + // Don't initialize these because they are cached elsewhere and may not exist + private Rect mProtectionRect; + private Path mProtectionPath; + private Rect mTotalBounds = new Rect(); + // Whether or not to show the cutout protection path + private boolean mShowProtection = false; + private final int[] mLocation = new int[2]; private final boolean mInitialStart; private final Runnable mVisibilityChangedListener; @@ -887,7 +927,13 @@ public class ScreenDecorations extends SystemUI implements Tunable, super.onDraw(canvas); getLocationOnScreen(mLocation); canvas.translate(-mLocation[0], -mLocation[1]); - if (!mBoundingPath.isEmpty()) { + + if (mShowProtection && !mProtectionRect.isEmpty()) { + mPaint.setColor(mColor); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setAntiAlias(true); + canvas.drawPath(mProtectionPath, mPaint); + } else if (!mBoundingPath.isEmpty()) { mPaint.setColor(mColor); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); @@ -915,6 +961,22 @@ public class ScreenDecorations extends SystemUI implements Tunable, update(); } + void setProtection(Path protectionPath, Rect pathBounds) { + mProtectionPath = protectionPath; + mProtectionRect = pathBounds; + } + + void setShowProtection(boolean shouldShow) { + if (mShowProtection == shouldShow) { + return; + } + + mShowProtection = shouldShow; + updateBoundingPath(); + requestLayout(); + invalidate(); + } + private boolean isStart() { final boolean flipped = (mRotation == RotationUtils.ROTATION_SEASCAPE || mRotation == RotationUtils.ROTATION_UPSIDE_DOWN); @@ -961,6 +1023,9 @@ public class ScreenDecorations extends SystemUI implements Tunable, Matrix m = new Matrix(); transformPhysicalToLogicalCoordinates(mInfo.rotation, dw, dh, m); mBoundingPath.transform(m); + if (mProtectionPath != null) { + mProtectionPath.transform(m); + } } private static void transformPhysicalToLogicalCoordinates(@Surface.Rotation int rotation, @@ -1018,9 +1083,19 @@ public class ScreenDecorations extends SystemUI implements Tunable, super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } - setMeasuredDimension( - resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0), - resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0)); + + if (mShowProtection) { + // Make sure that our measured height encompases the protection + mTotalBounds.union(mBoundingRect); + mTotalBounds.union(mProtectionRect); + setMeasuredDimension( + resolveSizeAndState(mTotalBounds.width(), widthMeasureSpec, 0), + resolveSizeAndState(mTotalBounds.height(), heightMeasureSpec, 0)); + } else { + setMeasuredDimension( + resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0), + resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0)); + } } public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, -- GitLab From 29c75abfe17c603cf075075beda32eb5d163d6c0 Mon Sep 17 00:00:00 2001 From: Ram Periathiruvadi Date: Tue, 25 Feb 2020 10:12:44 -0800 Subject: [PATCH 097/143] Resolve trust agents on USER_STARTED in addition to USER_ADDED. ACTION_USER_ADDED is a broadcast that is sent once when the user is created. TrustManagerService resolves the enabled trust agents for an user only when the user is created. However, if there is a reboot or power loss before the broadcast is received, the trust agents are never resolved for that user. This change also registers for ACTION_USER_STARTED, so the service checks for enabled trust agents on every boot. If the trust agents have been already resolved and initialized for that users, there is already a Secure Settings key (TRUST_AGENTS_INITIALIZED) that is turned on, so we wouldn't be doing this more than once per user. Bug: 150145767 Test: TrustManagerService resolves trust agents only once - either on USER_ADDED or USER_STARTED. Change-Id: I83c2dd02d4b476f8b85af1aa4d9d0c77095207ce --- .../java/com/android/server/trust/TrustManagerService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 7408dd40b5ca..ef54d0477615 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -1389,7 +1389,8 @@ public class TrustManagerService extends SystemService { if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) { refreshAgentList(getSendingUserId()); updateDevicePolicyFeatures(); - } else if (Intent.ACTION_USER_ADDED.equals(action)) { + } else if (Intent.ACTION_USER_ADDED.equals(action) || Intent.ACTION_USER_STARTED.equals( + action)) { int userId = getUserId(intent); if (userId > 0) { maybeEnableFactoryTrustAgents(mLockPatternUtils, userId); @@ -1430,6 +1431,7 @@ public class TrustManagerService extends SystemService { filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_STARTED); context.registerReceiverAsUser(this, UserHandle.ALL, filter, -- GitLab From e207aed32949a0d421029d1a1153469b06dc68d7 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Wed, 26 Feb 2020 11:18:57 -0500 Subject: [PATCH 098/143] Use status_bar_padding_top in QS system icons Test: manual Bug: 148651257 Change-Id: I771502c97623efb6513c0b12bac2ef7a95f09fc4 --- packages/SystemUI/res/layout/system_icons.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index f3b72bf23757..6fb5590df6ed 100644 --- a/packages/SystemUI/res/layout/system_icons.xml +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -26,6 +26,7 @@ android:layout_weight="1" android:layout_height="match_parent" android:paddingEnd="@dimen/signal_cluster_battery_padding" + android:paddingTop="@dimen/status_bar_padding_top" android:gravity="center_vertical" android:orientation="horizontal"/> -- GitLab From 97e162d60551c7cac3316ee00a6c12d520ce91d3 Mon Sep 17 00:00:00 2001 From: Yu-Han Yang Date: Wed, 26 Feb 2020 12:46:01 -0800 Subject: [PATCH 099/143] Allow settingIgnored for DBH request if inEmergency Bug: 150232136 Test: on device Change-Id: Ia987418a591d716b787d406d725338a8563a55dd --- .../android/server/location/GnssConfiguration.java | 9 ++++++--- .../server/location/GnssLocationProvider.java | 13 +++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java index 86a84e312899..18d9f69c9735 100644 --- a/services/core/java/com/android/server/location/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/GnssConfiguration.java @@ -79,7 +79,7 @@ class GnssConfiguration { // Represents an HAL interface version. Instances of this class are created in the JNI layer // and returned through native methods. - private static class HalInterfaceVersion { + static class HalInterfaceVersion { final int mMajor; final int mMinor; @@ -205,6 +205,10 @@ class GnssConfiguration { native_set_satellite_blacklist(constellations, svids); } + HalInterfaceVersion getHalInterfaceVersion() { + return native_get_gnss_configuration_version(); + } + interface SetCarrierProperty { boolean set(int value); } @@ -231,8 +235,7 @@ class GnssConfiguration { logConfigurations(); - final HalInterfaceVersion gnssConfigurationIfaceVersion = - native_get_gnss_configuration_version(); + final HalInterfaceVersion gnssConfigurationIfaceVersion = getHalInterfaceVersion(); if (gnssConfigurationIfaceVersion != null) { // Set to a range checked value. if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion) diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 4b79677b475b..342e9b8c3006 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -772,10 +772,15 @@ public class GnssLocationProvider extends AbstractLocationProvider implements locationRequest.setProvider(provider); - // Ignore location settings if in emergency mode. - if (isUserEmergency && mNIHandler.getInEmergency()) { - locationRequest.setLocationSettingsIgnored(true); - durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER; + // Ignore location settings if in emergency mode. This is only allowed for + // isUserEmergency request (introduced in HAL v2.0), or DBH request in HAL v1.1. + if (mNIHandler.getInEmergency()) { + GnssConfiguration.HalInterfaceVersion halVersion = + mGnssConfiguration.getHalInterfaceVersion(); + if (isUserEmergency || (halVersion.mMajor < 2 && !independentFromGnss)) { + locationRequest.setLocationSettingsIgnored(true); + durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER; + } } Log.i(TAG, -- GitLab From 348476e0944242bcf7c98b404293f4634f243ba2 Mon Sep 17 00:00:00 2001 From: Agatha Man Date: Thu, 14 Nov 2019 11:18:01 -0800 Subject: [PATCH 100/143] AudioService - remove sendBroadcastToAll() from setMasterMuteInternalNoCallerCheck() sendBroadcastToAll is a duplicate broadcast of MASTER_MUTE_CHANGED_ACTION. The same broadcast is called by sendMasterMuteUpdate. Test: make Bug: 144352459 Change-Id: I0f5283fe35521f04c04c159d42bd907fccfb226f (cherry picked from commit 1ae52c25c81bab7d0aa5c1994ea604a4836027eb) --- services/core/java/com/android/server/audio/AudioService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index b5dbe9cb0895..3a5d4bc32d5c 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2776,10 +2776,6 @@ public class AudioService extends IAudioService.Stub setSystemAudioMute(mute); AudioSystem.setMasterMute(mute); sendMasterMuteUpdate(mute, flags); - - Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); - intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute); - sendBroadcastToAll(intent); } } } -- GitLab From d0555bba57fc8b2510a458cf07757e0db07e3aa6 Mon Sep 17 00:00:00 2001 From: Babak Bostan Date: Thu, 27 Feb 2020 11:17:55 -0800 Subject: [PATCH 101/143] DO NOT MERGE Add toast message when bluetooth connects to voice recognition. Bug: 143531081 Test: Manual Change-Id: I342a1e5eefc59d25a8bea1c0fe72b8669bfdbe84 --- packages/CarSystemUI/res/values/strings.xml | 2 + ...nnectedDeviceVoiceRecognitionNotifier.java | 90 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 packages/CarSystemUI/src/com/android/systemui/voicerecognition/car/ConnectedDeviceVoiceRecognitionNotifier.java diff --git a/packages/CarSystemUI/res/values/strings.xml b/packages/CarSystemUI/res/values/strings.xml index 0368e61978fd..9ea7ed027d34 100644 --- a/packages/CarSystemUI/res/values/strings.xml +++ b/packages/CarSystemUI/res/values/strings.xml @@ -20,4 +20,6 @@ Min Max + + Voice recognition now handled by connected Bluetooth device diff --git a/packages/CarSystemUI/src/com/android/systemui/voicerecognition/car/ConnectedDeviceVoiceRecognitionNotifier.java b/packages/CarSystemUI/src/com/android/systemui/voicerecognition/car/ConnectedDeviceVoiceRecognitionNotifier.java new file mode 100644 index 000000000000..5cd145b05a1b --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/voicerecognition/car/ConnectedDeviceVoiceRecognitionNotifier.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.voicerecognition.car; + +import android.bluetooth.BluetoothHeadsetClient; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.UserHandle; +import android.util.Log; +import android.widget.Toast; + +import com.android.systemui.Dependency; +import com.android.systemui.R; +import com.android.systemui.SysUIToast; +import com.android.systemui.SystemUI; + +import javax.inject.Inject; + +/** + * Controller responsible for showing toast message when voice recognition over bluetooth device + * getting activated. + */ +public class ConnectedDeviceVoiceRecognitionNotifier extends SystemUI { + + private static final String TAG = "CarVoiceRecognition"; + private static final int INVALID_VALUE = -1; + private static final int VOICE_RECOGNITION_STARTED = 1; + + private Handler mHandler; + + private final BroadcastReceiver mVoiceRecognitionReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Voice recognition received an intent!"); + } + if (intent == null + || intent.getAction() == null + || !BluetoothHeadsetClient.ACTION_AG_EVENT.equals(intent.getAction()) + || !intent.hasExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION)) { + return; + } + + int voiceRecognitionState = intent.getIntExtra( + BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE); + + if (voiceRecognitionState == VOICE_RECOGNITION_STARTED) { + mHandler.post(() -> { + SysUIToast.makeText(mContext, R.string.voice_recognition_toast, + Toast.LENGTH_LONG).show(); + }); + } + } + }; + + @Inject + public ConnectedDeviceVoiceRecognitionNotifier() { + super(); + mHandler = Dependency.get(Dependency.MAIN_HANDLER); + } + + @Override + public void start() { + } + + @Override + protected void onBootCompleted() { + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothHeadsetClient.ACTION_AG_EVENT); + mContext.registerReceiverAsUser(mVoiceRecognitionReceiver, UserHandle.ALL, filter, + /* broadcastPermission= */ null, /* scheduler= */ null); + } +} -- GitLab From 9859e1724b9732aaba3e971bb3e34ef41fc2bac6 Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Thu, 27 Feb 2020 17:11:43 -0800 Subject: [PATCH 102/143] Fix carrier config string typo. Bug: 148611362 Test: build Change-Id: Idf0c82a9920c62ecdc595973565656ed9ceedff6 --- telephony/java/android/telephony/CarrierConfigManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 81042f4a34bf..717adb9d2b93 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3167,7 +3167,7 @@ public class CarrierConfigManager { * @hide */ public static final String KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG = - "data_switch_validation_min_gap_LONG"; + "data_switch_validation_min_gap_long"; /** * A boolean property indicating whether this subscription should be managed as an opportunistic -- GitLab From 1180021cd841b0101339408fc5b593a67a44fca2 Mon Sep 17 00:00:00 2001 From: Jay Aliomer Date: Tue, 18 Feb 2020 11:48:29 -0500 Subject: [PATCH 103/143] Back porting Dark theme bug fixes from R Applying theme on start update system properties on startup to apply the updates Fixes: 149441632 Fixes: 149385662 Test: UiModeManager tests Change-Id: I7f71e27a43eb24be833b3003340653fefc75d0cc Merged-In: I0bee6517b39216146681097262cf55c7192b0131 --- .../android/server/UiModeManagerService.java | 107 +++++++++++------- .../server/UiModeManagerServiceTest.java | 5 +- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index 7ad04728b512..479c9e4adb7a 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -74,6 +74,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import static android.app.UiModeManager.MODE_NIGHT_AUTO; +import static android.app.UiModeManager.MODE_NIGHT_YES; + final class UiModeManagerService extends SystemService { private static final String TAG = UiModeManager.class.getSimpleName(); private static final boolean LOG = false; @@ -131,6 +134,7 @@ final class UiModeManagerService extends SystemService { private NotificationManager mNotificationManager; private StatusBarManager mStatusBarManager; private WindowManagerInternal mWindowManager; + private PowerManager mPowerManager; private PowerManager.WakeLock mWakeLock; @@ -143,11 +147,12 @@ final class UiModeManagerService extends SystemService { @VisibleForTesting protected UiModeManagerService(Context context, WindowManagerInternal wm, PowerManager.WakeLock wl, TwilightManager tm, - boolean setupWizardComplete) { + PowerManager pm, boolean setupWizardComplete) { super(context); mWindowManager = wm; mWakeLock = wl; mTwilightManager = tm; + mPowerManager = pm; mSetupWizardComplete = setupWizardComplete; } @@ -268,14 +273,19 @@ final class UiModeManagerService extends SystemService { private final ContentObserver mDarkThemeObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri) { - int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, - mNightMode, 0); - mode = mode == UiModeManager.MODE_NIGHT_AUTO - ? UiModeManager.MODE_NIGHT_YES : mode; - SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); + updateSystemProperties(); } }; + private void updateSystemProperties() { + int mode = Secure.getIntForUser(getContext().getContentResolver(), Secure.UI_NIGHT_MODE, + mNightMode, 0); + if (mode == MODE_NIGHT_AUTO) { + mode = MODE_NIGHT_YES; + } + SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); + } + @Override public void onSwitchUser(int userHandle) { super.onSwitchUser(userHandle); @@ -287,9 +297,9 @@ final class UiModeManagerService extends SystemService { public void onStart() { final Context context = getContext(); - final PowerManager powerManager = + mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); + mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); mWindowManager = LocalServices.getService(WindowManagerInternal.class); // If setup isn't complete for this user listen for completion so we can unblock @@ -356,6 +366,7 @@ final class UiModeManagerService extends SystemService { context.getContentResolver().registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE), false, mDarkThemeObserver, 0); + mHandler.post(() -> updateSystemProperties()); } @VisibleForTesting @@ -413,6 +424,7 @@ final class UiModeManagerService extends SystemService { } private void registerScreenOffEvent() { + if (mPowerSave) return; mWaitForScreenOff = true; final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); @@ -560,7 +572,9 @@ final class UiModeManagerService extends SystemService { persistNightMode(user); } // on screen off will update configuration instead - if (mNightMode != UiModeManager.MODE_NIGHT_AUTO || mCar) { + if ((mNightMode != MODE_NIGHT_AUTO) + || shouldApplyAutomaticChangesImmediately()) { + unregisterScreenOffEvent(); updateLocked(0, 0); } else { registerScreenOffEvent(); @@ -638,7 +652,6 @@ final class UiModeManagerService extends SystemService { pw.println("Current UI Mode Service state:"); pw.print(" mDockState="); pw.print(mDockState); pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); - pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" ("); pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") "); pw.print(" mNightModeLocked="); pw.println(mNightModeLocked); @@ -655,11 +668,9 @@ final class UiModeManagerService extends SystemService { pw.print(" mComputedNightMode="); pw.print(mComputedNightMode); pw.print(" mCarModeEnableFlags="); pw.print(mCarModeEnableFlags); pw.print(" mEnableCarDockLaunch="); pw.println(mEnableCarDockLaunch); - pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); pw.print(" mUiModeLocked="); pw.print(mUiModeLocked); pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode)); - pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration); pw.print(" mSystemReady="); pw.println(mSystemReady); @@ -678,7 +689,6 @@ final class UiModeManagerService extends SystemService { mTwilightManager = getLocalService(TwilightManager.class); mSystemReady = true; mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - updateComputedNightModeLocked(); registerVrStateListener(); updateLocked(0, 0); } @@ -857,40 +867,56 @@ final class UiModeManagerService extends SystemService { uiMode = Configuration.UI_MODE_TYPE_VR_HEADSET; } - if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + if (mNightMode == MODE_NIGHT_YES || mNightMode == UiModeManager.MODE_NIGHT_NO) { + mComputedNightMode = mNightMode == MODE_NIGHT_YES; + } + + if (mNightMode == MODE_NIGHT_AUTO) { + boolean activateNightMode = mComputedNightMode; if (mTwilightManager != null) { mTwilightManager.registerListener(mTwilightListener, mHandler); + final TwilightState lastState = mTwilightManager.getLastTwilightState(); + activateNightMode = lastState == null ? mComputedNightMode : lastState.isNight(); } - updateComputedNightModeLocked(); - uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES - : Configuration.UI_MODE_NIGHT_NO; + + updateComputedNightModeLocked(activateNightMode); } else { if (mTwilightManager != null) { mTwilightManager.unregisterListener(mTwilightListener); } - uiMode |= mNightMode << 4; } // Override night mode in power save mode if not in car mode if (mPowerSave && !mCarModeEnabled) { uiMode &= ~Configuration.UI_MODE_NIGHT_NO; uiMode |= Configuration.UI_MODE_NIGHT_YES; + } else { + uiMode = getComputedUiModeConfiguration(uiMode); } if (LOG) { Slog.d(TAG, - "updateConfigurationLocked: mDockState=" + mDockState + "updateConfigurationLocked: mDockState=" + mDockState + "; mCarMode=" + mCarModeEnabled + "; mNightMode=" + mNightMode + "; uiMode=" + uiMode); } mCurUiMode = uiMode; - if (!mHoldingConfiguration || !mWaitForScreenOff) { + if (!mHoldingConfiguration && (!mWaitForScreenOff || mPowerSave)) { mConfiguration.uiMode = uiMode; } } + @UiModeManager.NightMode + private int getComputedUiModeConfiguration(@UiModeManager.NightMode int uiMode) { + uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES + : Configuration.UI_MODE_NIGHT_NO; + uiMode &= mComputedNightMode ? ~Configuration.UI_MODE_NIGHT_NO + : ~Configuration.UI_MODE_NIGHT_YES; + return uiMode; + } + private void applyConfigurationExternallyLocked() { if (mSetUiMode != mConfiguration.uiMode) { mSetUiMode = mConfiguration.uiMode; @@ -898,10 +924,16 @@ final class UiModeManagerService extends SystemService { ActivityTaskManager.getService().updateConfiguration(mConfiguration); } catch (RemoteException e) { Slog.w(TAG, "Failure communicating with activity manager", e); + } catch (SecurityException e) { + Slog.e(TAG, "Activity does not have the ", e); } } } + private boolean shouldApplyAutomaticChangesImmediately() { + return mCar || !mPowerManager.isInteractive(); + } + void updateLocked(int enableFlags, int disableFlags) { String action = null; String oldAction = null; @@ -1132,26 +1164,21 @@ final class UiModeManagerService extends SystemService { } } - private void updateComputedNightModeLocked() { - if (mTwilightManager != null) { - TwilightState state = mTwilightManager.getLastTwilightState(); - if (state != null) { - mComputedNightMode = state.isNight(); - } - if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) { - mComputedNightMode = true; - return; - } - if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) { - mComputedNightMode = false; - return; - } - - mNightModeOverride = mNightMode; - final int user = UserHandle.getCallingUserId(); - Secure.putIntForUser(getContext().getContentResolver(), - OVERRIDE_NIGHT_MODE, mNightModeOverride, user); + private void updateComputedNightModeLocked(boolean activate) { + mComputedNightMode = activate; + if (mNightModeOverride == UiModeManager.MODE_NIGHT_YES && !mComputedNightMode) { + mComputedNightMode = true; + return; + } + if (mNightModeOverride == UiModeManager.MODE_NIGHT_NO && mComputedNightMode) { + mComputedNightMode = false; + return; } + + mNightModeOverride = mNightMode; + final int user = UserHandle.getCallingUserId(); + Secure.putIntForUser(getContext().getContentResolver(), + OVERRIDE_NIGHT_MODE, mNightModeOverride, user); } private void registerVrStateListener() { @@ -1272,7 +1299,7 @@ final class UiModeManagerService extends SystemService { final boolean isIt = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_YES) != 0; if (LOG) { Slog.d(TAG, - "LocalService.isNightMode(): mNightMode=" + mNightMode + "LocalService.isNightMode(): mNightMode=" + mNightMode + "; mComputedNightMode=" + mComputedNightMode + "; uiMode=" + mConfiguration.uiMode + "; isIt=" + isIt); diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index 338f837b9b44..3fce5ebc8432 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -24,6 +24,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.os.PowerManager; +import android.os.PowerManagerInternal; import android.os.RemoteException; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -66,12 +67,14 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { TwilightManager mTwilightManager; @Mock PowerManager.WakeLock mWakeLock; + @Mock + PowerManager mPowerManager; private Set mScreenOffRecievers; @Before public void setUp() { mUiManagerService = new UiModeManagerService(mContext, mWindowManager, mWakeLock, - mTwilightManager, true); + mTwilightManager, mPowerManager, true); mScreenOffRecievers = new HashSet<>(); mService = mUiManagerService.getService(); when(mContext.checkCallingOrSelfPermission(anyString())) -- GitLab From 3e27a339176670f563c845b3ee027d5d5e6b671b Mon Sep 17 00:00:00 2001 From: Tyler Trephan Date: Fri, 14 Feb 2020 14:13:53 -0800 Subject: [PATCH 104/143] Updated wakeLock permission descriptions. Test: None Change-Id: Idc5e4be36b1527722e0dd84e8f2bcd0c2a7b02a3 Fix: 146586093 (cherry picked from commit 4701da640cc255253f87576c636b9fcac879bd89) --- core/res/res/values/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a0d2d842000b..5d5729b412be 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1211,6 +1211,8 @@ Allows the app to access the phone numbers of the device. + + keep car screen turned on prevent tablet from sleeping @@ -1218,6 +1220,8 @@ prevent phone from sleeping + Allows the app to keep the car screen turned on. + Allows the app to prevent the tablet from going to sleep. Allows the app to prevent the TV from going to sleep. -- GitLab From 9494c9dbb73b0ce237cb2f64fba90434b1b09c09 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Fri, 28 Feb 2020 23:04:58 +0000 Subject: [PATCH 105/143] DO NOT MERGE: Revert: Freeup lock when IME is set inactive and unbound Reason for revert: Caused an unexpected regression Bug 144174015 Bug: 139806621 Bug: 144103599 Fix: 144174015 Test: Manually verified Bug 144174015 disappeared as follows 1. Open Gmail then start composing an email 2. Swipe up the home button to recents then re-launch Gmail 3. Do the step 2 several times. 4. Make sure that you can still type something on Gmail. Change-Id: I04a77afea17f9d3eb05017fa00313fad4e48cd5c --- .../view/inputmethod/InputMethodManager.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index d3618adca6c4..d75810ad0e37 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -655,14 +655,14 @@ public final class InputMethodManager { } catch (RemoteException e) { } } - } - // Check focus again in case that "onWindowFocus" is called before - // handling this message. - if (mServedView != null && canStartInput(mServedView)) { - if (checkFocusNoStartInput(mRestartOnNextWindowFocus)) { - final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS - : StartInputReason.DEACTIVATED_BY_IMMS; - startInputInner(reason, null, 0, 0, 0); + // Check focus again in case that "onWindowFocus" is called before + // handling this message. + if (mServedView != null && canStartInput(mServedView)) { + if (checkFocusNoStartInput(mRestartOnNextWindowFocus)) { + final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS + : StartInputReason.DEACTIVATED_BY_IMMS; + startInputInner(reason, null, 0, 0, 0); + } } } return; @@ -1225,10 +1225,6 @@ public final class InputMethodManager { */ void clearBindingLocked() { if (DEBUG) Log.v(TAG, "Clearing binding!"); - if (mWindowFocusGainFuture != null) { - mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); - mWindowFocusGainFuture = null; - } clearConnectionLocked(); setInputChannelLocked(null); mBindSequence = -1; -- GitLab From 344858dd9c5616a0de16fa0ac72e0d384e2406c4 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Fri, 28 Feb 2020 23:04:58 +0000 Subject: [PATCH 106/143] DO NOT MERGE: Revert Move startInput for WINDOW_FOCUS_GAIN to background thread Reason for revert: Caused an unexpected regression Bug 144174015 Bug: 139806621 Bug: 144103599 Fix: 144174015 Test: Manually verified Bug 144174015 disappeared as follows 1. Open Gmail then start composing an email 2. Swipe up the home button to recents then re-launch Gmail 3. Do the step 2 several times. 4. Make sure that you can still type something on Gmail. Change-Id: I9265f01ed2f6e4aca7728d278f06ceea5633dac5 --- .../view/inputmethod/InputMethodManager.java | 77 ++++++------------- 1 file changed, 22 insertions(+), 55 deletions(-) diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index d75810ad0e37..032af1c5c7b5 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -92,10 +92,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; /** @@ -424,13 +421,6 @@ public final class InputMethodManager { int mCursorCandStart; int mCursorCandEnd; - /** - * Initial startInput with {@link StartInputReason.WINDOW_FOCUS_GAIN} is executed - * in a background thread. Later, if there is an actual startInput it will wait on - * main thread till the background thread completes. - */ - private CompletableFuture mWindowFocusGainFuture; - /** * The instance that has previously been sent to the input method. */ @@ -1608,18 +1598,6 @@ public final class InputMethodManager { boolean startInputInner(@StartInputReason int startInputReason, @Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode, int windowFlags) { - if (startInputReason != StartInputReason.WINDOW_FOCUS_GAIN - && mWindowFocusGainFuture != null) { - try { - mWindowFocusGainFuture.get(); - } catch (ExecutionException | InterruptedException e) { - // do nothing - } catch (CancellationException e) { - // window no longer has focus. - return true; - } - } - final View view; synchronized (mH) { view = mServedView; @@ -1973,38 +1951,31 @@ public final class InputMethodManager { startInputFlags |= StartInputFlags.FIRST_WINDOW_FOCUS_GAIN; } - final boolean forceNewFocus1 = forceNewFocus; - final int startInputFlags1 = startInputFlags; - if (mWindowFocusGainFuture != null) { - mWindowFocusGainFuture.cancel(false/* mayInterruptIfRunning */); - } - mWindowFocusGainFuture = CompletableFuture.runAsync(() -> { - if (checkFocusNoStartInput(forceNewFocus1)) { - // We need to restart input on the current focus view. This - // should be done in conjunction with telling the system service - // about the window gaining focus, to help make the transition - // smooth. - if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), - startInputFlags1, softInputMode, windowFlags)) { - return; - } + if (checkFocusNoStartInput(forceNewFocus)) { + // We need to restart input on the current focus view. This + // should be done in conjunction with telling the system service + // about the window gaining focus, to help make the transition + // smooth. + if (startInputInner(StartInputReason.WINDOW_FOCUS_GAIN, rootView.getWindowToken(), + startInputFlags, softInputMode, windowFlags)) { + return; } + } - // For some reason we didn't do a startInput + windowFocusGain, so - // we'll just do a window focus gain and call it a day. - synchronized (mH) { - try { - if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); - mService.startInputOrWindowGainedFocus( - StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, - rootView.getWindowToken(), startInputFlags1, softInputMode, windowFlags, - null, null, 0 /* missingMethodFlags */, - rootView.getContext().getApplicationInfo().targetSdkVersion); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + // For some reason we didn't do a startInput + windowFocusGain, so + // we'll just do a window focus gain and call it a day. + synchronized (mH) { + try { + if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); + mService.startInputOrWindowGainedFocus( + StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, + rootView.getWindowToken(), startInputFlags, softInputMode, windowFlags, + null, null, 0 /* missingMethodFlags */, + rootView.getContext().getApplicationInfo().targetSdkVersion); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - }); + } } /** @hide */ @@ -2019,10 +1990,6 @@ public final class InputMethodManager { // If the mCurRootView is losing window focus, release the strong reference to it // so as not to prevent it from being garbage-collected. mCurRootView = null; - if (mWindowFocusGainFuture != null) { - mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */); - mWindowFocusGainFuture = null; - } } else { if (DEBUG) { Log.v(TAG, "Ignoring onPreWindowFocus()." -- GitLab From 0d7e27af30e39fbb6dcafedc854daa639074e5cc Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 3 Mar 2020 14:36:21 +0800 Subject: [PATCH 107/143] RESTRICT AUTOMERGE Use consistent calling uid and package in navigateUpTo Originally, if the caller of navigateUpTo is alive, even the calling uid is set to the caller who launched the existing destination activity, the uid from caller process has higher priority to replace the given calling uid. So this change doesn't modify the existing behavior if the caller process is valid. Besides, the case of delivering new intent uses the source record as calling identity too, so the case of starting new activity should be consistent. Also forbid attaching null application thread to avoid unexpected state in process record. Bug: 144285917 Test: bit FrameworksServicesTests:com.android.server.am.ActivityStackTests Change-Id: I60732f430256d37cb926d08d093581f051c4afed --- .../android/server/am/ActivityManagerService.java | 5 ++++- .../java/com/android/server/am/ActivityStack.java | 13 +++++++++---- .../com/android/server/am/ActivityStackTests.java | 13 +++++++++++++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b4c18b13947c..87bad5c049e0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6916,7 +6916,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - private final boolean attachApplicationLocked(IApplicationThread thread, + private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid) { // Find the application record that is being attached... either via @@ -7221,6 +7221,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public final void attachApplication(IApplicationThread thread) { + if (thread == null) { + throw new SecurityException("Invalid application interface"); + } synchronized (this) { int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 199860597f9a..c1ea022f1c11 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3961,6 +3961,11 @@ class ActivityStack extends ConfigurationContai final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { + if (srec.app == null || srec.app.thread == null) { + // Nothing to do if the caller is not attached, because this method should be called + // from an alive activity. + return false; + } final TaskRecord task = srec.getTask(); final ArrayList activities = task.mActivities; final int start = activities.indexOf(srec); @@ -4012,22 +4017,22 @@ class ActivityStack extends ConfigurationContai } if (parent != null && foundParentInTask) { + final int callingUid = srec.info.applicationInfo.uid; final int parentLaunchMode = parent.info.launchMode; final int destIntentFlags = destIntent.getFlags(); if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent, - srec.packageName); + parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); } else { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( destIntent.getComponent(), 0, srec.userId); int res = mService.mActivityStarter.startActivityLocked(srec.app.thread, destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null, - null, parent.appToken, null, 0, -1, parent.launchedFromUid, - parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null, + null, parent.appToken, null, 0, -1, callingUid, + srec.packageName, -1, callingUid, 0, null, false, true, null, null, "navigateUpTo"); foundParentInTask = res == ActivityManager.START_SUCCESS; } catch (RemoteException e) { diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 02fba082ca98..33174b2bf074 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -122,4 +122,17 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(task.getTopActivity(true /* includeOverlays */), taskOverlay); assertNotNull(result.r); } + + @Test + public void testNavigateUpTo() { + final ActivityManagerService service = createActivityManagerService(); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); + final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); + activityRecord.app = new ProcessRecord(null, activityRecord.appInfo, + activityRecord.processName, activityRecord.getUid()); + final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID); + // No-op if the source activity record doesn't have attached process (app.thread == null). + assertFalse(testStack.navigateUpToLocked(activityRecord, activityRecord.intent, + 0 /* resultCode */, null /* resultData */)); + } } -- GitLab From 55e8fd2352e16f63f5ef5ab9d243712599e09091 Mon Sep 17 00:00:00 2001 From: jiabin Date: Mon, 23 Dec 2019 13:09:58 -0800 Subject: [PATCH 108/143] Set/get allowed capture policy via AudioService. Do not call AudioSystem.setAllowedCapturePolicy directly in AudioManager. Instead, send the request to AudioService and calling the function in AudioService. In that case, AudioService can cached the request so that it benefits returning correct playback configuration. When querying capture policy, AudioManager will query AudioService first to see if there is cached capture policy. If there is exception, return cached capture policy in AudioManager. Test: dumpsys audio, query active audio playback configuration Test: atest AudioManagerTest, AudioAttributesTest Test: atest AudioPlaybackCaptureTest, AudioPlaybackConfigurationTest Bug: 145115448 Change-Id: I170571d8a67839bc5a53991d6c89127b99b5c794 Merged-In: I170571d8a67839bc5a53991d6c89127b99b5c794 (cherry picked from commit b33f36971dd80e600be6a7ffc0c0df65849da016) --- media/java/android/media/AudioAttributes.java | 5 +- media/java/android/media/AudioManager.java | 29 ++++--- media/java/android/media/IAudioService.aidl | 4 + .../android/server/audio/AudioService.java | 58 +++++++++++++ .../server/audio/PlaybackActivityMonitor.java | 82 +++++++++++++++++++ 5 files changed, 165 insertions(+), 13 deletions(-) diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 820d82dd3bd1..d2ae7c100c3f 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -1251,7 +1251,10 @@ public final class AudioAttributes implements Parcelable { } } - static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) { + /** + * @hide + */ + public static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) { switch (capturePolicy) { case ALLOW_CAPTURE_BY_NONE: flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE; diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 6890270f1bb6..142bc12f25c4 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1507,23 +1507,22 @@ public class AudioManager { * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. - * @throws IllegalArgumentException if the argument is not a valid value. + * @throws RuntimeException if the argument is not a valid value. */ public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) { - int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0); - // TODO: got trough AudioService and save a cache to restore in case of AP crash // TODO: also pass the package in case multiple packages have the same UID - int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags); - if (result != AudioSystem.AUDIO_STATUS_OK) { - Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); - return; + final IAudioService service = getService(); + try { + int result = service.setAllowedCapturePolicy(capturePolicy); + if (result != AudioSystem.AUDIO_STATUS_OK) { + Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); + return; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - mCapturePolicy = capturePolicy; } - @AudioAttributes.CapturePolicy - private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL; - /** * Return the capture policy. * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or @@ -1531,7 +1530,13 @@ public class AudioManager { */ @AudioAttributes.CapturePolicy public int getAllowedCapturePolicy() { - return mCapturePolicy; + int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL; + try { + result = getService().getAllowedCapturePolicy(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to query allowed capture policy: " + e); + } + return result; } //==================================================================== diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 71f52a1b7d8e..7052e5afb565 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -259,6 +259,10 @@ interface IAudioService { boolean hasHapticChannels(in Uri uri); + int setAllowedCapturePolicy(in int capturePolicy); + + int getAllowedCapturePolicy(); + // WARNING: read warning at top of file, new methods that need to be used by native // code via IAudioManager.h need to be added to the top section. } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 3a5d4bc32d5c..d7bb4c074f48 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1041,6 +1041,27 @@ public class AudioService extends IAudioService.Stub } } + // Restore capture policies + synchronized (mPlaybackMonitor) { + HashMap allowedCapturePolicies = + mPlaybackMonitor.getAllAllowedCapturePolicies(); + for (HashMap.Entry entry : allowedCapturePolicies.entrySet()) { + int result = AudioSystem.setAllowedCapturePolicy( + entry.getKey(), + AudioAttributes.capturePolicyToFlags(entry.getValue(), 0x0)); + if (result != AudioSystem.AUDIO_STATUS_OK) { + Log.e(TAG, "Failed to restore capture policy, uid: " + + entry.getKey() + ", capture policy: " + entry.getValue() + + ", result: " + result); + // When restoring capture policy failed, set the capture policy as + // ALLOW_CAPTURE_BY_ALL, which will result in removing the cached + // capture policy in PlaybackActivityMonitor. + mPlaybackMonitor.setAllowedCapturePolicy( + entry.getKey(), AudioAttributes.ALLOW_CAPTURE_BY_ALL); + } + } + } + onIndicateSystemReady(); // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); @@ -7250,6 +7271,43 @@ public class AudioService extends IAudioService.Stub mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid()); } + /** + * Specifies whether the audio played by this app may or may not be captured by other apps or + * the system. + * + * @param capturePolicy one of + * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. + * @return AudioSystem.AUDIO_STATUS_OK if set allowed capture policy succeed. + * @throws IllegalArgumentException if the argument is not a valid value. + */ + public int setAllowedCapturePolicy(int capturePolicy) { + int callingUid = Binder.getCallingUid(); + int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0); + final long identity = Binder.clearCallingIdentity(); + synchronized (mPlaybackMonitor) { + int result = AudioSystem.setAllowedCapturePolicy(callingUid, flags); + if (result == AudioSystem.AUDIO_STATUS_OK) { + mPlaybackMonitor.setAllowedCapturePolicy(callingUid, capturePolicy); + } + Binder.restoreCallingIdentity(identity); + return result; + } + } + + /** + * Return the capture policy. + * @return the cached capture policy for the calling uid. + */ + public int getAllowedCapturePolicy() { + int callingUid = Binder.getCallingUid(); + final long identity = Binder.clearCallingIdentity(); + int capturePolicy = mPlaybackMonitor.getAllowedCapturePolicy(callingUid); + Binder.restoreCallingIdentity(identity); + return capturePolicy; + } + //====================== // Audio device management //====================== diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index 3a25d980e97a..93ffe835338f 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -160,6 +160,12 @@ public final class PlaybackActivityMonitor new AudioPlaybackConfiguration(pic, newPiid, Binder.getCallingUid(), Binder.getCallingPid()); apc.init(); + synchronized (mAllowedCapturePolicies) { + int uid = apc.getClientUid(); + if (mAllowedCapturePolicies.containsKey(uid)) { + updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid)); + } + } sEventLogger.log(new NewPlayerEvent(apc)); synchronized(mPlayerLock) { mPlayers.put(newPiid, apc); @@ -169,6 +175,13 @@ public final class PlaybackActivityMonitor public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) { final boolean change; + synchronized (mAllowedCapturePolicies) { + if (mAllowedCapturePolicies.containsKey(binderUid) + && attr.getAllowedCapturePolicy() < mAllowedCapturePolicies.get(binderUid)) { + attr = new AudioAttributes.Builder(attr) + .setAllowedCapturePolicy(mAllowedCapturePolicies.get(binderUid)).build(); + } + } synchronized(mPlayerLock) { final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid)); if (checkConfigurationCaller(piid, apc, binderUid)) { @@ -284,6 +297,69 @@ public final class PlaybackActivityMonitor } } + /** + * A map of uid to capture policy. + */ + private final HashMap mAllowedCapturePolicies = + new HashMap(); + + /** + * Cache allowed capture policy, which specifies whether the audio played by the app may or may + * not be captured by other apps or the system. + * + * @param uid the uid of requested app + * @param capturePolicy one of + * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, + * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. + */ + public void setAllowedCapturePolicy(int uid, int capturePolicy) { + synchronized (mAllowedCapturePolicies) { + if (capturePolicy == AudioAttributes.ALLOW_CAPTURE_BY_ALL) { + // When the capture policy is ALLOW_CAPTURE_BY_ALL, it is okay to + // remove it from cached capture policy as it is the default value. + mAllowedCapturePolicies.remove(uid); + return; + } else { + mAllowedCapturePolicies.put(uid, capturePolicy); + } + } + synchronized (mPlayerLock) { + for (AudioPlaybackConfiguration apc : mPlayers.values()) { + if (apc.getClientUid() == uid) { + updateAllowedCapturePolicy(apc, capturePolicy); + } + } + } + } + + /** + * Return the capture policy for given uid. + * @param uid the uid to query its cached capture policy. + * @return cached capture policy for given uid or AudioAttributes.ALLOW_CAPTURE_BY_ALL + * if there is not cached capture policy. + */ + public int getAllowedCapturePolicy(int uid) { + return mAllowedCapturePolicies.getOrDefault(uid, AudioAttributes.ALLOW_CAPTURE_BY_ALL); + } + + /** + * Return all cached capture policies. + */ + public HashMap getAllAllowedCapturePolicies() { + return mAllowedCapturePolicies; + } + + private void updateAllowedCapturePolicy(AudioPlaybackConfiguration apc, int capturePolicy) { + AudioAttributes attr = apc.getAudioAttributes(); + if (attr.getAllowedCapturePolicy() >= capturePolicy) { + return; + } + apc.handleAudioAttributesEvent( + new AudioAttributes.Builder(apc.getAudioAttributes()) + .setAllowedCapturePolicy(capturePolicy).build()); + } + // Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor @Override public void playerDeath(int piid) { @@ -331,6 +407,12 @@ public final class PlaybackActivityMonitor // log sEventLogger.dump(pw); } + synchronized (mAllowedCapturePolicies) { + pw.println("\n allowed capture policies:"); + for (HashMap.Entry entry : mAllowedCapturePolicies.entrySet()) { + pw.println(" uid: " + entry.getKey() + " policy: " + entry.getValue()); + } + } } /** -- GitLab From 8a2c62c2867d30dd2065096b63512d2861ebae51 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 3 Mar 2020 18:12:10 +0800 Subject: [PATCH 109/143] RESTRICT AUTOMERGE Use consistent calling uid and package in navigateUpTo Originally, if the caller of navigateUpTo is alive, even the calling uid is set to the caller who launched the existing destination activity, the uid from caller process has higher priority to replace the given calling uid. So this change doesn't modify the existing behavior if the caller process is valid. Besides, the case of delivering new intent uses the source record as calling identity too, so the case of starting new activity should be consistent. Also forbid attaching null application thread to avoid unexpected state in process record. Bug: 144285917 Test: atest ActivityStackTests#testNavigateUpTo Change-Id: I60732f430256d37cb926d08d093581f051c4afed --- .../server/am/ActivityManagerService.java | 5 ++- .../com/android/server/wm/ActivityStack.java | 15 ++++--- .../android/server/wm/ActivityStarter.java | 5 +++ .../android/server/wm/ActivityStackTests.java | 41 +++++++++++++++++-- .../android/server/wm/ActivityTestsBase.java | 1 + 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index cf00210c34d3..f9d13c286093 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4759,7 +4759,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @GuardedBy("this") - private final boolean attachApplicationLocked(IApplicationThread thread, + private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { // Find the application record that is being attached... either via @@ -5173,6 +5173,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public final void attachApplication(IApplicationThread thread, long startSeq) { + if (thread == null) { + throw new SecurityException("Invalid application interface"); + } synchronized (this) { int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 56be335c2624..1a9b11cd62d5 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4257,6 +4257,11 @@ class ActivityStack extends ConfigurationContainer { final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { + if (!srec.attachedToProcess()) { + // Nothing to do if the caller is not attached, because this method should be called + // from an alive activity. + return false; + } final TaskRecord task = srec.getTaskRecord(); final ArrayList activities = task.mActivities; final int start = activities.indexOf(srec); @@ -4310,14 +4315,14 @@ class ActivityStack extends ConfigurationContainer { } if (parent != null && foundParentInTask) { + final int callingUid = srec.info.applicationInfo.uid; final int parentLaunchMode = parent.info.launchMode; final int destIntentFlags = destIntent.getFlags(); if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent, - srec.packageName); + parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); } else { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( @@ -4330,10 +4335,10 @@ class ActivityStack extends ConfigurationContainer { .setActivityInfo(aInfo) .setResultTo(parent.appToken) .setCallingPid(-1) - .setCallingUid(parent.launchedFromUid) - .setCallingPackage(parent.launchedFromPackage) + .setCallingUid(callingUid) + .setCallingPackage(srec.packageName) .setRealCallingPid(-1) - .setRealCallingUid(parent.launchedFromUid) + .setRealCallingUid(callingUid) .setComponentSpecified(true) .execute(); foundParentInTask = res == ActivityManager.START_SUCCESS; diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 5b697ee89602..f37698de34d5 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2763,6 +2763,11 @@ class ActivityStarter { return mRequest.intent; } + @VisibleForTesting + int getCallingUid() { + return mRequest.callingUid; + } + ActivityStarter setReason(String reason) { mRequest.reason = reason; return this; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index bde0ef6aa39e..ff27b9bb1c9e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -28,7 +28,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; @@ -54,8 +54,11 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import android.app.ActivityManager; +import android.app.IApplicationThread; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.os.UserHandle; @@ -82,8 +85,9 @@ public class ActivityStackTests extends ActivityTestsBase { @Before public void setUp() throws Exception { mDefaultDisplay = mRootActivityContainer.getDefaultDisplay(); - mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, - true /* onTop */)); + mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, + true /* onTop */); + spyOn(mStack); mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); } @@ -1078,6 +1082,37 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(listener.mChanged); } + @Test + public void testNavigateUpTo() { + final ActivityStartController controller = mock(ActivityStartController.class); + final ActivityStarter starter = new ActivityStarter(controller, + mService, mService.mStackSupervisor, mock(ActivityStartInterceptor.class)); + doReturn(controller).when(mService).getActivityStartController(); + spyOn(starter); + doReturn(ActivityManager.START_SUCCESS).when(starter).execute(); + + final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask) + .setUid(firstActivity.getUid() + 1).build(); + doReturn(starter).when(controller).obtainStarter(eq(firstActivity.intent), anyString()); + + final IApplicationThread thread = secondActivity.app.getThread(); + secondActivity.app.setThread(null); + // This should do nothing from a non-attached caller. + assertFalse(mStack.navigateUpToLocked(secondActivity /* source record */, + firstActivity.intent /* destIntent */, 0 /* resultCode */, null /* resultData */)); + + secondActivity.app.setThread(thread); + assertTrue(mStack.navigateUpToLocked(secondActivity /* source record */, + firstActivity.intent /* destIntent */, 0 /* resultCode */, null /* resultData */)); + // The firstActivity uses default launch mode, so the activities between it and itself will + // be finished. + assertTrue(secondActivity.finishing); + assertTrue(firstActivity.finishing); + // The calling uid of the new activity should be the current real caller. + assertEquals(secondActivity.getUid(), starter.getCallingUid()); + } + private void verifyShouldSleepActivities(boolean focusedStack, boolean keyguardGoingAway, boolean displaySleeping, boolean expected) { final ActivityDisplay display = mock(ActivityDisplay.class); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 84bdecb86826..f94f00203521 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -290,6 +290,7 @@ class ActivityTestsBase { aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; aInfo.packageName = mComponent.getPackageName(); + aInfo.name = mComponent.getClassName(); if (mTargetActivity != null) { aInfo.targetActivity = mTargetActivity; } -- GitLab From be885c832f23b32aa11d44d234adffeedc6a90a7 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Wed, 20 Nov 2019 13:04:54 -0500 Subject: [PATCH 110/143] Remove Dependency.staticOnConfigurationChanged ConfigurationChangedReceiver is removed. Classes that want to be notified of configuration changes should implement ConfigurationController.ConfigurationListener instead and register themselves with the ConfigurationController. This CPs http://ag/9762349 Change-Id: I00c08a30b6d8dcac7e26230cb4354bc1fda74b10 Merged-In: Id2c3fe5ae2729b181769fb31b8050da264299d72 Bug: 150541820 Test: atest SystemUITests --- .../ConfigurationChangedReceiver.java | 21 ------- .../src/com/android/systemui/Dependency.java | 10 --- .../android/systemui/SystemUIApplication.java | 6 +- .../systemui/SystemUIRootComponent.java | 9 +++ .../systemui/assist/AssistManager.java | 61 +++++++++++-------- .../systemui/fragments/FragmentService.java | 25 +++++--- .../phone/ConfigurationControllerImpl.kt | 5 +- .../policy/ConfigurationController.java | 6 +- .../policy/NetworkControllerImpl.java | 22 +++---- .../com/android/systemui/DependencyTest.java | 11 ---- .../leaks/FakeConfigurationController.java | 6 ++ 11 files changed, 84 insertions(+), 98 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java diff --git a/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java b/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java deleted file mode 100644 index 4fba6404f370..000000000000 --- a/packages/SystemUI/src/com/android/systemui/ConfigurationChangedReceiver.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui; - -import android.content.res.Configuration; - -public interface ConfigurationChangedReceiver { - void onConfigurationChanged(Configuration newConfiguration); -} diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 15bea2484d7f..c09c7673d376 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -16,7 +16,6 @@ package com.android.systemui; import android.annotation.Nullable; import android.app.INotificationManager; -import android.content.res.Configuration; import android.hardware.SensorPrivacyManager; import android.hardware.display.NightDisplayListener; import android.os.Handler; @@ -521,15 +520,6 @@ public class Dependency { .forEach(o -> ((Dumpable) o).dump(fd, pw, args)); } - protected static void staticOnConfigurationChanged(Configuration newConfig) { - sDependency.onConfigurationChanged(newConfig); - } - - protected synchronized void onConfigurationChanged(Configuration newConfig) { - mDependencies.values().stream().filter(obj -> obj instanceof ConfigurationChangedReceiver) - .forEach(o -> ((ConfigurationChangedReceiver) o).onConfigurationChanged(newConfig)); - } - protected final T getDependency(Class cls) { return getDependencyInner(cls); } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index 9252e5767996..0d1bd6bae2b3 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -286,7 +286,11 @@ public class SystemUIApplication extends Application implements SysUiServiceProv @Override public void onConfigurationChanged(Configuration newConfig) { if (mServicesStarted) { - Dependency.staticOnConfigurationChanged(newConfig); + SystemUIFactory + .getInstance() + .getRootComponent() + .getConfigurationController() + .onConfigurationChanged(newConfig); int len = mServices.length; for (int i = 0; i < len; i++) { if (mServices[i] != null) { diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java index f18c8b2c3da6..a5b386eddd34 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java @@ -20,6 +20,7 @@ import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME import com.android.systemui.fragments.FragmentService; import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.leak.GarbageMonitor; @@ -40,12 +41,20 @@ import dagger.Component; SystemUIModule.class, SystemUIDefaultModule.class}) public interface SystemUIRootComponent { + /** * Main dependency providing module. */ @Singleton Dependency.DependencyInjector createDependency(); + + /** + * Creates a ConfigurationController. + */ + @Singleton + ConfigurationController getConfigurationController(); + /** * Injects the StatusBar. */ diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 1a2d062f1b80..74b4f9537b87 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -39,13 +39,13 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.applications.InterestingConfigChanges; -import com.android.systemui.ConfigurationChangedReceiver; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.ui.DefaultUiController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import javax.inject.Inject; @@ -55,7 +55,7 @@ import javax.inject.Singleton; * Class to manage everything related to assist in SystemUI. */ @Singleton -public class AssistManager implements ConfigurationChangedReceiver { +public class AssistManager { /** * Controls the UI for showing Assistant invocation progress. @@ -153,12 +153,40 @@ public class AssistManager implements ConfigurationChangedReceiver { } }; + private ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { + @Override + public void onConfigChanged(Configuration newConfig) { + if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) { + return; + } + boolean visible = false; + if (mView != null) { + visible = mView.isShowing(); + mWindowManager.removeView(mView); + } + + mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate( + R.layout.assist_orb, null); + mView.setVisibility(View.GONE); + mView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + WindowManager.LayoutParams lp = getLayoutParams(); + mWindowManager.addView(mView, lp); + if (visible) { + mView.show(true /* show */, false /* animate */); + } + } + }; + @Inject public AssistManager( DeviceProvisionedController controller, Context context, AssistUtils assistUtils, - AssistHandleBehaviorController handleController) { + AssistHandleBehaviorController handleController, + ConfigurationController configurationController) { mContext = context; mDeviceProvisionedController = controller; mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); @@ -167,11 +195,13 @@ public class AssistManager implements ConfigurationChangedReceiver { mPhoneStateMonitor = new PhoneStateMonitor(context); mHandleController = handleController; + configurationController.addCallback(mConfigurationListener); + registerVoiceInteractionSessionListener(); mInterestingConfigChanges = new InterestingConfigChanges(ActivityInfo.CONFIG_ORIENTATION | ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS); - onConfigurationChanged(context.getResources().getConfiguration()); + mConfigurationListener.onConfigChanged(context.getResources().getConfiguration()); mShouldEnableOrb = !ActivityManager.isLowRamDeviceStatic(); mUiController = new DefaultUiController(mContext); @@ -221,29 +251,6 @@ public class AssistManager implements ConfigurationChangedReceiver { }); } - public void onConfigurationChanged(Configuration newConfiguration) { - if (!mInterestingConfigChanges.applyNewConfig(mContext.getResources())) { - return; - } - boolean visible = false; - if (mView != null) { - visible = mView.isShowing(); - mWindowManager.removeView(mView); - } - - mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate( - R.layout.assist_orb, null); - mView.setVisibility(View.GONE); - mView.setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - WindowManager.LayoutParams lp = getLayoutParams(); - mWindowManager.addView(mView, lp); - if (visible) { - mView.show(true /* show */, false /* animate */); - } - } - protected boolean shouldShowOrb() { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java index b4cc571be061..bbf49e3d13d2 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java @@ -20,11 +20,11 @@ import android.os.Handler; import android.util.ArrayMap; import android.view.View; -import com.android.systemui.ConfigurationChangedReceiver; import com.android.systemui.Dumpable; import com.android.systemui.SystemUIRootComponent; import com.android.systemui.qs.QSFragment; import com.android.systemui.statusbar.phone.NavigationBarFragment; +import com.android.systemui.statusbar.policy.ConfigurationController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -41,7 +41,7 @@ import dagger.Subcomponent; * Also dispatches the configuration changes to all current FragmentHostStates. */ @Singleton -public class FragmentService implements ConfigurationChangedReceiver, Dumpable { +public class FragmentService implements Dumpable { private static final String TAG = "FragmentService"; @@ -50,10 +50,22 @@ public class FragmentService implements ConfigurationChangedReceiver, Dumpable { private final Handler mHandler = new Handler(); private final FragmentCreator mFragmentCreator; + private ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { + @Override + public void onConfigChanged(Configuration newConfig) { + for (FragmentHostState state : mHosts.values()) { + state.sendConfigurationChange(newConfig); + } + } + }; + @Inject - public FragmentService(SystemUIRootComponent rootComponent) { + public FragmentService(SystemUIRootComponent rootComponent, + ConfigurationController configurationController) { mFragmentCreator = rootComponent.createFragmentCreator(); initInjectionMap(); + configurationController.addCallback(mConfigurationListener); } ArrayMap getInjectionMap() { @@ -96,13 +108,6 @@ public class FragmentService implements ConfigurationChangedReceiver, Dumpable { } } - @Override - public void onConfigurationChanged(Configuration newConfig) { - for (FragmentHostState state : mHosts.values()) { - state.sendConfigurationChange(newConfig); - } - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Dumping fragments:"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt index 424acfd9916b..54ef623e95ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt @@ -18,14 +18,11 @@ import android.content.Context import android.content.pm.ActivityInfo import android.content.res.Configuration import android.os.LocaleList - -import com.android.systemui.ConfigurationChangedReceiver import com.android.systemui.statusbar.policy.ConfigurationController import java.util.ArrayList -class ConfigurationControllerImpl(context: Context) - : ConfigurationController, ConfigurationChangedReceiver { +class ConfigurationControllerImpl(context: Context) : ConfigurationController { private val listeners: MutableList = ArrayList() private val lastConfig = Configuration() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java index 0e5c8c105df8..0a6cf7be736f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java @@ -24,7 +24,11 @@ import com.android.systemui.statusbar.policy.ConfigurationController.Configurati */ public interface ConfigurationController extends CallbackController { - public void notifyThemeChanged(); + /** Alert controller of a change in the configuration. */ + void onConfigurationChanged(Configuration newConfiguration); + + /** Alert controller of a change in between light and dark themes. */ + void notifyThemeChanged(); interface ConfigurationListener { default void onConfigChanged(Configuration newConfig) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 7a09455017dd..2ad5a8aa7fe5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -61,7 +61,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.settingslib.net.DataUsageController; -import com.android.systemui.ConfigurationChangedReceiver; import com.android.systemui.DemoMode; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -87,8 +86,7 @@ import javax.inject.Singleton; /** Platform implementation of the network controller. **/ @Singleton public class NetworkControllerImpl extends BroadcastReceiver - implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider, - ConfigurationChangedReceiver, Dumpable { + implements NetworkController, DemoMode, DataUsageController.NetworkNameProvider, Dumpable { // debug static final String TAG = "NetworkController"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -166,6 +164,14 @@ public class NetworkControllerImpl extends BroadcastReceiver private boolean mUserSetup; private boolean mSimDetected; + private ConfigurationController.ConfigurationListener mConfigurationListener = + new ConfigurationController.ConfigurationListener() { + @Override + public void onConfigChanged(Configuration newConfig) { + mConfig = Config.readConfig(mContext); + mReceiverHandler.post(() -> handleConfigurationChanged()); + } + }; /** * Construct this controller object and register for updates. */ @@ -553,16 +559,6 @@ public class NetworkControllerImpl extends BroadcastReceiver } } - public void onConfigurationChanged(Configuration newConfig) { - mConfig = Config.readConfig(mContext); - mReceiverHandler.post(new Runnable() { - @Override - public void run() { - handleConfigurationChanged(); - } - }); - } - @VisibleForTesting void handleConfigurationChanged() { updateMobileControllers(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java index b9d09ce91c1a..420acc507f19 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java @@ -36,8 +36,6 @@ import java.io.PrintWriter; public class DependencyTest extends SysuiTestCase { public static final DependencyKey DUMPABLE = new DependencyKey<>("dumpable"); - public static final DependencyKey CONFIGURATION_CHANGED_RECEIVER - = new DependencyKey<>("config_changed_receiver"); @Test public void testClassDependency() { @@ -62,15 +60,6 @@ public class DependencyTest extends SysuiTestCase { verify(d).dump(eq(null), any(), eq(null)); } - @Test - public void testConfigurationChanged() { - ConfigurationChangedReceiver d = mock(ConfigurationChangedReceiver.class); - mDependency.injectTestDependency(CONFIGURATION_CHANGED_RECEIVER, d); - Dependency.get(CONFIGURATION_CHANGED_RECEIVER); - mDependency.onConfigurationChanged(null); - verify(d).onConfigurationChanged(eq(null)); - } - @Test public void testInitDependency() { Dependency.clearDependencies(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java index 5ddf7a208379..f5ccac39ed20 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java @@ -14,6 +14,8 @@ package com.android.systemui.utils.leaks; +import android.content.res.Configuration; + import com.android.systemui.statusbar.policy.ConfigurationController; public class FakeConfigurationController @@ -24,6 +26,10 @@ public class FakeConfigurationController super(sysuiLeakCheck, "config"); } + @Override + public void onConfigurationChanged(Configuration newConfiguration) { + } + @Override public void notifyThemeChanged() { } -- GitLab From 24ee8ef61e696248f6bdcc23842418808e3630ef Mon Sep 17 00:00:00 2001 From: Kai Shi Date: Wed, 26 Feb 2020 15:46:56 -0800 Subject: [PATCH 111/143] Add EAP methods in wifi.proto To help find the root cause of high authentication failure rate in enterprise network, add EAP method and authentication phase2 method in connection event metrics. Bug: 150237135 Test: manual Test: atest com.android.server.wifi Merged-In: I7f3268b2842783f99c0a43d8b4996d0a7dd46c6e Change-Id: Id4ac7947871785d16b81c0806986f54d64fdb0ce --- proto/src/wifi.proto | 66 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 353a18756ca2..03495d2e8c40 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -635,6 +635,66 @@ message RouterFingerPrint { ROUTER_TECH_OTHER = 6; } + enum EapMethod { + + // No EAP method used + TYPE_EAP_UNKNOWN = 0; + + // EAP with Transport Layer Security + TYPE_EAP_TLS = 1; + + // EAP with Tunneled Transport Layer Security + TYPE_EAP_TTLS = 2; + + // EAP with Subscriber Identity Module [RFC-4186] + TYPE_EAP_SIM = 3; + + // EAP with Authentication and Key Agreement [RFC-4187] + TYPE_EAP_AKA = 4; + + // EAP with Authentication and Key Agreement Prime [RFC-5448] + TYPE_EAP_AKA_PRIME = 5; + + // Protected EAP + TYPE_EAP_PEAP = 6; + + // EAP for Hotspot 2.0 r2 OSEN + TYPE_EAP_UNAUTH_TLS = 7; + + // EAP with Password + TYPE_EAP_PWD = 8; + + // EAP with WAPI certifcate + TYPE_EAP_WAPI_CERT = 9; + } + + enum AuthPhase2Method { + + // No phase2 method + TYPE_PHASE2_NONE = 0; + + // Password Authentication Protocol + TYPE_PHASE2_PAP = 1; + + // Microsoft Challenge Handshake Authentication Protocol + TYPE_PHASE2_MSCHAP = 2; + + // Microsoft Challenge Handshake Authentication Protocol v2 + TYPE_PHASE2_MSCHAPV2 = 3; + + // Generic Token Card + TYPE_PHASE2_GTC = 4; + + // EAP-Subscriber Identity Module [RFC-4186] + TYPE_PHASE2_SIM = 5; + + // EAP-Authentication and Key Agreement [RFC-4187] + TYPE_PHASE2_AKA = 6; + + // EAP-Authentication and Key Agreement Prime [RFC-5448] + TYPE_PHASE2_AKA_PRIME = 7; + } + optional RoamType roam_type = 1; // Channel on which the connection takes place. @@ -657,6 +717,12 @@ message RouterFingerPrint { // If the router is a passpoint / hotspot 2.0 network optional bool passpoint = 8; + + // EAP method used by the enterprise network + optional EapMethod eap_method = 9; + + // Phase 2 authentication method after setting up a secure channel + optional AuthPhase2Method auth_phase2_method = 10; } message ConnectionEvent { -- GitLab From 96a9e48520fc2359a3cdd6b3513bf158d6844365 Mon Sep 17 00:00:00 2001 From: "Nate(Qiang) Jiang" Date: Mon, 2 Mar 2020 17:09:44 -0800 Subject: [PATCH 112/143] Create different KeyId for saved and suggestion network Bug: 150500247 Test: atest android.net.wifi Merged-In: I31ee6f3a3295aca0bd7fcb83ce74327922977797 Change-Id: Ia416b2e986c86fe0a29641f6a20236802d72a233 --- .../android/net/wifi/WifiConfiguration.java | 14 ++++- .../net/wifi/WifiConfigurationTest.java | 61 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index ed416429a279..88f2bb2ad6e8 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -2113,15 +2113,23 @@ public class WifiConfiguration implements Parcelable { throw new IllegalStateException("Not an EAP network"); } - return trimStringForKeyId(SSID) + "_" + keyMgmt + "_" + - trimStringForKeyId(enterpriseConfig.getKeyId(current != null ? - current.enterpriseConfig : null)); + String keyId = trimStringForKeyId(SSID) + "_" + keyMgmt + "_" + + trimStringForKeyId(enterpriseConfig.getKeyId(current != null + ? current.enterpriseConfig : null)); + + if (!fromWifiNetworkSuggestion) { + return keyId; + } + return keyId + "_" + trimStringForKeyId(BSSID) + "_" + trimStringForKeyId(creatorName); } catch (NullPointerException e) { throw new IllegalStateException("Invalid config details"); } } private String trimStringForKeyId(String string) { + if (string == null) { + return ""; + } // Remove quotes and spaces return string.replace("\"", "").replace(" ", ""); } diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index ba9fc786afe7..f56cdc30af36 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -349,6 +349,67 @@ public class WifiConfigurationTest { assertTrue(exceptionThrown); } + /** + * Verifies that getKeyIdForCredentials returns the expected string for Suggestion Enterprise + * networks + * @throws Exception + */ + @Test + public void testGetKeyIdForCredentialsForSuggestion() throws Exception { + WifiConfiguration config = new WifiConfiguration(); + final String mSsid = "TestAP"; + final String packageName = "TestApp"; + final String bSsid = MacAddress.createRandomUnicastAddress().toString(); + String suggestionSuffix = "_" + bSsid + "_" + packageName; + config.SSID = mSsid; + config.fromWifiNetworkSuggestion = true; + config.creatorName = packageName; + config.BSSID = bSsid; + + // Test various combinations + // EAP with TLS + config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); + config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS); + config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE); + String keyId = config.getKeyIdForCredentials(config); + assertEquals(keyId, mSsid + "_WPA_EAP_TLS_NULL" + suggestionSuffix); + + // EAP with TTLS & MSCHAPv2 + config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); + config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS); + config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAPV2); + keyId = config.getKeyIdForCredentials(config); + assertEquals(keyId, mSsid + "_WPA_EAP_TTLS_MSCHAPV2" + suggestionSuffix); + + // Suite-B 192 with PWD & GTC + config.allowedKeyManagement.clear(); + config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192); + config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PWD); + config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC); + keyId = config.getKeyIdForCredentials(config); + assertEquals(keyId, mSsid + "_SUITE_B_192_PWD_GTC" + suggestionSuffix); + + // IEEE8021X with SIM + config.allowedKeyManagement.clear(); + config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM); + config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE); + keyId = config.getKeyIdForCredentials(config); + assertEquals(keyId, mSsid + "_IEEE8021X_SIM_NULL" + suggestionSuffix); + + // Try calling this method with non-Enterprise network, expect an exception + boolean exceptionThrown = false; + try { + config.allowedKeyManagement.clear(); + config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); + config.preSharedKey = "TestPsk"; + keyId = config.getKeyIdForCredentials(config); + } catch (IllegalStateException e) { + exceptionThrown = true; + } + assertTrue(exceptionThrown); + } + /** * Verifies that getSsidAndSecurityTypeString returns the correct String for networks of * various different security types -- GitLab From dfa720a5e97f1f68209c708c3a1fd1294d57b459 Mon Sep 17 00:00:00 2001 From: "Nate(Qiang) Jiang" Date: Wed, 4 Mar 2020 00:04:48 -0800 Subject: [PATCH 113/143] fix break build Bug: 150747236 Test: build Change-Id: Ic63771975d3d951548b3454d5971dc8cd817218d --- wifi/tests/src/android/net/wifi/WifiConfigurationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index f9bd6bb4e230..fe30ddd3765a 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -361,7 +361,7 @@ public class WifiConfigurationTest { WifiConfiguration config = new WifiConfiguration(); final String mSsid = "TestAP"; final String packageName = "TestApp"; - final String bSsid = MacAddress.createRandomUnicastAddress().toString(); + final String bSsid = MacAddressUtils.createRandomUnicastAddress().toString(); String suggestionSuffix = "_" + bSsid + "_" + packageName; config.SSID = mSsid; config.fromWifiNetworkSuggestion = true; -- GitLab From 2fd00cd4032c67242f26da16e24ccb51dac8ca48 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Thu, 14 Nov 2019 18:18:30 +0000 Subject: [PATCH 114/143] Frameworks/base: Support dex2oat cpu-set system property Check dalvik.vm.dex2oat-cpu-set in AndroidRuntime and pass to ART with "--cpu-set=" as a compiler option, if found. Check dalvik.vm.image-dex2oat-cpu-set in AndroidRuntime and pass to ART with "--cpu-set=" as an image compiler option, if found. Bug: 141446571 Bug: 149395059 Test: manual Change-Id: Ica6a39048292d3d43aeb58d25f79f1398a7d5a79 Merged-In: Ica6a39048292d3d43aeb58d25f79f1398a7d5a79 (cherry picked from commit 870ce3f6d790f9c692b6d5e8872b33f5b642ea0b) --- core/jni/AndroidRuntime.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index cd0b340d489d..c2a7c79f714b 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -665,6 +665,8 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX]; + char dex2oatCpuSetBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX]; + char dex2oatCpuSetImageBuf[sizeof("--cpu-set=")-1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_variant_key[PROPERTY_KEY_MAX]; char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX]; char dex2oat_isa_features_key[PROPERTY_KEY_MAX]; @@ -937,6 +939,10 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option"); parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j", "-Ximage-compiler-option"); + parseCompilerOption("dalvik.vm.dex2oat-cpu-set", dex2oatCpuSetBuf, "--cpu-set=", + "-Xcompiler-option"); + parseCompilerOption("dalvik.vm.image-dex2oat-cpu-set", dex2oatCpuSetImageBuf, "--cpu-set=", + "-Ximage-compiler-option"); // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to // pass the instruction-set-features/variant as an image-compiler-option. -- GitLab From da78af4d6696dda77c692a7c6f2f49d4277cf341 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 3 Mar 2020 16:29:31 +0800 Subject: [PATCH 115/143] RESTRICT AUTOMERGE Use consistent calling uid and package in navigateUpTo Originally, if the caller of navigateUpTo is alive, even the calling uid is set to the caller who launched the existing destination activity, the uid from caller process has higher priority to replace the given calling uid. So this change doesn't modify the existing behavior if the caller process is valid. Besides, the case of delivering new intent uses the source record as calling identity too, so the case of starting new activity should be consistent. Also forbid attaching null application thread to avoid unexpected state in process record. Bug: 144285917 Test: atest ActivityStackTests#testNavigateUpTo Test: atest CtsSecurityTestCases:ActivityManagerTest# \ testActivityManager_attachNullApplication Change-Id: I60732f430256d37cb926d08d093581f051c4afed --- .../android/server/am/ActivityManagerService.java | 5 ++++- .../java/com/android/server/am/ActivityStack.java | 15 ++++++++++----- .../com/android/server/am/ActivityStackTests.java | 13 +++++++++++++ .../com/android/server/am/ActivityTestsBase.java | 2 ++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7c57c43533af..13ec0133938b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7593,7 +7593,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @GuardedBy("this") - private final boolean attachApplicationLocked(IApplicationThread thread, + private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { // Find the application record that is being attached... either via @@ -7974,6 +7974,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public final void attachApplication(IApplicationThread thread, long startSeq) { + if (thread == null) { + throw new SecurityException("Invalid application interface"); + } synchronized (this) { int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 19ee3572d619..0fd8bb8d697a 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3943,6 +3943,11 @@ class ActivityStack extends ConfigurationContai final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { + if (srec.app == null || srec.app.thread == null) { + // Nothing to do if the caller is not attached, because this method should be called + // from an alive activity. + return false; + } final TaskRecord task = srec.getTask(); final ArrayList activities = task.mActivities; final int start = activities.indexOf(srec); @@ -3994,14 +3999,14 @@ class ActivityStack extends ConfigurationContai } if (parent != null && foundParentInTask) { + final int callingUid = srec.info.applicationInfo.uid; final int parentLaunchMode = parent.info.launchMode; final int destIntentFlags = destIntent.getFlags(); if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent, - srec.packageName); + parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); } else { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( @@ -4014,10 +4019,10 @@ class ActivityStack extends ConfigurationContai .setActivityInfo(aInfo) .setResultTo(parent.appToken) .setCallingPid(-1) - .setCallingUid(parent.launchedFromUid) - .setCallingPackage(parent.launchedFromPackage) + .setCallingUid(callingUid) + .setCallingPackage(srec.packageName) .setRealCallingPid(-1) - .setRealCallingUid(parent.launchedFromUid) + .setRealCallingUid(callingUid) .setComponentSpecified(true) .execute(); foundParentInTask = res == ActivityManager.START_SUCCESS; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 01425ed51b55..55ece4cf03da 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -606,6 +606,19 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(listener.changed); } + @Test + public void testNavigateUpTo() { + final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask) + .setUid(firstActivity.getUid() + 1).build(); + secondActivity.app.thread = null; + // This should do nothing from a non-attached caller (app.thread == null). + assertFalse(mStack.navigateUpToLocked(secondActivity /* source record */, + firstActivity.intent /* destIntent */, 0 /* resultCode */, null /* resultData */)); + assertFalse(secondActivity.finishing); + assertFalse(firstActivity.finishing); + } + private void verifyShouldSleepActivities(boolean focusedStack, boolean keyguardGoingAway, boolean displaySleeping, boolean expected) { mSupervisor.mFocusedStack = focusedStack ? mStack : null; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 1cd111fce0ec..6467dbd85701 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -192,6 +192,8 @@ public class ActivityTestsBase { aInfo.applicationInfo = new ApplicationInfo(); aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; + aInfo.packageName = mComponent.getPackageName(); + aInfo.name = mComponent.getClassName(); aInfo.flags |= mActivityFlags; final ActivityRecord activity = new ActivityRecord(mService, null /* caller */, -- GitLab From 1ec2f403e9552d4d43413231e436bbdfd9eec1ec Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 3 Mar 2020 18:12:10 +0800 Subject: [PATCH 116/143] RESTRICT AUTOMERGE Use consistent calling uid and package in navigateUpTo Originally, if the caller of navigateUpTo is alive, even the calling uid is set to the caller who launched the existing destination activity, the uid from caller process has higher priority to replace the given calling uid. So this change doesn't modify the existing behavior if the caller process is valid. Besides, the case of delivering new intent uses the source record as calling identity too, so the case of starting new activity should be consistent. Also forbid attaching null application thread to avoid unexpected state in process record. Bug: 144285917 Test: atest ActivityStackTests#testNavigateUpTo Test: atest CtsSecurityTestCases:ActivityManagerTest# \ testActivityManager_attachNullApplication Change-Id: I60732f430256d37cb926d08d093581f051c4afed --- .../server/am/ActivityManagerService.java | 5 ++- .../com/android/server/wm/ActivityStack.java | 15 ++++--- .../android/server/wm/ActivityStarter.java | 5 +++ .../android/server/wm/ActivityStackTests.java | 41 +++++++++++++++++-- .../android/server/wm/ActivityTestsBase.java | 1 + 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c6cae530e795..f045274e43f7 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4759,7 +4759,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @GuardedBy("this") - private final boolean attachApplicationLocked(IApplicationThread thread, + private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { // Find the application record that is being attached... either via @@ -5173,6 +5173,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public final void attachApplication(IApplicationThread thread, long startSeq) { + if (thread == null) { + throw new SecurityException("Invalid application interface"); + } synchronized (this) { int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 6bed46226b42..764b92929de0 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4241,6 +4241,11 @@ class ActivityStack extends ConfigurationContainer { final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { + if (!srec.attachedToProcess()) { + // Nothing to do if the caller is not attached, because this method should be called + // from an alive activity. + return false; + } final TaskRecord task = srec.getTaskRecord(); final ArrayList activities = task.mActivities; final int start = activities.indexOf(srec); @@ -4294,14 +4299,14 @@ class ActivityStack extends ConfigurationContainer { } if (parent != null && foundParentInTask) { + final int callingUid = srec.info.applicationInfo.uid; final int parentLaunchMode = parent.info.launchMode; final int destIntentFlags = destIntent.getFlags(); if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent, - srec.packageName); + parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); } else { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( @@ -4314,10 +4319,10 @@ class ActivityStack extends ConfigurationContainer { .setActivityInfo(aInfo) .setResultTo(parent.appToken) .setCallingPid(-1) - .setCallingUid(parent.launchedFromUid) - .setCallingPackage(parent.launchedFromPackage) + .setCallingUid(callingUid) + .setCallingPackage(srec.packageName) .setRealCallingPid(-1) - .setRealCallingUid(parent.launchedFromUid) + .setRealCallingUid(callingUid) .setComponentSpecified(true) .execute(); foundParentInTask = res == ActivityManager.START_SUCCESS; diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 0a88eef86ea8..1ebfa46f1955 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2743,6 +2743,11 @@ class ActivityStarter { return mRequest.intent; } + @VisibleForTesting + int getCallingUid() { + return mRequest.callingUid; + } + ActivityStarter setReason(String reason) { mRequest.reason = reason; return this; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index bde0ef6aa39e..ff27b9bb1c9e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -28,7 +28,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; @@ -54,8 +54,11 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import android.app.ActivityManager; +import android.app.IApplicationThread; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.os.UserHandle; @@ -82,8 +85,9 @@ public class ActivityStackTests extends ActivityTestsBase { @Before public void setUp() throws Exception { mDefaultDisplay = mRootActivityContainer.getDefaultDisplay(); - mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, - true /* onTop */)); + mStack = mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, + true /* onTop */); + spyOn(mStack); mTask = new TaskBuilder(mSupervisor).setStack(mStack).build(); } @@ -1078,6 +1082,37 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(listener.mChanged); } + @Test + public void testNavigateUpTo() { + final ActivityStartController controller = mock(ActivityStartController.class); + final ActivityStarter starter = new ActivityStarter(controller, + mService, mService.mStackSupervisor, mock(ActivityStartInterceptor.class)); + doReturn(controller).when(mService).getActivityStartController(); + spyOn(starter); + doReturn(ActivityManager.START_SUCCESS).when(starter).execute(); + + final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); + final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask) + .setUid(firstActivity.getUid() + 1).build(); + doReturn(starter).when(controller).obtainStarter(eq(firstActivity.intent), anyString()); + + final IApplicationThread thread = secondActivity.app.getThread(); + secondActivity.app.setThread(null); + // This should do nothing from a non-attached caller. + assertFalse(mStack.navigateUpToLocked(secondActivity /* source record */, + firstActivity.intent /* destIntent */, 0 /* resultCode */, null /* resultData */)); + + secondActivity.app.setThread(thread); + assertTrue(mStack.navigateUpToLocked(secondActivity /* source record */, + firstActivity.intent /* destIntent */, 0 /* resultCode */, null /* resultData */)); + // The firstActivity uses default launch mode, so the activities between it and itself will + // be finished. + assertTrue(secondActivity.finishing); + assertTrue(firstActivity.finishing); + // The calling uid of the new activity should be the current real caller. + assertEquals(secondActivity.getUid(), starter.getCallingUid()); + } + private void verifyShouldSleepActivities(boolean focusedStack, boolean keyguardGoingAway, boolean displaySleeping, boolean expected) { final ActivityDisplay display = mock(ActivityDisplay.class); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 4986a6d5bd0d..1d366259b590 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -265,6 +265,7 @@ class ActivityTestsBase { aInfo.applicationInfo.packageName = mComponent.getPackageName(); aInfo.applicationInfo.uid = mUid; aInfo.packageName = mComponent.getPackageName(); + aInfo.name = mComponent.getClassName(); if (mTargetActivity != null) { aInfo.targetActivity = mTargetActivity; } -- GitLab From 60a6583adfdb50df1643e0df2dc37096f977a483 Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Tue, 4 Feb 2020 16:41:06 +0000 Subject: [PATCH 117/143] RESTRICT AUTOMERGE Block TYPE_PRESENTATION windows on default display ... and any other display that isn't considered a public presentation display, as per Display.isPublicPresentation() Bug: 141745510 Test: cts-tradefed run cts -m CtsWindowManagerDeviceTestCases -t android.server.wm.PresentationTest Change-Id: I2aaab1903dee54190338f7b6e49888aa51437108 --- core/java/android/app/Presentation.java | 16 +++++++++------- .../android/server/wm/WindowManagerService.java | 8 ++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index cb72d4d5dc2c..b3a39f5025c7 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -26,18 +26,18 @@ import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; -import android.os.Handler; -import android.os.Message; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.TypedValue; /** * Base class for presentations. @@ -116,7 +116,9 @@ import android.util.TypedValue; * The display manager keeps track of all displays in the system. However, not all * displays are appropriate for showing presentations. For example, if an activity * attempted to show a presentation on the main display it might obscure its own content - * (it's like opening a dialog on top of your activity). + * (it's like opening a dialog on top of your activity). Creating a presentation on the main + * display will result in {@link android.view.WindowManager.InvalidDisplayException} being thrown + * when invoking {@link #show()}. *

* Here's how to identify suitable displays for showing presentations using * {@link DisplayManager#getDisplays(String)} and the @@ -243,7 +245,7 @@ public class Presentation extends Dialog { /** * Inherited from {@link Dialog#show}. Will throw * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary - * {@link Display} can't be found. + * {@link Display} can't be found or if it does not have {@link Display#FLAG_PRESENTATION} set. */ @Override public void show() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 436a5c729b86..2de8ae155f81 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -60,6 +60,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; @@ -1276,6 +1277,13 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_PERMISSION_DENIED; } + if (type == TYPE_PRESENTATION && !displayContent.getDisplay().isPublicPresentation()) { + Slog.w(TAG_WM, + "Attempted to add presentation window to a non-suitable display. " + + "Aborting."); + return WindowManagerGlobal.ADD_INVALID_DISPLAY; + } + AppWindowToken atoken = null; final boolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token -- GitLab From bf89805ea34cc6232a34538bad9e00d51b3672eb Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Tue, 4 Feb 2020 16:41:06 +0000 Subject: [PATCH 118/143] RESTRICT AUTOMERGE Block TYPE_PRESENTATION windows on default display ... and any other display that isn't considered a public presentation display, as per Display.isPublicPresentation() Bug: 141745510 Test: cts-tradefed run cts -m CtsActivityManagerDeviceTestCases -t android.server.am.PresentationTest Change-Id: I2aaab1903dee54190338f7b6e49888aa51437108 --- core/java/android/app/Presentation.java | 16 +++++++++------- .../android/server/wm/WindowManagerService.java | 8 ++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index af55788e617f..bc2b250328a6 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -25,18 +25,18 @@ import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; -import android.os.Handler; -import android.os.Message; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.TypedValue; /** * Base class for presentations. @@ -115,7 +115,9 @@ import android.util.TypedValue; * The display manager keeps track of all displays in the system. However, not all * displays are appropriate for showing presentations. For example, if an activity * attempted to show a presentation on the main display it might obscure its own content - * (it's like opening a dialog on top of your activity). + * (it's like opening a dialog on top of your activity). Creating a presentation on the main + * display will result in {@link android.view.WindowManager.InvalidDisplayException} being thrown + * when invoking {@link #show()}. *

* Here's how to identify suitable displays for showing presentations using * {@link DisplayManager#getDisplays(String)} and the @@ -242,7 +244,7 @@ public class Presentation extends Dialog { /** * Inherited from {@link Dialog#show}. Will throw * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary - * {@link Display} can't be found. + * {@link Display} can't be found or if it does not have {@link Display#FLAG_PRESENTATION} set. */ @Override public void show() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8b4a2dd36e6c..b438d044d102 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -55,6 +55,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; @@ -1182,6 +1183,13 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_PERMISSION_DENIED; } + if (type == TYPE_PRESENTATION && !displayContent.getDisplay().isPublicPresentation()) { + Slog.w(TAG_WM, + "Attempted to add presentation window to a non-suitable display. " + + "Aborting."); + return WindowManagerGlobal.ADD_INVALID_DISPLAY; + } + AppWindowToken atoken = null; final boolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token -- GitLab From 06a7bf9e9e1ae1b6b5a162fa664ad5ed5670ad74 Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Wed, 4 Mar 2020 12:19:37 -0800 Subject: [PATCH 119/143] DO NOT MERGE Set the sensor threshold only if sensor exists Bug: 150779130 Test: atest SystemUITests and manual test for automotive Change-Id: I18e3584c66f1286713a6fdadc678a9048869913b --- .../SystemUI/src/com/android/systemui/doze/DozeSensors.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index b7c8f707b850..e6cbab26c655 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -305,7 +305,7 @@ public class DozeSensors { mContext.getResources()); } else { sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); - mSensorThreshold = sensor.getMaximumRange(); + mSensorThreshold = sensor == null ? 0 : sensor.getMaximumRange(); } mSensor = sensor; } -- GitLab From 2b05cccddfe4a57f5e3ecb83be16e3f88c052849 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 4 Mar 2020 14:15:52 -0800 Subject: [PATCH 120/143] Animate cuttout protection Bug: 145095085 Change-Id: Ida54d4369a2cb8c300cbeb90f0d7f3e4b562be42 Merged-In: Ida54d4369a2cb8c300cbeb90f0d7f3e4b562be42 --- .../android/systemui/ScreenDecorations.java | 46 +++++++++++++++---- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 3a8524a3ee7d..022a254ca937 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -26,8 +26,10 @@ import static com.android.systemui.tuner.TunablePadding.FLAG_END; import static com.android.systemui.tuner.TunablePadding.FLAG_START; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.annotation.Dimension; import android.annotation.NonNull; import android.app.ActivityManager; @@ -869,6 +871,8 @@ public class ScreenDecorations extends SystemUI implements Tunable, public static class DisplayCutoutView extends View implements DisplayManager.DisplayListener, RegionInterceptableView { + private static final float HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f; + private final DisplayInfo mInfo = new DisplayInfo(); private final Paint mPaint = new Paint(); private final List mBounds = new ArrayList(); @@ -888,6 +892,8 @@ public class ScreenDecorations extends SystemUI implements Tunable, private int mColor = Color.BLACK; private boolean mStart; private int mRotation; + private float mCameraProtectionProgress = HIDDEN_CAMERA_PROTECTION_SCALE; + private ValueAnimator mCameraProtectionAnimator; public DisplayCutoutView(Context context, boolean start, Runnable visibilityChangedListener, ScreenDecorations decorations) { @@ -928,17 +934,18 @@ public class ScreenDecorations extends SystemUI implements Tunable, getLocationOnScreen(mLocation); canvas.translate(-mLocation[0], -mLocation[1]); - if (mShowProtection && !mProtectionRect.isEmpty()) { - mPaint.setColor(mColor); - mPaint.setStyle(Paint.Style.FILL); - mPaint.setAntiAlias(true); - canvas.drawPath(mProtectionPath, mPaint); - } else if (!mBoundingPath.isEmpty()) { + if (!mBoundingPath.isEmpty()) { mPaint.setColor(mColor); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); canvas.drawPath(mBoundingPath, mPaint); } + if (mCameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE + && !mProtectionRect.isEmpty()) { + canvas.scale(mCameraProtectionProgress, mCameraProtectionProgress, + mProtectionRect.centerX(), mProtectionRect.centerY()); + canvas.drawPath(mProtectionPath, mPaint); + } } @Override @@ -973,8 +980,31 @@ public class ScreenDecorations extends SystemUI implements Tunable, mShowProtection = shouldShow; updateBoundingPath(); - requestLayout(); - invalidate(); + // Delay the relayout until the end of the animation when hiding the cutout, + // otherwise we'd clip it. + if (mShowProtection) { + requestLayout(); + } + if (mCameraProtectionAnimator != null) { + mCameraProtectionAnimator.cancel(); + } + mCameraProtectionAnimator = ValueAnimator.ofFloat(mCameraProtectionProgress, + mShowProtection ? 1.0f : HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750); + mCameraProtectionAnimator.setInterpolator(Interpolators.DECELERATE_QUINT); + mCameraProtectionAnimator.addUpdateListener(animation -> { + mCameraProtectionProgress = (float) animation.getAnimatedValue(); + invalidate(); + }); + mCameraProtectionAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCameraProtectionAnimator = null; + if (!mShowProtection) { + requestLayout(); + } + } + }); + mCameraProtectionAnimator.start(); } private boolean isStart() { -- GitLab From 16dfe7bfd80768bfd8228e5ea4a7119af2230edc Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 6 Mar 2020 03:35:09 +0000 Subject: [PATCH 121/143] Revert "[automerger skipped] Merge "DO NOT MERGE - Kill apps out..." Revert "DO NOT MERGE - Track framework changes to crashApplicati..." Revert "[automerger skipped] Merge "DO NOT MERGE - Add test of f..." Revert submission 10557201-am-f98a6c51a74d42d6bc57f980bd694e3e Reason for revert: Should not have been automerged from qt-dev; the whole topic should have been skipped. Reverted Changes: I01c0b570b:[automerger skipped] Merge "DO NOT MERGE - Add tes... I7451c89d1:DO NOT MERGE - Track framework changes to crashApp... Iec866858c:DO NOT MERGE - Track framework changes to crashApp... I200606752:[automerger skipped] Merge "DO NOT MERGE - Kill ap... Change-Id: Ib0ecc5fc825a7c6f38679d1818178869d6cef23e -- GitLab From a9bb977a7158b010920228f287b07e5023634951 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 6 Mar 2020 03:54:52 +0000 Subject: [PATCH 122/143] Revert "[automerger skipped] Merge "DO NOT MERGE - Kill apps out..." Revert "[automerger skipped] Merge "DO NOT MERGE - Add test of f..." Revert "DO NOT MERGE - Track framework changes to crashApplicati..." Revert submission 10556828-am-2e2e7004e4cb4ef8b776d65e9ffe33f3 Reason for revert: Should never have automerged downstream from qt-dev; the entire topic should have been skipped. Reverted Changes: I241d8d8da:DO NOT MERGE - Track framework changes to crashApp... Ib1a5695f9:[automerger skipped] Merge "DO NOT MERGE - Add tes... I3e6eb3f5c:[automerger skipped] Merge "DO NOT MERGE - Kill ap... Ibe4652916:DO NOT MERGE - Track framework changes to crashApp... Change-Id: I4d73e88c87891af1540dfd95c9e9bc3c39b11531 -- GitLab From 377838b451d53ed2e8cd9fc751e989d6ab877e18 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Fri, 6 Mar 2020 16:55:46 -0500 Subject: [PATCH 123/143] Reset protection path on rotation Fixes the issue where camera cutout protection paths were accruing rotation by not caching the unmodified path. Fixes: 150531720 Test: manual Change-Id: I0cece9900e86dc553401200346dc964c562b0ce0 --- .../android/systemui/CameraAvailabilityListener.kt | 2 +- .../src/com/android/systemui/ScreenDecorations.java | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt index 24fa91b9e838..284074e76ae2 100644 --- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt +++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt @@ -26,7 +26,7 @@ import java.util.concurrent.Executor import kotlin.math.roundToInt -const val TAG = "CameraOpTransitionController" +const val TAG = "CameraAvailabilityListener" /** * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 022a254ca937..6ea6a748ae8d 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -878,9 +878,10 @@ public class ScreenDecorations extends SystemUI implements Tunable, private final List mBounds = new ArrayList(); private final Rect mBoundingRect = new Rect(); private final Path mBoundingPath = new Path(); - // Don't initialize these because they are cached elsewhere and may not exist + // Don't initialize these yet because they may never exist private Rect mProtectionRect; private Path mProtectionPath; + private Path mProtectionPathOrig; private Rect mTotalBounds = new Rect(); // Whether or not to show the cutout protection path private boolean mShowProtection = false; @@ -969,7 +970,11 @@ public class ScreenDecorations extends SystemUI implements Tunable, } void setProtection(Path protectionPath, Rect pathBounds) { - mProtectionPath = protectionPath; + if (mProtectionPathOrig == null) { + mProtectionPathOrig = new Path(); + mProtectionPath = new Path(); + } + mProtectionPathOrig.set(protectionPath); mProtectionRect = pathBounds; } @@ -1053,7 +1058,9 @@ public class ScreenDecorations extends SystemUI implements Tunable, Matrix m = new Matrix(); transformPhysicalToLogicalCoordinates(mInfo.rotation, dw, dh, m); mBoundingPath.transform(m); - if (mProtectionPath != null) { + if (mProtectionPathOrig != null) { + // Reset the protection path so we don't aggregate rotations + mProtectionPath.set(mProtectionPathOrig); mProtectionPath.transform(m); } } -- GitLab From 7a66c7b39c50376efa042ef849fcecf7e41b2a17 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Fri, 6 Mar 2020 11:52:04 -0800 Subject: [PATCH 124/143] Do not accept NaN as scrim values Scrim values are becoming NaN and causing the status bar window to not collapse. These are inavlid values and should not be accepted. Bug: 150672579 Test: make Change-Id: I8217a0fa9a08f94b98121d6584fafab1bca88b4d Merged-In: I8217a0fa9a08f94b98121d6584fafab1bca88b4d --- .../android/systemui/statusbar/ScrimView.java | 5 ++++ .../statusbar/phone/ScrimController.java | 25 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java index 04f1c3248a6f..1524b0799084 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar; +import static java.lang.Float.isNaN; + import android.annotation.NonNull; import android.content.Context; import android.graphics.Canvas; @@ -179,6 +181,9 @@ public class ScrimView extends View { * @param alpha Gradient alpha from 0 to 1. */ public void setViewAlpha(float alpha) { + if (isNaN(alpha)) { + throw new IllegalArgumentException("alpha cannot be NaN"); + } if (alpha != mViewAlpha) { mViewAlpha = alpha; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 9019e9a3f44b..d9bb995c5da8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static java.lang.Float.isNaN; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; @@ -261,6 +263,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo mCurrentBehindTint = state.getBehindTint(); mCurrentInFrontAlpha = state.getFrontAlpha(); mCurrentBehindAlpha = state.getBehindAlpha(); + if (isNaN(mCurrentBehindAlpha) || isNaN(mCurrentInFrontAlpha)) { + throw new IllegalStateException("Scrim opacity is NaN for state: " + state + ", front: " + + mCurrentInFrontAlpha + ", back: " + mCurrentBehindAlpha); + } applyExpansionToAlpha(); // Scrim might acquire focus when user is navigating with a D-pad or a keyboard. @@ -390,6 +396,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo * @param fraction From 0 to 1 where 0 means collapsed and 1 expanded. */ public void setPanelExpansion(float fraction) { + if (isNaN(fraction)) { + throw new IllegalArgumentException("Fraction should not be NaN"); + } if (mExpansionFraction != fraction) { mExpansionFraction = fraction; @@ -464,6 +473,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo mCurrentBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(), mState.getBehindTint(), interpolatedFract); } + if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) { + throw new IllegalStateException("Scrim opacity is NaN for state: " + mState + + ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha); + } } /** @@ -523,6 +536,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo float newBehindAlpha = mState.getBehindAlpha(); if (mCurrentBehindAlpha != newBehindAlpha) { mCurrentBehindAlpha = newBehindAlpha; + if (isNaN(mCurrentBehindAlpha)) { + throw new IllegalStateException("Scrim opacity is NaN for state: " + mState + + ", back: " + mCurrentBehindAlpha); + } updateScrims(); } } @@ -903,7 +920,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo pw.print(" alpha="); pw.print(mCurrentBehindAlpha); pw.print(" tint=0x"); pw.println(Integer.toHexString(mScrimBehind.getTint())); - pw.print(" mTracking="); pw.println(mTracking); + pw.print(" mTracking="); pw.println(mTracking); + + pw.print(" mExpansionFraction="); pw.println(mExpansionFraction); } public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) { @@ -950,6 +969,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // in this case, back-scrim needs to be re-evaluated if (mState == ScrimState.AOD || mState == ScrimState.PULSING) { float newBehindAlpha = mState.getBehindAlpha(); + if (isNaN(newBehindAlpha)) { + throw new IllegalStateException("Scrim opacity is NaN for state: " + mState + + ", back: " + mCurrentBehindAlpha); + } if (mCurrentBehindAlpha != newBehindAlpha) { mCurrentBehindAlpha = newBehindAlpha; updateScrims(); -- GitLab From 12c8c244a63113612c69d4970878e6722efdaab8 Mon Sep 17 00:00:00 2001 From: Aleks Rozman Date: Sun, 8 Mar 2020 15:03:06 -0700 Subject: [PATCH 125/143] DO NOT MERGE: Resolve mBehindAlpha with mCurrentBehindAlpha fixes a build breakage, mBehindAlpha is a master thing but mCurrentBehindAlpha is a QPR1 thing BUG: 151041066 Test: Compile Change-Id: I78d767319d2ba856a9f453f71b39ddd3c96e6b9f --- .../com/android/systemui/statusbar/phone/ScrimController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index d9bb995c5da8..08ba50857fa7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -473,9 +473,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo mCurrentBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(), mState.getBehindTint(), interpolatedFract); } - if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) { + if (isNaN(mCurrentBehindAlpha) || isNaN(mCurrentInFrontAlpha)) { throw new IllegalStateException("Scrim opacity is NaN for state: " + mState - + ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha); + + ", front: " + mCurrentInFrontAlpha + ", back: " + mCurrentBehindAlpha); } } -- GitLab From 7d4adf4d46caa7695c395e3e994e1d57a94ae92c Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Tue, 4 Feb 2020 16:41:06 +0000 Subject: [PATCH 126/143] RESTRICT AUTOMERGE Block TYPE_PRESENTATION windows on default display ... and any other display that isn't considered a public presentation display, as per Display.isPublicPresentation() Bug: 141745510 Test: manual test via test app Change-Id: I2aaab1903dee54190338f7b6e49888aa51437108 --- core/java/android/app/Presentation.java | 16 +++++++++------- .../android/server/wm/WindowManagerService.java | 8 ++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index af55788e617f..bc2b250328a6 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -25,18 +25,18 @@ import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; -import android.os.Handler; -import android.os.Message; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.TypedValue; /** * Base class for presentations. @@ -115,7 +115,9 @@ import android.util.TypedValue; * The display manager keeps track of all displays in the system. However, not all * displays are appropriate for showing presentations. For example, if an activity * attempted to show a presentation on the main display it might obscure its own content - * (it's like opening a dialog on top of your activity). + * (it's like opening a dialog on top of your activity). Creating a presentation on the main + * display will result in {@link android.view.WindowManager.InvalidDisplayException} being thrown + * when invoking {@link #show()}. *

* Here's how to identify suitable displays for showing presentations using * {@link DisplayManager#getDisplays(String)} and the @@ -242,7 +244,7 @@ public class Presentation extends Dialog { /** * Inherited from {@link Dialog#show}. Will throw * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary - * {@link Display} can't be found. + * {@link Display} can't be found or if it does not have {@link Display#FLAG_PRESENTATION} set. */ @Override public void show() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5f4c99437af9..d35ad413ccef 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -58,6 +58,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; @@ -1255,6 +1256,13 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_PERMISSION_DENIED; } + if (type == TYPE_PRESENTATION && !displayContent.getDisplay().isPublicPresentation()) { + Slog.w(TAG_WM, + "Attempted to add presentation window to a non-suitable display. " + + "Aborting."); + return WindowManagerGlobal.ADD_INVALID_DISPLAY; + } + AppWindowToken atoken = null; final boolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token -- GitLab From 0bb93d4b1c05d717ed4cbf5772a6a766b5281f1e Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Tue, 4 Feb 2020 16:41:06 +0000 Subject: [PATCH 127/143] RESTRICT AUTOMERGE Block TYPE_PRESENTATION windows on default display ... and any other display that isn't considered a public presentation display, as per Display.isPublicPresentation() Bug: 141745510 Test: manual test via test app Change-Id: I2aaab1903dee54190338f7b6e49888aa51437108 --- core/java/android/app/Presentation.java | 16 +++++++++------- .../android/server/wm/WindowManagerService.java | 8 ++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index af55788e617f..bc2b250328a6 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -25,18 +25,18 @@ import android.content.res.Resources; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.Gravity; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerImpl; -import android.os.Handler; -import android.os.Message; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.TypedValue; /** * Base class for presentations. @@ -115,7 +115,9 @@ import android.util.TypedValue; * The display manager keeps track of all displays in the system. However, not all * displays are appropriate for showing presentations. For example, if an activity * attempted to show a presentation on the main display it might obscure its own content - * (it's like opening a dialog on top of your activity). + * (it's like opening a dialog on top of your activity). Creating a presentation on the main + * display will result in {@link android.view.WindowManager.InvalidDisplayException} being thrown + * when invoking {@link #show()}. *

* Here's how to identify suitable displays for showing presentations using * {@link DisplayManager#getDisplays(String)} and the @@ -242,7 +244,7 @@ public class Presentation extends Dialog { /** * Inherited from {@link Dialog#show}. Will throw * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary - * {@link Display} can't be found. + * {@link Display} can't be found or if it does not have {@link Display#FLAG_PRESENTATION} set. */ @Override public void show() { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8439669a2147..361c116b67f6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -56,6 +56,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; @@ -1227,6 +1228,13 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_PERMISSION_DENIED; } + if (type == TYPE_PRESENTATION && !displayContent.getDisplay().isPublicPresentation()) { + Slog.w(TAG_WM, + "Attempted to add presentation window to a non-suitable display. " + + "Aborting."); + return WindowManagerGlobal.ADD_INVALID_DISPLAY; + } + AppWindowToken atoken = null; final boolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token -- GitLab From ae242892e2ba416cfbf5fd707069faf2350ace9c Mon Sep 17 00:00:00 2001 From: Beverly Date: Mon, 9 Mar 2020 16:07:56 -0400 Subject: [PATCH 128/143] DO NOT MERGE Ignore insets on status_bar_container - Instead, PhoneStatusBarView will take care of display cutout insets based on the rotation of the device Test: atest SystemUITests Bug: 149197103 Change-Id: Ie4df9ce5c754408dcf2d50108576df42173fa17d --- .../SystemUI/res/layout/super_status_bar.xml | 3 +- .../statusbar/phone/PhoneStatusBarView.java | 50 +++++++++++++++---- .../statusbar/phone/StatusBarWindowView.java | 3 +- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index 9d56e08bc555..d68bd5d442ed 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -55,7 +55,8 @@ android:id="@+id/status_bar_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/system_bar_background" /> + android:background="@drawable/system_bar_background" + sysui:ignoreRightInset="true" /> cornerCutoutMargins = cornerCutoutMargins(mDisplayCutout, - getDisplay()); + getDisplay(), mRotationOrientation, mStatusBarHeight); updateCutoutLocation(cornerCutoutMargins); updateSafeInsets(cornerCutoutMargins); } @@ -332,15 +336,13 @@ public class PhoneStatusBarView extends PanelBar { // or letterboxing from the right or left sides. FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - if (mDisplayCutout == null || mDisplayCutout.isEmpty() - || mLastOrientation != ORIENTATION_PORTRAIT || cornerCutoutMargins == null) { + if (mDisplayCutout == null || mDisplayCutout.isEmpty() || cornerCutoutMargins == null) { lp.leftMargin = 0; lp.rightMargin = 0; return; } - - lp.leftMargin = Math.max(lp.leftMargin, cornerCutoutMargins.first); - lp.rightMargin = Math.max(lp.rightMargin, cornerCutoutMargins.second); + lp.leftMargin = cornerCutoutMargins.first; + lp.rightMargin = cornerCutoutMargins.second; // If we're already inset enough (e.g. on the status bar side), we can have 0 margin WindowInsets insets = getRootWindowInsets(); @@ -354,8 +356,19 @@ public class PhoneStatusBarView extends PanelBar { } } + /** + * Returns a Pair of integers where + * - Pair.first is the left margin inset + * - Pair.second is the right margin inset + * This method always assumes the cutout is on the top when the device is in portrait mode. + */ public static Pair cornerCutoutMargins(DisplayCutout cutout, Display display) { + return cornerCutoutMargins(cutout, display, RotationUtils.ROTATION_NONE, -1); + } + + private static Pair cornerCutoutMargins(DisplayCutout cutout, + Display display, int rotationOrientation, int statusBarHeight) { if (cutout == null) { return null; } @@ -363,14 +376,33 @@ public class PhoneStatusBarView extends PanelBar { display.getRealSize(size); Rect bounds = new Rect(); - boundsFromDirection(cutout, Gravity.TOP, bounds); + switch (rotationOrientation) { + case RotationUtils.ROTATION_LANDSCAPE: + boundsFromDirection(cutout, Gravity.LEFT, bounds); + break; + case RotationUtils.ROTATION_SEASCAPE: + boundsFromDirection(cutout, Gravity.RIGHT, bounds); + break; + case RotationUtils.ROTATION_NONE: + boundsFromDirection(cutout, Gravity.TOP, bounds); + break; + case RotationUtils.ROTATION_UPSIDE_DOWN: + // we assume the cutout is always on top in portrait mode + return null; + } + + if (statusBarHeight >= 0 && bounds.top > statusBarHeight) { + return null; + } if (bounds.left <= 0) { return new Pair<>(bounds.right, 0); } + if (bounds.right >= size.x) { return new Pair<>(0, size.x - bounds.left); } + return null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 0ab2af864383..459e0da0b067 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -180,7 +180,8 @@ public class StatusBarWindowView extends FrameLayout { int targetLeft = Math.max(insets.left, leftCutout); int targetRight = Math.max(insets.right, rightCutout); - // Super-special right inset handling, because scrims and backdrop need to ignore it. + // Super-special right inset handling, because scrims, backdrop and status bar + // container need to ignore it. if (targetRight != mRightInset || targetLeft != mLeftInset) { mRightInset = targetRight; mLeftInset = targetLeft; -- GitLab From 447394f90871f10f58ac423004bd01a5d44079d0 Mon Sep 17 00:00:00 2001 From: Beverly Date: Mon, 9 Mar 2020 12:24:06 -0400 Subject: [PATCH 129/143] DO NOT MERGE Add null check for status bar transitions Test: atest SystemUITests Bug: 150570478 Change-Id: I4c93a08ddcbe35a95b77012e2345bfa25167be1b --- .../src/com/android/systemui/statusbar/phone/StatusBar.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 7e6d11b77f64..cc691ae2d9be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -2277,8 +2277,10 @@ public class StatusBar extends SystemUI implements DemoMode, void checkBarModes() { if (mDemoMode) return; - if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState, - getStatusBarTransitions()); + if (mStatusBarView != null && getStatusBarTransitions() != null) { + checkBarMode(mStatusBarMode, mStatusBarWindowState, + getStatusBarTransitions()); + } mNavigationBarController.checkNavBarModes(mDisplayId); mNoAnimationOnNextBarModeChange = false; } -- GitLab From 973ecc619c0bb87a03481774ea9e86d2924601e4 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Sat, 22 Feb 2020 23:20:41 +0800 Subject: [PATCH 130/143] RESTRICT AUTOMERGE Create separated tasks for different apps from startActivities Assume there are 2 applications A, B with different uids. There are 4 activities A1, A2, B1, B2 with default task affinity and launch mode. After A1 called startActivities(B1, A2, B2): Original : Task(A1, B1, A2, B2) This Change: Task(A1, B1), Task(A2, B2) In other words, the source caller cannot launch its activity above the activity of other application in the same task, and it can still launch activity of other application in its task. Bug: 145669109 Test: run cts --test android.server.cts.StartActivityTests \ -m CtsServicesHostTestCases Change-Id: I97bd875146a52f62b8fe82235487ccefb2955e8e --- .../com/android/server/am/ActivityStarter.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index fa2e04f70a30..aec552d3e145 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -940,6 +940,8 @@ class ActivityStarter { } else { callingPid = callingUid = -1; } + boolean forceNewTask = false; + final int filterCallingUid = callingUid >= 0 ? callingUid : realCallingUid; final long origId = Binder.clearCallingIdentity(); try { synchronized (mService) { @@ -959,6 +961,9 @@ class ActivityStarter { // Don't modify the client's object! intent = new Intent(intent); + if (forceNewTask) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } // Collect information about the target of the Intent. ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0, @@ -984,7 +989,17 @@ class ActivityStarter { return res; } - resultTo = outActivity[0] != null ? outActivity[0].appToken : null; + final ActivityRecord started = outActivity[0]; + if (started != null && started.getUid() == filterCallingUid) { + // Only the started activity which has the same uid as the source caller can + // be the caller of next activity. + resultTo = started.appToken; + forceNewTask = false; + } else { + // Different apps not adjacent to the caller are forced to be new task. + resultTo = null; + forceNewTask = true; + } } } } finally { -- GitLab From e375ee8f8a4e767040cfbef1ead28623b3e986e0 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Fri, 6 Mar 2020 11:38:21 -0800 Subject: [PATCH 131/143] Camera: Add new hidden API for camera open/close callback The hidden API is used by SystemUI process to adjust the system UI based on when a certain camera is opened or closed. Test: Manually observe callbacks in SystemUI when running camera CTS Bug: 150540299 Change-Id: I04cae782d96f0e32be8ef588dcd328f84b32887a Merged-In: I04cae782d96f0e32be8ef588dcd328f84b32887a --- .../hardware/camera2/CameraManager.java | 85 +++++++++++++++++++ core/res/AndroidManifest.xml | 8 ++ core/res/res/values/strings.xml | 5 ++ data/etc/com.android.systemui.xml | 1 + .../integration/CameraBinderTest.java | 9 ++ packages/SystemUI/AndroidManifest.xml | 1 + 6 files changed, 109 insertions(+) diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index c8276b25c52d..13f2a5ebc785 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -701,6 +701,33 @@ public final class CameraManager { public void onCameraAccessPrioritiesChanged() { // default empty implementation } + + /** + * A camera device has been opened by an application. + * + *

The default implementation of this method does nothing.

+ * + * @param cameraId The unique identifier of the new camera. + * @param packageId The package Id of the application opening the camera. + * + * @see #onCameraClosed + */ + /** @hide */ + public void onCameraOpened(@NonNull String cameraId, @NonNull String packageId) { + // default empty implementation + } + + /** + * A previously-opened camera has been closed. + * + *

The default implementation of this method does nothing.

+ * + * @param cameraId The unique identifier of the closed camera. + */ + /** @hide */ + public void onCameraClosed(@NonNull String cameraId) { + // default empty implementation + } } /** @@ -1139,6 +1166,38 @@ public final class CameraManager { } } + private void postSingleCameraOpenedUpdate(final AvailabilityCallback callback, + final Executor executor, final String id, final String packageId) { + final long ident = Binder.clearCallingIdentity(); + try { + executor.execute( + new Runnable() { + @Override + public void run() { + callback.onCameraOpened(id, packageId); + } + }); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void postSingleCameraClosedUpdate(final AvailabilityCallback callback, + final Executor executor, final String id) { + final long ident = Binder.clearCallingIdentity(); + try { + executor.execute( + new Runnable() { + @Override + public void run() { + callback.onCameraClosed(id); + } + }); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor, final String id, final int status) { if (isAvailable(status)) { @@ -1401,6 +1460,32 @@ public final class CameraManager { } } + @Override + public void onCameraOpened(String cameraId, String clientPackageId) { + synchronized (mLock) { + final int callbackCount = mCallbackMap.size(); + for (int i = 0; i < callbackCount; i++) { + Executor executor = mCallbackMap.valueAt(i); + final AvailabilityCallback callback = mCallbackMap.keyAt(i); + + postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId); + } + } + } + + @Override + public void onCameraClosed(String cameraId) { + synchronized (mLock) { + final int callbackCount = mCallbackMap.size(); + for (int i = 0; i < callbackCount; i++) { + Executor executor = mCallbackMap.valueAt(i); + final AvailabilityCallback callback = mCallbackMap.keyAt(i); + + postSingleCameraClosedUpdate(callback, executor, cameraId); + } + } + } + /** * Try to connect to camera service after some delay if any client registered camera * availability callback or torch status callback. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 5778d02737b9..7b95d92ce1d6 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1267,6 +1267,14 @@ android:description="@string/permdesc_camera" android:protectionLevel="dangerous|instant" /> + + diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 5d5729b412be..044e07420c2d 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1151,6 +1151,11 @@ This app can take pictures and record videos using the camera at any time. + + Allow an application or service to receive callbacks about camera devices being opened or closed. + + This signature app can receive callbacks when any camera device is being opened (by what application package) or closed. + control vibration diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index a305d48c4633..2f5b5f3bf7b4 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -60,5 +60,6 @@ + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index 87a59df19e8e..0889192099df 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -313,6 +313,15 @@ public class CameraBinderTest extends AndroidTestCase { public void onCameraAccessPrioritiesChanged() { Log.v(TAG, "Camera access permission change"); } + @Override + public void onCameraOpened(String cameraId, String clientPackageName) { + Log.v(TAG, String.format("Camera %s is opened by client package %s", + cameraId, clientPackageName)); + } + @Override + public void onCameraClosed(String cameraId) { + Log.v(TAG, String.format("Camera %s is closed", cameraId)); + } } /** diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 862abfda6a65..20b61f966d2d 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -151,6 +151,7 @@ + -- GitLab From ace57ca0dfdbb2d4af52370628a3a63575355ad2 Mon Sep 17 00:00:00 2001 From: Govinda Wasserman Date: Thu, 5 Mar 2020 17:01:21 -0500 Subject: [PATCH 132/143] [DO NOT MERGE] Allows the Assistant to request suppression of fling Test: Tested locally BUG: 150688842 Change-Id: I8e8b2ccb87d9ff48d5a287f12ca9a6a2240a2cdb --- .../shared/system/QuickStepContract.java | 5 ++++ .../systemui/assist/AssistManager.java | 25 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 08996c38baf6..cfefe0c3c0fd 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -85,6 +85,9 @@ public class QuickStepContract { // The notification panel is expanded and interactive (either locked or unlocked), and the // quick settings is not expanded public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11; + // The Assistant gesture should be constrained. It is up to the launcher implementation to + // decide how to constrain it + public static final int SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1 << 12; @Retention(RetentionPolicy.SOURCE) @IntDef({SYSUI_STATE_SCREEN_PINNING, @@ -117,6 +120,8 @@ public class QuickStepContract { str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : ""); str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : ""); str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : ""); + str.add((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0 + ? "asst_gesture_constrain" : ""); return str.toString(); } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 74b4f9537b87..d2c5f1e91ea7 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -1,5 +1,9 @@ package com.android.systemui.assist; +import static android.view.Display.DEFAULT_DISPLAY; + +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -39,7 +43,6 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.settingslib.applications.InterestingConfigChanges; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.ui.DefaultUiController; @@ -103,6 +106,9 @@ public class AssistManager { public static final String INVOCATION_TYPE_KEY = "invocation_type"; protected static final String ACTION_KEY = "action"; protected static final String SHOW_ASSIST_HANDLES_ACTION = "show_assist_handles"; + protected static final String SET_ASSIST_GESTURE_CONSTRAINED_ACTION = + "set_assist_gesture_constrained"; + protected static final String CONSTRAINED_KEY = "should_constrain"; public static final int INVOCATION_TYPE_GESTURE = 1; public static final int INVOCATION_TYPE_ACTIVE_EDGE = 2; @@ -125,6 +131,7 @@ public class AssistManager { private final PhoneStateMonitor mPhoneStateMonitor; private final AssistHandleBehaviorController mHandleController; private final UiController mUiController; + protected final OverviewProxyService mOverviewProxyService; private AssistOrbContainer mView; private final DeviceProvisionedController mDeviceProvisionedController; @@ -186,7 +193,8 @@ public class AssistManager { Context context, AssistUtils assistUtils, AssistHandleBehaviorController handleController, - ConfigurationController configurationController) { + ConfigurationController configurationController, + OverviewProxyService overviewProxyService) { mContext = context; mDeviceProvisionedController = controller; mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); @@ -206,8 +214,8 @@ public class AssistManager { mUiController = new DefaultUiController(mContext); - OverviewProxyService overviewProxy = Dependency.get(OverviewProxyService.class); - overviewProxy.addCallback(new OverviewProxyService.OverviewProxyListener() { + mOverviewProxyService = overviewProxyService; + mOverviewProxyService.addCallback(new OverviewProxyService.OverviewProxyListener() { @Override public void onAssistantProgress(float progress) { // Progress goes from 0 to 1 to indicate how close the assist gesture is to @@ -244,8 +252,15 @@ public class AssistManager { if (VERBOSE) { Log.v(TAG, "UI hints received"); } - if (SHOW_ASSIST_HANDLES_ACTION.equals(hints.getString(ACTION_KEY))) { + + String action = hints.getString(ACTION_KEY); + if (SHOW_ASSIST_HANDLES_ACTION.equals(action)) { requestAssistHandles(); + } else if (SET_ASSIST_GESTURE_CONSTRAINED_ACTION.equals(action)) { + mOverviewProxyService.setSystemUiStateFlag( + SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED, + hints.getBoolean(CONSTRAINED_KEY, false), + DEFAULT_DISPLAY); } } }); -- GitLab From 7890462180ec409a9c5e4845685304e8690378af Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 10 Mar 2020 14:13:02 -0700 Subject: [PATCH 133/143] Properly rotate cutout protection rect Test: visual Fixes: 151054867 Change-Id: I4840e7650b30d9ce6f73c0e2ea0d0b3b47222fb4 --- .../com/android/systemui/ScreenDecorations.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index 6ea6a748ae8d..e0a9bb166fb2 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -48,6 +48,7 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.Region; import android.graphics.drawable.VectorDrawable; import android.hardware.display.DisplayManager; @@ -879,7 +880,8 @@ public class ScreenDecorations extends SystemUI implements Tunable, private final Rect mBoundingRect = new Rect(); private final Path mBoundingPath = new Path(); // Don't initialize these yet because they may never exist - private Rect mProtectionRect; + private RectF mProtectionRect; + private RectF mProtectionRectOrig; private Path mProtectionPath; private Path mProtectionPathOrig; private Rect mTotalBounds = new Rect(); @@ -975,7 +977,11 @@ public class ScreenDecorations extends SystemUI implements Tunable, mProtectionPath = new Path(); } mProtectionPathOrig.set(protectionPath); - mProtectionRect = pathBounds; + if (mProtectionRectOrig == null) { + mProtectionRectOrig = new RectF(); + mProtectionRect = new RectF(); + } + mProtectionRectOrig.set(pathBounds); } void setShowProtection(boolean shouldShow) { @@ -1062,6 +1068,7 @@ public class ScreenDecorations extends SystemUI implements Tunable, // Reset the protection path so we don't aggregate rotations mProtectionPath.set(mProtectionPathOrig); mProtectionPath.transform(m); + m.mapRect(mProtectionRect, mProtectionRectOrig); } } @@ -1124,7 +1131,8 @@ public class ScreenDecorations extends SystemUI implements Tunable, if (mShowProtection) { // Make sure that our measured height encompases the protection mTotalBounds.union(mBoundingRect); - mTotalBounds.union(mProtectionRect); + mTotalBounds.union((int) mProtectionRect.left, (int) mProtectionRect.top, + (int) mProtectionRect.right, (int) mProtectionRect.bottom); setMeasuredDimension( resolveSizeAndState(mTotalBounds.width(), widthMeasureSpec, 0), resolveSizeAndState(mTotalBounds.height(), heightMeasureSpec, 0)); -- GitLab From 45a53e6cb8d3276126cfe0e717ad7ed486d39b24 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Mon, 19 Aug 2019 16:16:20 -0700 Subject: [PATCH 134/143] DO NOT MERGE - Kill apps outright for API contract violations ...rather than relying on in-app code to perform the shutdown. Bug: 128649910 Bug: 140108616 Test: manual Test: atest OsHostTests#testForegroundServiceBadNotification Change-Id: I94d9de50bb03c33666471e3dbd9c721e9278f7cb Merged-In: I94d9de50bb03c33666471e3dbd9c721e9278f7cb --- core/java/android/app/IActivityManager.aidl | 3 ++- .../com/android/server/am/ActiveServices.java | 11 +++++++- .../server/am/ActivityManagerService.java | 5 ++-- .../am/ActivityManagerShellCommand.java | 2 +- .../java/com/android/server/am/AppErrors.java | 26 ++++++++++++++----- .../com/android/server/am/ServiceRecord.java | 7 +++-- .../NotificationManagerService.java | 2 +- 7 files changed, 39 insertions(+), 17 deletions(-) diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 48ca71690a1b..c0c63555b10a 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -287,7 +287,8 @@ interface IActivityManager { void handleApplicationStrictModeViolation(in IBinder app, int penaltyMask, in StrictMode.ViolationInfo crashInfo); boolean isTopActivityImmersive(); - void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message); + void crashApplication(int uid, int initialPid, in String packageName, int userId, + in String message, boolean force); @UnsupportedAppUsage String getProviderMimeType(in Uri uri, int userId); // Cause the specified process to dump the specified heap. diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 7bc2e6d647be..5d72828964c7 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -829,6 +829,15 @@ public final class ActiveServices { } } + void killMisbehavingService(ServiceRecord r, + int appUid, int appPid, String localPackageName) { + synchronized (mAm) { + stopServiceLocked(r); + mAm.crashApplication(appUid, appPid, localPackageName, -1, + "Bad notification for startForeground", true /*force*/); + } + } + IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) { ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), @@ -3918,7 +3927,7 @@ public final class ActiveServices { void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) { mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId, "Context.startForegroundService() did not then call Service.startForeground(): " - + serviceRecord); + + serviceRecord, false /*force*/); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f9d13c286093..67bb1c0268d4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3568,7 +3568,7 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void crashApplication(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: crashApplication() from pid=" @@ -3580,7 +3580,8 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message); + mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, + message, force); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 26b3f435dea1..9f3a7e93a433 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -1051,7 +1051,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } catch (NumberFormatException e) { packageName = arg; } - mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash"); + mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash", false); return 0; } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index a4c695067139..bbd2d34e92a6 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -314,20 +314,24 @@ class AppErrors { } void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) { - app.setCrashing(false); - app.crashingReport = null; - app.setNotResponding(false); - app.notRespondingReport = null; if (app.anrDialog == fromDialog) { app.anrDialog = null; } if (app.waitDialog == fromDialog) { app.waitDialog = null; } + killAppImmediateLocked(app, "user-terminated", "user request after error"); + } + + private void killAppImmediateLocked(ProcessRecord app, String reason, String killReason) { + app.setCrashing(false); + app.crashingReport = null; + app.setNotResponding(false); + app.notRespondingReport = null; if (app.pid > 0 && app.pid != MY_PID) { - handleAppCrashLocked(app, "user-terminated" /*reason*/, + handleAppCrashLocked(app, reason, null /*shortMsg*/, null /*longMsg*/, null /*stackTrace*/, null /*data*/); - app.kill("user request after error", true); + app.kill(killReason, true); } } @@ -341,7 +345,7 @@ class AppErrors { * @param message */ void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, - String message) { + String message, boolean force) { ProcessRecord proc = null; // Figure out which process to kill. We don't trust that initialPid @@ -374,6 +378,14 @@ class AppErrors { } proc.scheduleCrash(message); + if (force) { + // If the app is responsive, the scheduled crash will happen as expected + // and then the delayed summary kill will be a no-op. + final ProcessRecord p = proc; + mService.mHandler.postDelayed( + () -> killAppImmediateLocked(p, "forced", "killed for invalid state"), + 5000L); + } } /** diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index dee8e3b285a7..c408695bcb66 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -798,6 +798,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN final String localPackageName = packageName; final int localForegroundId = foregroundId; final Notification _foregroundNoti = foregroundNoti; + final ServiceRecord record = this; ams.mHandler.post(new Runnable() { public void run() { NotificationManagerInternal nm = LocalServices.getService( @@ -896,10 +897,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN Slog.w(TAG, "Error showing notification for service", e); // If it gave us a garbage notification, it doesn't // get to be foreground. - ams.setServiceForeground(instanceName, ServiceRecord.this, - 0, null, 0, 0); - ams.crashApplication(appUid, appPid, localPackageName, -1, - "Bad notification for startForeground: " + e); + ams.mServices.killMisbehavingService(record, + appUid, appPid, localPackageName); } } }); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 09a79433cb5c..47ed7f54e1b0 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -920,7 +920,7 @@ public class NotificationManagerService extends SystemService { () -> mAm.crashApplication(uid, initialPid, pkg, -1, "Bad notification(tag=" + tag + ", id=" + id + ") posted from package " + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): " - + message)); + + message, true /* force */)); } } -- GitLab From 931583291316957774205d7d4403988d4818be35 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Tue, 10 Mar 2020 14:16:56 -0400 Subject: [PATCH 135/143] DO NOT MERGE: Allow corner UI to decouple from rounded_corner_radius frameworks/base/core/res/res/dimens value rounded_corner_radius can change not to reflect the actual device size due to tuning the rounding on window corners. This change allows us to decouple corner UI's idea of what the corner size is from the framework dimension Test: manual Change-Id: I6548d74921d6e71250486984869572bdd304b0d0 --- packages/SystemUI/res/values/dimens.xml | 5 +++++ .../src/com/android/systemui/CornerHandleView.java | 6 +++--- .../com/android/systemui/assist/ui/DisplayUtils.java | 12 ++++++------ .../assist/ui/PathSpecCornerPathRenderer.java | 4 ++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 2e1799168b5d..0263329dbe8e 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1156,4 +1156,9 @@ 10sp + + + @*android:dimen/rounded_corner_radius + @*android:dimen/rounded_corner_radius_top + @*android:dimen/rounded_corner_radius_top diff --git a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java index a94952c5bc19..6606c8235def 100644 --- a/packages/SystemUI/src/com/android/systemui/CornerHandleView.java +++ b/packages/SystemUI/src/com/android/systemui/CornerHandleView.java @@ -152,14 +152,14 @@ public class CornerHandleView extends View { // Attempt to get the bottom corner radius, otherwise fall back on the generic or top // values. If none are available, use the FALLBACK_RADIUS_DP. int radius = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.rounded_corner_radius_bottom); + com.android.systemui.R.dimen.config_rounded_mask_size_bottom); if (radius == 0) { radius = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.rounded_corner_radius); + com.android.systemui.R.dimen.config_rounded_mask_size); } if (radius == 0) { radius = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.rounded_corner_radius_top); + com.android.systemui.R.dimen.config_rounded_mask_size_top); } if (radius == 0) { radius = (int) convertDpToPixel(FALLBACK_RADIUS_DP, mContext); diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DisplayUtils.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DisplayUtils.java index 251229f42da3..33e6ca49ddd5 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/DisplayUtils.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DisplayUtils.java @@ -84,8 +84,8 @@ public class DisplayUtils { public static int getCornerRadiusBottom(Context context) { int radius = 0; - int resourceId = context.getResources().getIdentifier("rounded_corner_radius_bottom", - "dimen", "android"); + int resourceId = context.getResources().getIdentifier("config_rounded_mask_size_bottom", + "dimen", "com.android.systemui"); if (resourceId > 0) { radius = context.getResources().getDimensionPixelSize(resourceId); } @@ -103,8 +103,8 @@ public class DisplayUtils { public static int getCornerRadiusTop(Context context) { int radius = 0; - int resourceId = context.getResources().getIdentifier("rounded_corner_radius_top", - "dimen", "android"); + int resourceId = context.getResources().getIdentifier("config_rounded_mask_size_top", + "dimen", "com.android.systemui"); if (resourceId > 0) { radius = context.getResources().getDimensionPixelSize(resourceId); } @@ -118,8 +118,8 @@ public class DisplayUtils { private static int getCornerRadiusDefault(Context context) { int radius = 0; - int resourceId = context.getResources().getIdentifier("rounded_corner_radius", "dimen", - "android"); + int resourceId = context.getResources().getIdentifier("config_rounded_mask_size", + "dimen", "com.android.systemui"); if (resourceId > 0) { radius = context.getResources().getDimensionPixelSize(resourceId); } diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java b/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java index 2bad7fc9583a..523378e97c94 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java @@ -45,8 +45,8 @@ public final class PathSpecCornerPathRenderer extends CornerPathRenderer { mWidth = DisplayUtils.getWidth(context); mHeight = DisplayUtils.getHeight(context); - mBottomCornerRadius = DisplayUtils.getCornerRadiusBottom(context); - mTopCornerRadius = DisplayUtils.getCornerRadiusTop(context); + mBottomCornerRadius = DisplayUtils.getCornerRadiusBottom(context); + mTopCornerRadius = DisplayUtils.getCornerRadiusTop(context); String pathData = context.getResources().getString(R.string.config_rounded_mask); Path path = PathParser.createPathFromPathData(pathData); -- GitLab From 1c9bf5cc54d0b32d8f3046c452e710b017c477c0 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 3 Mar 2020 14:36:21 +0800 Subject: [PATCH 136/143] RESTRICT AUTOMERGE Use consistent calling uid and package in navigateUpTo Originally, if the caller of navigateUpTo is alive, even the calling uid is set to the caller who launched the existing destination activity, the uid from caller process has higher priority to replace the given calling uid. So this change doesn't modify the existing behavior if the caller process is valid. Besides, the case of delivering new intent uses the source record as calling identity too, so the case of starting new activity should be consistent. Also forbid attaching null application thread to avoid unexpected state in process record. Bug: 144285917 Test: bit FrameworksServicesTests:ActivityStackTests Test: bit CtsSecurityTestCases:ActivityManagerTest# \ testActivityManager_attachNullApplication Merged-In: I60732f430256d37cb926d08d093581f051c4afed Change-Id: I60732f430256d37cb926d08d093581f051c4afed --- .../android/server/am/ActivityManagerService.java | 5 ++++- .../java/com/android/server/am/ActivityStack.java | 13 +++++++++---- .../com/android/server/am/ActivityStackTests.java | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 348a0376e08c..e0ac45adb3f4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6722,7 +6722,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - private final boolean attachApplicationLocked(IApplicationThread thread, + private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid) { // Find the application record that is being attached... either via @@ -7027,6 +7027,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public final void attachApplication(IApplicationThread thread) { + if (thread == null) { + throw new SecurityException("Invalid application interface"); + } synchronized (this) { int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index bde317a163db..a65a59465166 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3853,6 +3853,11 @@ class ActivityStack extends ConfigurationContai final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode, Intent resultData) { + if (srec.app == null || srec.app.thread == null) { + // Nothing to do if the caller is not attached, because this method should be called + // from an alive activity. + return false; + } final TaskRecord task = srec.getTask(); final ArrayList activities = task.mActivities; final int start = activities.indexOf(srec); @@ -3904,22 +3909,22 @@ class ActivityStack extends ConfigurationContai } if (parent != null && foundParentInTask) { + final int callingUid = srec.info.applicationInfo.uid; final int parentLaunchMode = parent.info.launchMode; final int destIntentFlags = destIntent.getFlags(); if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(srec.info.applicationInfo.uid, destIntent, - srec.packageName); + parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); } else { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( destIntent.getComponent(), 0, srec.userId); int res = mService.mActivityStarter.startActivityLocked(srec.app.thread, destIntent, null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null, - null, parent.appToken, null, 0, -1, parent.launchedFromUid, - parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null, + null, parent.appToken, null, 0, -1, callingUid, + srec.packageName, -1, callingUid, 0, null, false, true, null, null, null, "navigateUpTo"); foundParentInTask = res == ActivityManager.START_SUCCESS; } catch (RemoteException e) { diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index 711c36b8b1d4..bdd89da1df88 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -17,6 +17,7 @@ package com.android.server.am; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -119,4 +120,17 @@ public class ActivityStackTests extends ActivityTestsBase { assertEquals(ActivityStack.STACK_VISIBLE_ACTIVITY_BEHIND, fullscreenWorkspaceStackId.shouldBeVisible(null /*starting*/)); } + + @Test + public void testNavigateUpTo() { + final ActivityManagerService service = createActivityManagerService(); + final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID); + final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task); + activityRecord.app = new ProcessRecord(null, activityRecord.appInfo, + activityRecord.processName, activityRecord.getUid()); + final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID); + // No-op if the source activity record doesn't have attached process (app.thread == null). + assertFalse(testStack.navigateUpToLocked(activityRecord, activityRecord.intent, + 0 /* resultCode */, null /* resultData */)); + } } -- GitLab From 2263309459abe979774735bf3fe5ca53f65fa96a Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Wed, 11 Mar 2020 16:37:28 -0700 Subject: [PATCH 137/143] Either reuse sensor values or don't dim down at all ALS latency is unpredictable and sometimes debounced. This means that it might take at least 3 seconds for the display to wake-up, if it wakes-up at all. We might also get stuck and never show HUNs if the event doesn't arrive. This is a bug that we had in the past, but was not as noticeable because the padlock was below the scrims, now, users are reporting that the padlock shows up, but the hun is not. Test: manual Fixes: 150852696 Change-Id: Iade5ebd4c33e7c9d668b09144964f1408ef529ad Merged-In: Iade5ebd4c33e7c9d668b09144964f1408ef529ad --- .../systemui/doze/DozeScreenBrightness.java | 11 +---- .../doze/DozeScreenBrightnessTest.java | 42 ------------------- 2 files changed, 2 insertions(+), 51 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index c27e633f2a96..1145501f4c51 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -155,15 +155,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } int scrimOpacity = -1; - if (mPaused || mScreenOff) { - // If AOD is paused, force the screen black until the - // sensor reports a new brightness. This ensures that when the screen comes on - // again, it will only show after the brightness sensor has stabilized, - // avoiding a potential flicker. - scrimOpacity = 255; - } else if (!mScreenOff && mLightSensor == null) { - // No light sensor but previous state turned the screen black. Make the scrim - // transparent and below views visible. + if (mLightSensor == null) { + // No light sensor, scrims are always transparent. scrimOpacity = 0; } else if (brightnessReady) { // Only unblank scrim once brightness is ready. diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index 3b760e31b4ac..0e8dffd57079 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -220,48 +220,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { assertEquals(10/255f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); } - @Test - public void pausingAod_softBlanks() throws Exception { - mScreen.transitionTo(UNINITIALIZED, INITIALIZED); - mScreen.transitionTo(INITIALIZED, DOZE_AOD); - - mSensor.sendSensorEvent(2); - - mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING); - mScreen.transitionTo(DOZE_AOD_PAUSING, DOZE_AOD_PAUSED); - - assertEquals(1f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); - - mSensor.sendSensorEvent(0); - assertEquals(1f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); - - mScreen.transitionTo(DOZE_AOD_PAUSED, DOZE_AOD); - assertEquals(1f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); - } - - @Test - public void pausingAod_softBlanks_withSpuriousSensorDuringPause() throws Exception { - mScreen.transitionTo(UNINITIALIZED, INITIALIZED); - mScreen.transitionTo(INITIALIZED, DOZE_AOD); - mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING); - mScreen.transitionTo(DOZE_AOD_PAUSING, DOZE_AOD_PAUSED); - - mSensor.sendSensorEvent(1); - assertEquals(1f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); - } - - @Test - public void screenOff_softBlanks() throws Exception { - mScreen.transitionTo(UNINITIALIZED, INITIALIZED); - mScreen.transitionTo(INITIALIZED, DOZE_AOD); - mScreen.transitionTo(DOZE_AOD, DOZE); - assertEquals(1f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); - - mScreen.transitionTo(DOZE, DOZE_AOD); - mSensor.sendSensorEvent(2); - assertEquals(0f, mHostFake.aodDimmingScrimOpacity, 0.001f /* delta */); - } - @Test public void pausingAod_unblanksAfterSensor() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); -- GitLab From b6cd9c2003d258e1f60a839d22720f442e150d52 Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Mon, 24 Feb 2020 11:51:43 +0800 Subject: [PATCH 138/143] Fix race condition while WallpaperMS rebinding service. Connection object could not receive onServiceConnected after new process of the service was active. How issue happen: 1. The process of wallpaper service died, AM schedule to restart, WallpaperMS schedule to rebind. 2. WallpaperMS bind service with new connection object. => ActiveService bring up new process. Add this ServiceRecord to mPendingServices. 3. WallpaperMS unbind previous connection object. => ActiveService remove previous connection, also remove this ServiceRecord object from mPendingServices list. 4. Process ready, attach application but cannot find the service from pendingServices. Solution: Do not remove the ServiceRecord object from mPendingServices if there is any connection left. Also use runnable object instead of method reference. Bug: 148834472 Test: atest WallpaperManagerTest WallpaperManagerServiceTests Change-Id: I3adec66de8ac0c7efc9ad3ffbf604b01eacb5720 Merged-In: I3adec66de8ac0c7efc9ad3ffbf604b01eacb5720 (cherry picked from commit d1551333823f4e86ec0e19b65c4faafeb617f87b) --- .../core/java/com/android/server/am/ActiveServices.java | 7 +++++-- .../android/server/wallpaper/WallpaperManagerService.java | 8 ++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 5d72828964c7..f03d9df6ed5f 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3159,8 +3159,11 @@ public final class ActiveServices { } } - // If unbound while waiting to start, remove the pending service - mPendingServices.remove(s); + // If unbound while waiting to start and there is no connection left in this service, + // remove the pending service + if (s.getConnections().isEmpty()) { + mPendingServices.remove(s); + } if ((c.flags&Context.BIND_AUTO_CREATE) != 0) { boolean hasAutoCreate = s.hasAutoCreateConnections(); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 4e136af0fdc3..0e2f0ce991c7 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1180,6 +1180,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } }; + private Runnable mTryToRebindRunnable = () -> { + tryToRebind(); + }; + WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) { mInfo = info; mWallpaper = wallpaper; @@ -1286,7 +1290,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub saveSettingsLocked(mWallpaper.userId); } FgThread.getHandler().removeCallbacks(mResetRunnable); - mContext.getMainThreadHandler().removeCallbacks(this::tryToRebind); + mContext.getMainThreadHandler().removeCallbacks(mTryToRebindRunnable); } } } @@ -1344,7 +1348,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub < WALLPAPER_RECONNECT_TIMEOUT_MS) { // Bind fail without timeout, schedule rebind Slog.w(TAG, "Rebind fail! Try again later"); - mContext.getMainThreadHandler().postDelayed(this::tryToRebind, 1000); + mContext.getMainThreadHandler().postDelayed(mTryToRebindRunnable, 1000); } else { // Timeout Slog.w(TAG, "Reverting to built-in wallpaper!"); -- GitLab From a1c9c5433d8a3a5de757b90d59d63a8bede358b2 Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Fri, 13 Mar 2020 16:09:43 +0800 Subject: [PATCH 139/143] DO NOT MERGE Optimizing ScreenDecorations performance Avoid calling onTuningChanged() when onConfigurationChanged() trigger Only calling onTuningChanged() when roundedCornersChanged is true. Test: atest SystemUITests Test: atest ScreenDecorationsTest Bug: 148912090 Change-Id: I2507d12b277d058cef390d7c55488d0d09dde206 Merged-In: Ie33526214072ad324ca00a10074ad212dfbf4258 --- .../SystemUI/src/com/android/systemui/ScreenDecorations.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index e0a9bb166fb2..8e5d5a83750d 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -588,8 +588,8 @@ public class ScreenDecorations extends SystemUI implements Tunable, mRoundedDefaultTop = newRoundedDefaultTop; mRoundedDefaultBottom = newRoundedDefaultBottom; } + onTuningChanged(SIZE, null); } - onTuningChanged(SIZE, null); } private void updateViews() { -- GitLab From 07808d1477d03b50c6e5535cf54210dad8e4f133 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sun, 15 Mar 2020 15:03:31 -0700 Subject: [PATCH 140/143] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: Icdc4ac69264d3712e36961f588a783cc13122b4c --- core/res/res/values-af/strings.xml | 4 + core/res/res/values-am/strings.xml | 4 + core/res/res/values-ar/strings.xml | 90 ++++++++++++----------- core/res/res/values-as/strings.xml | 6 ++ core/res/res/values-az/strings.xml | 4 + core/res/res/values-b+sr+Latn/strings.xml | 6 +- core/res/res/values-be/strings.xml | 6 +- core/res/res/values-bg/strings.xml | 4 + core/res/res/values-bn/strings.xml | 8 +- core/res/res/values-bs/strings.xml | 4 + core/res/res/values-ca/strings.xml | 28 ++++--- core/res/res/values-cs/strings.xml | 4 + core/res/res/values-da/strings.xml | 4 + core/res/res/values-de/strings.xml | 4 + core/res/res/values-el/strings.xml | 4 + core/res/res/values-en-rAU/strings.xml | 4 + core/res/res/values-en-rCA/strings.xml | 4 + core/res/res/values-en-rGB/strings.xml | 4 + core/res/res/values-en-rIN/strings.xml | 4 + core/res/res/values-en-rXC/strings.xml | 4 + core/res/res/values-es-rUS/strings.xml | 8 +- core/res/res/values-es/strings.xml | 12 ++- core/res/res/values-et/strings.xml | 4 + core/res/res/values-eu/strings.xml | 18 +++-- core/res/res/values-fa/strings.xml | 4 + core/res/res/values-fi/strings.xml | 4 + core/res/res/values-fr-rCA/strings.xml | 6 +- core/res/res/values-fr/strings.xml | 4 + core/res/res/values-gl/strings.xml | 4 + core/res/res/values-gu/strings.xml | 8 +- core/res/res/values-hi/strings.xml | 6 ++ core/res/res/values-hr/strings.xml | 4 + core/res/res/values-hu/strings.xml | 4 + core/res/res/values-hy/strings.xml | 8 +- core/res/res/values-in/strings.xml | 6 +- core/res/res/values-is/strings.xml | 4 + core/res/res/values-it/strings.xml | 8 +- core/res/res/values-iw/strings.xml | 4 + core/res/res/values-ja/strings.xml | 8 +- core/res/res/values-ka/strings.xml | 4 + core/res/res/values-kk/strings.xml | 4 + core/res/res/values-km/strings.xml | 4 + core/res/res/values-kn/strings.xml | 8 +- core/res/res/values-ko/strings.xml | 4 + core/res/res/values-ky/strings.xml | 60 ++++++++------- core/res/res/values-lo/strings.xml | 4 + core/res/res/values-lt/strings.xml | 4 + core/res/res/values-lv/strings.xml | 4 + core/res/res/values-mk/strings.xml | 14 ++-- core/res/res/values-ml/strings.xml | 6 ++ core/res/res/values-mn/strings.xml | 4 + core/res/res/values-mr/strings.xml | 8 +- core/res/res/values-ms/strings.xml | 4 + core/res/res/values-my/strings.xml | 6 +- core/res/res/values-nb/strings.xml | 6 +- core/res/res/values-ne/strings.xml | 6 ++ core/res/res/values-nl/strings.xml | 4 + core/res/res/values-or/strings.xml | 6 ++ core/res/res/values-pa/strings.xml | 4 + core/res/res/values-pl/strings.xml | 12 ++- core/res/res/values-pt-rBR/strings.xml | 10 ++- core/res/res/values-pt-rPT/strings.xml | 4 + core/res/res/values-pt/strings.xml | 10 ++- core/res/res/values-ro/strings.xml | 4 + core/res/res/values-ru/strings.xml | 10 ++- core/res/res/values-si/strings.xml | 4 + core/res/res/values-sk/strings.xml | 6 +- core/res/res/values-sl/strings.xml | 4 + core/res/res/values-sq/strings.xml | 16 ++-- core/res/res/values-sr/strings.xml | 6 +- core/res/res/values-sv/strings.xml | 8 +- core/res/res/values-sw/strings.xml | 8 +- core/res/res/values-ta/strings.xml | 44 ++++++----- core/res/res/values-te/strings.xml | 4 + core/res/res/values-th/strings.xml | 4 + core/res/res/values-tl/strings.xml | 4 + core/res/res/values-tr/strings.xml | 4 + core/res/res/values-uk/strings.xml | 4 + core/res/res/values-ur/strings.xml | 6 ++ core/res/res/values-uz/strings.xml | 4 + core/res/res/values-vi/strings.xml | 4 + core/res/res/values-zh-rCN/strings.xml | 4 + core/res/res/values-zh-rHK/strings.xml | 6 +- core/res/res/values-zh-rTW/strings.xml | 4 + core/res/res/values-zu/strings.xml | 4 + 85 files changed, 524 insertions(+), 162 deletions(-) diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index c1723908441c..807fe648a2d5 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -434,6 +434,8 @@ "Hierdie program kan jou fisieke aktiwiteit herken." "neem foto\'s en video\'s" "Hierdie program kan enige tyd met die kamera foto\'s neem en video\'s opneem." + "Laat \'n program of diens toe om terugbeloproepe te ontvang oor kameratoestelle wat oopgemaak of toegemaak word." + "Hierdie handtekeningprogram kan terugbeloproepe ontvang wanneer enige kameratoestel oopgemaak (deur watter programpakket) of toegemaak word." "beheer vibrasie" "Laat die program toe om die vibrator te beheer." "skakel foonnommers direk" @@ -450,9 +452,11 @@ "Laat die program toe om \'n oproep voort te sit wat in \'n ander program begin is." "lees foonnommers" "Laat die program toe om toegang tot die toestel se foonnommers te kry." + "hou motorskerm aan" "verhoed dat tablet slaap" "keer TV om te sluimer" "verhoed foon om te slaap" + "Laat die program toe om die motorskerm aan te hou." "Laat die program toe om die tablet te keer om te slaap." "Laat die program toe om die TV te keer om te sluimer." "Laat die program toe om die foon te keer om te slaap." diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 5a6d63537048..a7102271e4f8 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -434,6 +434,8 @@ "ይህ መተግበሪያ አካላዊ እንቅስቃሴዎን ለይቶ ሊያውቅ ይችላል።" "ፎቶዎች እና ቪዲዮዎች ያንሱ" "ይህ መተግበሪያ በማናቸውም ጊዜ ካሜራውን በመጠቀም ፎቶ ሊያነሳ እና ቪዲዮዎችን ሊቀርጽ ይችላል።" + "አንድ መተግበሪያ ወይም አገልግሎት እየተከፈቱ ወይም እየተዘጉ ስላሉ የካሜራ መሣሪያዎች መልሶ ጥሪዎችን እንዲቀበል ይፍቀዱ።" + "ማንኛውም የካሜራ መሣሪያ እየተከፈተ (በምን የመተግበሪያ ጥቅል) ወይም እየተዘጋ ሲሆን ይህ የፊርማ መተግበሪያ መልሶ ጥሪዎችን መቀበል ይችላል።" "ነዛሪ ተቆጣጠር" "ነዛሪውን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።" "በቀጥታ ስልክ ቁጥሮች ደውል" @@ -450,9 +452,11 @@ "መተግበሪያው በሌላ መተግበሪያ ውስጥ የተጀመረ ጥሪ እንዲቀጥል ያስችለዋል።" "ስልክ ቁጥሮች ያንብቡ" "መተግበሪያው የመሣሪያውን የስልክ ቁጥሮች እንዲደርስባቸው ይፈቅድለታል።" + "የመኪና ማያ ገጽ እንደበራ አቆይ" "ጡባዊ ከማንቀላፋት ተከላከል" "ቴሌቪዥን እንዳይተኛ አግድ" "ስልክ ከማንቀላፋት ተከላከል" + "መተግበሪያው የመኪናው ማያ ገጽ እንደበራ እንዲያቆየው ያስችለዋል።" "ጡባዊውን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።" "መተግበሪያው ቴሌቪዥኑ እንዳይተኛ እንዲያግድ ያስችለዋል።" "ስልኩን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።" diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 954ffd3b50d5..3cbf14558666 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -49,7 +49,7 @@ "‏اكتب رمز PUK مكونًا من ٨ أرقام أو أكثر." "‏شريحة SIM مؤمّنة برمز PUK. اكتب رمز PUK لإلغاء تأمينها." "‏اكتب PUK2 لإلغاء تأمين شريحة SIM." - "‏محاولة غير ناجحة، مكّن قفل SIM/RUIM." + "‏محاولة غير ناجحة، فعّل قفل SIM/RUIM." ‏لم يتبق لديك أي محاولات (%d) يتم بعدها قفل شريحة SIM. ‏يتبقى لديك محاولتان (%d) يتم بعدهما قفل شريحة SIM. @@ -123,12 +123,12 @@ "التجوال - شريك متميز" "تجوال - وظائف الخدمة الكاملة" "تجوال - وظائف الخدمة الجزئية" - "إعلان بانر للتجوال قيد التشغيل" + "إعلان بانر للتجوال قيد التفعيل" "إعلان بانر للتجوال متوقف" "البحث عن خدمة" "‏تعذّر إعداد الاتصال عبر Wi‑Fi." - "‏لإجراء مكالمات وإرسال رسائل عبر Wi-Fi، اطلب من مشغّل شبكة الجوّال أولاً إعداد هذه الخدمة، ثم شغّل الاتصال عبر Wi-Fi مرة أخرى من خلال الإعدادات. (رمز الخطأ: %1$s)" + "‏لإجراء مكالمات وإرسال رسائل عبر Wi-Fi، اطلب من مفعِّل شبكة الجوّال أولاً إعداد هذه الخدمة، ثم فعِّل الاتصال عبر Wi-Fi مرة أخرى من خلال الإعدادات. (رمز الخطأ: %1$s)" "‏حدثت مشكلة أثناء تسجيل الاتصال عبر Wi‑Fi باستخدام مشغِّل شبكة الجوّال: %1$s" @@ -206,8 +206,8 @@ "خيارات التلفزيون" "خيارات الهاتف" "وضع صامت" - "تشغيل اللاسلكي" - "إيقاف تشغيل الشبكة اللاسلكية" + "تفعيل اللاسلكي" + "إيقاف تفعيل الشبكة اللاسلكية" "قفل الشاشة" "إيقاف التشغيل" "إيقاف الرنين" @@ -217,13 +217,13 @@ "جارٍ الإعداد للتحديث…" "جارٍ معالجة حزمة التحديث…" "جارٍ إعادة التشغيل…" - "إعادة الضبط بحسب بيانات المصنع" + "إعادة الضبط على الإعدادات الأصلية" "جارٍ إعادة التشغيل…" "جارٍ إيقاف التشغيل..." - "سيتم إيقاف تشغيل الجهاز اللوحي." + "سيتم إيقاف تفعيل الجهاز اللوحي." "سيتم إيقاف التلفزيون." "سيتم إيقاف المشاهدة." - "سيتم إيقاف تشغيل هاتفك." + "سيتم إيقاف تفعيل هاتفك." "هل تريد إيقاف التشغيل؟" "إعادة تشغيل في الوضع الآمن" "هل تريد إعادة تشغيل الكمبيوتر في الوضع الآمن؟ سيؤدي ذلك إلى إيقاف جميع تطبيقات الجهات الخارجية التي تم تثبيتها. ستتم استعادتها عند إعادة التشغيل مرة أخرى." @@ -254,9 +254,9 @@ "وضع صامت" "الصوت متوقف" - "الصوت قيد التشغيل" + "الصوت قيد التفعيل" "وضع الطائرة" - "وضع الطائرة قيد التشغيل" + "وضع الطائرة قيد التفعيل" "وضع الطائرة متوقف" "الإعدادات" "مساعدة" @@ -327,8 +327,8 @@ "‏هل تريد السماح لتطبيق <b>%1$s</b> بالدخول إلى بيانات المستشعر حول علاماتك الحيوية؟" "استرداد محتوى النافذة" "فحص محتوى نافذة يتم التفاعل معها" - "تشغيل الاستكشاف باللمس" - "سيتم نطق العناصر التي تم النقر عليها بصوت عال ويمكن استكشاف الشاشة باستخدام الإيماءات." + "تفعيل الاستكشاف باللمس" + "سيتم قول العناصر التي تم النقر عليها بصوت عال ويمكن استكشاف الشاشة باستخدام الإيماءات." "ملاحظة النص الذي تكتبه" "يتضمن بيانات شخصية مثل أرقام بطاقات الائتمان وكلمات المرور." "التحكم في تكبير الشاشة" @@ -374,7 +374,7 @@ "إعادة ترتيب التطبيقات قيد التشغيل" "للسماح للتطبيق بنقل المهام إلى المقدمة والخلفية. وقد يجري التطبيق ذلك بدون إذنك." "تفعيل وضع السيارة" - "للسماح للتطبيق بتمكين وضع السيارة." + "للسماح للتطبيق بتفعيل وضع السيارة." "إغلاق التطبيقات الأخرى" "للسماح للتطبيق بإنهاء عمليات التطبيقات الأخرى في الخلفية. وقد يؤدي هذا إلى توقف تطبيقات أخرى عن العمل." "يمكن لهذا التطبيق الظهور في مقدمة التطبيقات الأخرى" @@ -426,7 +426,7 @@ "يمكن لهذا التطبيق إضافة أحداث تقويم أو إزالتها أو تغييرها على التلفزيون. كما يمكنه إرسال رسائل تبدو أنها من أصحاب التقويم، أو تغيير الأحداث بدون إشعار مالكيها." "يمكن لهذا التطبيق إضافة أحداث تقويم أو إزالتها أو تغييرها على الهاتف. كما يمكنه إرسال رسائل يبدو أنها واردة من مالكي التقويم، ويمكنه كذلك تغيير الأحداث بدون إشعار مالكيها." "الدخول إلى المزيد من أوامر موفر الموقع" - "‏للسماح للتطبيق بالدخول إلى أوامر إضافية لموفر الموقع. قد يتيح هذا للتطبيق التداخل مع تشغيل تقنية نظام تحديد المواقع العالمي (GPS) أو مصادر الموقع الأخرى." + "‏للسماح للتطبيق بالدخول إلى أوامر إضافية لموفر الموقع. قد يتيح هذا للتطبيق التداخل مع تفعيل تقنية نظام تحديد المواقع العالمي (GPS) أو مصادر الموقع الأخرى." "الوصول إلى الموقع الجغرافي الدقيق في الواجهة الأمامية فقط" "لا يمكن لهذا التطبيق معرفة موقعك الجغرافي بالضبط إلا عندما يعمل في الخلفية. ويجب تفعيل خدمات الموقع الجغرافي هذه وأن تكون متاحة على الهاتف حتى يتمكن التطبيق من استخدامها. وقد يؤدي هذا إلى زيادة استهلاك طاقة البطارية." "الوصول إلى الموقع الجغرافي التقريبي (بالاعتماد على الشبكة) في الخلفية فقط" @@ -446,6 +446,8 @@ "يمكن لهذا التطبيق التعرّف على نشاطك البدني." "التقاط صور وفيديوهات" "يمكن لهذا التطبيق التقاط صور وتسجيل فيديوهات باستخدام الكاميرا في أي وقت." + "يسمح الإذن لتطبيق أو خدمة بتلقّي استدعاءات عما إذا كانت أجهزة الكاميرات مفتوحة أو مغلقة." + "يمكن أن يتلقّى تطبيق التوقيع هذا استدعاءات عندما يكون جهاز أي كاميرا مفتوحًا (بحزمة تطبيق) أو مغلقًا." "التحكم في الاهتزاز" "للسماح للتطبيق بالتحكم في الهزّاز." "اتصال مباشر بأرقام الهواتف" @@ -462,9 +464,11 @@ "السماح للتطبيق بمواصلة مكالمة بدأت في تطبيق آخر." "قراءة أرقام الهواتف" "للسماح للتطبيق بالوصول إلى أرقام الهواتف على هذا الجهاز." + "الاحتفاظ بشاشة السيارة مفعَّلة" "منع الجهاز اللوحي من الدخول في وضع السكون" "منع التلفزيون من الدخول في وضع السكون" "منع الهاتف من الدخول في وضع السكون" + "يسمح هذا الإذن للتطبيق بالاحتفاظ بشاشة السيارة مفعَّلة." "للسماح للتطبيق بمنع الجهاز اللوحي من الانتقال إلى وضع السكون." "يتيح للتطبيق منع التلفزيون من الدخول في وضع السكون." "للسماح للتطبيق بمنع الهاتف من الانتقال إلى وضع السكون." @@ -609,8 +613,8 @@ "رمز الوجه" "قراءة إعدادات المزامنة" "للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما." - "التبديل بين تشغيل المزامنة وإيقافها" - "للسماح للتطبيق بتعديل إعدادات المزامنة لحساب ما. على سبيل المثال، يمكن استخدام ذلك لتمكين مزامنة تطبيق \"الأشخاص\" مع حساب ما." + "التبديل بين تفعيل المزامنة وإيقافها" + "للسماح للتطبيق بتعديل إعدادات المزامنة لحساب ما. على سبيل المثال، يمكن استخدام ذلك لتفعيل مزامنة تطبيق \"الأشخاص\" مع حساب ما." "قراءة إحصاءات المزامنة" "للسماح للتطبيق بقراءة إحصائيات المزامنة لحساب ما، بما في ذلك سجل الأحداث المتزامنة ومقدار البيانات التي تمت مزامنتها." "قراءة محتوى مساحة التخزين المشتركة" @@ -679,7 +683,7 @@ "قفل الشاشة" "التحكّم في طريقة ووقت قفل الشاشة" "محو جميع البيانات" - "يمكنك محو بيانات الجهاز اللوحي بدون تحذير، وذلك عبر إجراء إعادة الضبط بحسب بيانات المصنع." + "يمكنك محو بيانات الجهاز اللوحي بدون تحذير، وذلك عبر إجراء إعادة الضبط على الإعدادات الأصلية." "محو بيانات التلفزيون بدون تحذير من خلال إجراء إعادة ضبط البيانات على الإعدادات الأصلية." "محو بيانات الهاتف بدون تحذير، وذلك من خلال إعادة ضبط البيانات على الإعدادات الأصلية" "محو بيانات المستخدم" @@ -690,8 +694,8 @@ "لضبط الخادم الوكيل العام في الجهاز على الاستخدام أثناء تفعيل السياسة. ولن يمكن لأحد سوى مالك الجهاز ضبط الخادم الوكيل العام." "تعيين مدة انتهاء صلاحية كلمة مرور قفل الشاشة" "لتغيير عدد مرات تغيير كلمة المرور ورقم التعريف الشخصي والنمط في قفل الشاشة." - "تعيين تشفير التخزين" - "يمكنك طلب تشفير بيانات التطبيق المخزنة." + "تعيين ترميز التخزين" + "يمكنك طلب ترميز بيانات التطبيق المخزنة." "إيقاف الكاميرات" "يمكنك منع استخدام جميع كاميرات الجهاز." "إيقاف بعض ميزات قفل الشاشة" @@ -845,7 +849,7 @@ "إيقاف مؤقت" "تشغيل" "إيقاف" - "إرجاع" + "ترجيع" "تقديم سريع" "مكالمات الطوارئ فقط" "الشبكة مؤمّنة" @@ -859,12 +863,12 @@ "‏لقد رسمت نقش فتح القفل بشكل غير صحيح %1$d مرة. بعد %2$d من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات تسجيل الدخول إلى Google.\n\n أعد المحاولة خلال %3$d ثانية." "‏لديك %1$d من محاولات رسم نقش فتح القفل غير الصحيحة. بعد %2$d من المحاولات غير الناجحة الأخرى، سيُطلب منك فتح قفل التلفزيون من خلال تسجيل الدخول إلى Google.\n\n يمكنك إعادة التجربة خلال %3$d ثانية." "‏لقد رسمت نقش فتح القفل بشكل غير صحيح %1$d مرة. بعد %2$d من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام معلومات تسجيل الدخول إلى Google.\n\n أعد المحاولة خلال %3$d ثانية." - "لقد حاولت فتح قفل الجهاز اللوحي %1$d من المرات. بعد %2$d من المحاولات غير الناجحة، ستتم إعادة تعيين الجهاز اللوحي إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." + "لقد حاولت فتح قفل الجهاز اللوحي %1$d من المرات. بعد %2$d من المحاولات غير الناجحة، ستتم إعادة ضبط الجهاز اللوحي إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." "لديك %1$d من محاولات فتح قفل التلفزيون غير الصحيحة. بعد %2$d من المحاولات غير الناجحة الأخرى، ستتم إعادة ضبط التلفزيون على الإعدادات الأساسية وستفقد جميع بيانات المستخدم." - "لقد حاولت فتح قفل الهاتف %1$d من المرات. بعد %2$d من المحاولات غير الناجحة، ستتم إعادة تعيين الهاتف إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." - "لقد حاولت فتح قفل الجهاز اللوحي %d من المرات بشكل غير صحيح. سيتم الآن إعادة تعيين الجهاز اللوحي إلى الإعدادات الأساسية." + "لقد حاولت فتح قفل الهاتف %1$d من المرات. بعد %2$d من المحاولات غير الناجحة، ستتم إعادة ضبط الهاتف إلى الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." + "لقد حاولت فتح قفل الجهاز اللوحي %d من المرات بشكل غير صحيح. سيتم الآن إعادة ضبط الجهاز اللوحي إلى الإعدادات الأساسية." "لديك %d من محاولات فتح قفل التلفزيون غير الصحيحة. ستتم الآن إعادة ضبط التلفزيون على الإعدادات الأساسية." - "لقد حاولت فتح قفل الهاتف %d من المرات بشكل غير صحيح. سيتم الآن إعادة تعيين الهاتف إلى الإعدادات الأساسية." + "لقد حاولت فتح قفل الهاتف %d من المرات بشكل غير صحيح. سيتم الآن إعادة ضبط الهاتف إلى الإعدادات الأساسية." "حاول مرة أخرى خلال %d ثانية." "هل نسيت النمط؟" "فتح قفل الحساب" @@ -920,7 +924,7 @@ "‏لم يتم العثور على أي حزمة توفر إجراء FACTORY_TEST." "إعادة تشغيل" "تعرض الصفحة في \"%s\":" - "جافا سكريبت" + "JavaScript" "تأكيد الانتقال" "مغادرة هذه الصفحة" "البقاء في هذه الصفحة" @@ -984,8 +988,8 @@ "إرسال طلب البحث" "البحث الصوتي" "‏هل تريد تفعيل ميزة Explore by Touch؟" - "‏يريد %1$s تفعيل ميزة Explore by Touch. عند تشغيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الجهاز اللوحي." - "‏يريد %1$s تفعيل ميزة Explore by Touch. عند تشغيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الهاتف." + "‏يريد %1$s تفعيل ميزة Explore by Touch. عند تفعيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الجهاز اللوحي." + "‏يريد %1$s تفعيل ميزة Explore by Touch. عند تفعيل ميزة Explore by Touch، سيكون بإمكانك سماع أو مشاهدة أوصاف لما تحت إصبعك أو إجراء إيماءات للتفاعل مع الهاتف." "قبل شهر واحد" "قبل شهر واحد" @@ -1253,7 +1257,7 @@ "%1$s لا يستجيب" "%1$s لا يستجيب" "العملية %1$s لا تستجيب" - "موافق" + "حسنًا" "إرسال تقرير" "انتظار" "أصبحت الصفحة لا تستجيب.\n\nهل تريد إغلاقها؟" @@ -1356,7 +1360,7 @@ "شبكات %s المقترحة - قد يتم توصيل الجهاز تلقائيًا." "سماح" "لا، شكرًا" - "‏سيتم تشغيل شبكة Wi-Fi تلقائيًا." + "‏سيتم تفعيل شبكة Wi-Fi تلقائيًا." "عندما تكون بالقرب من شبكة محفوظة عالية الجودة" "عدم إعادة التشغيل" "‏تم تفعيل شبكة Wi-Fi تلقائيًا." @@ -1392,7 +1396,7 @@ "‏اتصال Wi-Fi مباشر" "‏ابدأ Wi-Fi Direct. يؤدي هذا إلى إيقاف عميل/نقطة اتصال Wi-Fi." "‏تعذر بدء Wi-Fi Direct." - "‏تم تشغيل اتصال Wi-Fi المباشر" + "‏تم تفعيل اتصال Wi-Fi المباشر" "انقر للحصول على الإعدادات." "قبول" "رفض" @@ -1456,7 +1460,7 @@ "‏اختيار إيقاف تصحيح أخطاء USB." "تم تفعيل وضع \"مفعّل الاختبار\"" "يمكنك إجراء إعادة ضبط على الإعدادات الأصلية لإيقاف وضع \"مفعِّل اختبار\"." - "‏السوائل والشوائب في منفذ USB" + "‏السوائل أو الشوائب في منفذ USB" "‏تمّ إيقاف منفذ USB تلقائيًا. انقُر لمعرفة المزيد من المعلومات." "‏مسموح باستخدام منفذ USB" "لم يَعُد الهاتف يكتشف سوائل أو شوائب." @@ -1562,8 +1566,8 @@ "‏تم تفعيل VPN بواسطة %s" "انقر لإدارة الشبكة." "تم الاتصال بـ %s. انقر لإدارة الشبكة." - "‏جارٍ الاتصال بشبكة افتراضية خاصة (VPN) دائمة التشغيل..." - "‏تم الاتصال بشبكة افتراضية خاصة (VPN) دائمة التشغيل" + "‏جارٍ الاتصال بشبكة افتراضية خاصة (VPN) دائمة التفعيل..." + "‏تم الاتصال بشبكة افتراضية خاصة (VPN) دائمة التفعيل" "‏تم قطع الاتصال بالشبكة الافتراضية الخاصة (VPN) التي يتم تشغيلها دائمًا" "‏تعذّر الاتصال بشبكة VPN التي يتم تشغيلها دائمًا." "‏تغيير إعدادات الشبكة أو الشبكة الافتراضية الخاصة (VPN)" @@ -1753,12 +1757,12 @@ "‏لقد كتبت رمز PIN بشكل غير صحيح %1$d مرة. \n\nأعد المحاولة خلال %2$d ثانية." "لقد كتبت كلمة المرور بشكل غير صحيح %1$d مرة. \n\nأعد المحاولة خلال %2$d ثانية." "لقد رسمت نقش فتح القفل بطريقة غير صحيحة %1$d مرة. \n\nأعد المحاولة خلال %2$d ثانية." - "لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين الجهاز اللوحي على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." + "لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستتم إعادة ضبط الجهاز اللوحي على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." "لديك %1$d من محاولات فتح قفل التلفزيون غير الصحيحة. بعد %2$d من المحاولات غير الناجحة الأخرى، ستتم إعادة ضبط التلفزيون على الإعدادات الأساسية وستفقد جميع بيانات المستخدم." - "لقد حاولت فتح قفل الهاتف بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين الهاتف على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." - "لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح %d مرة. سيتم الآن إعادة تعيين الجهاز اللوحي على الإعدادات الأساسية." + "لقد حاولت فتح قفل الهاتف بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستتم إعادة ضبط الهاتف على الإعدادات الأساسية وسيتم فقد جميع بيانات المستخدم." + "لقد حاولت فتح قفل الجهاز اللوحي بشكل غير صحيح %d مرة. سيتم الآن إعادة ضبط الجهاز اللوحي على الإعدادات الأساسية." "لديك %d من محاولات فتح قفل التلفزيون غير الصحيحة. ستتم الآن إعادة ضبط التلفزيون على الإعدادات الأساسية." - "لقد حاولت فتح قفل الهاتف بشكل غير صحيح %d مرة. سيتم الآن إعادة تعيين الهاتف على الإعدادات الأساسية." + "لقد حاولت فتح قفل الهاتف بشكل غير صحيح %d مرة. سيتم الآن إعادة ضبط الهاتف على الإعدادات الأساسية." "لقد رسمت نقش فتح القفل بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال %3$d ثانية." "لقد رسمت نقش فتح القفل بشكل غير صحيح عدد %1$d من المرات. بعد %2$d من المحاولات غير الناجحة، سيُطلب منك فتح قفل التلفزيون باستخدام حساب بريد إلكتروني.\n\n يمكنك إعادة التجربة خلال %3$d ثانية." "لقد رسمت نقش فتح القفل بشكل غير صحيح %1$d مرة. بعد إجراء %2$d من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال %3$d ثانية." @@ -1916,12 +1920,12 @@ "تم التثبيت بواسطة المشرف" "تم التحديث بواسطة المشرف" "تم الحذف بواسطة المشرف" - "موافق" + "حسنًا" "‏لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"\n\n""مزيد من المعلومات" "‏لإطالة عمر البطارية، \"توفير شحن البطارية\":\n·تفعيل \"التصميم الداكن\"\n إيقاف النشاط في الخلفية أو تقييده وأيضًا بعض التأثيرات المرئية والميزات الأخرى، مثلاً \"Ok Google\"." "للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيق الذي تستخدمه الآن الوصول إلى البيانات، ولكن لا يمكنه تنفيذ ذلك كثيرًا. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها." - "هل تريد تشغيل توفير البيانات؟" - "تشغيل" + "هل تريد تفعيل توفير البيانات؟" + "تفعيل" ‏لمدة أقل من دقيقة (%1$d) (حتى %2$s) ‏لمدة دقيقتين (%1$d) (حتى %2$s) @@ -1999,7 +2003,7 @@ "حدث" "النوم" "يعمل %1$s على كتم بعض الأصوات." - "حدثت مشكلة داخلية في جهازك، وقد لا يستقر وضعه حتى إجراء إعادة الضبط بحسب بيانات المصنع." + "حدثت مشكلة داخلية في جهازك، وقد لا يستقر وضعه حتى إجراء إعادة الضبط على الإعدادات الأصلية." "حدثت مشكلة داخلية في جهازك. يمكنك الاتصال بالمصنِّع للحصول على تفاصيل." "‏تم تغيير طلب USSD إلى مكالمة عادية." "‏تم تغيير طلب USSD إلى طلب SS." @@ -2047,7 +2051,7 @@ "مزيد من المعلومات" "تفعيل الملف الشخصي للعمل؟" "سيتم تفعيل تطبيقات العمل التي تستخدمها والإشعارات والبيانات وغيرها من ميزات الملف الشخصي للعمل" - "تشغيل" + "تفعيل" "‏تمّ إنشاء هذا التطبيق لإصدار قديم من Android وقد لا يعمل بشكل صحيح. جرِّب البحث عن تحديثات أو الاتصال بمطوّر البرامج." "البحث عن تحديث" "لديك رسائل جديدة" @@ -2062,7 +2066,7 @@ "معلومات عن التطبيق" "−%1$s" "جارٍ بدء العرض التوضيحي…" - "جارٍ إعادة تعيين الجهاز…" + "جارٍ إعادة ضبط الجهاز…" "تم إيقاف %1$s" "مكالمة جماعية" "تلميح" diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 176b5f9922d0..0af9b14ab1b5 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -434,6 +434,10 @@ "এই এপটোৱে আপোনাৰ শাৰীৰিক কাৰ্যকলাপ চিনাক্ত কৰিব পাৰে।" "ফট\' তোলা আৰু ভিডিঅ\' ৰেকৰ্ড কৰা" "এই এপে যিকোনো সময়তে কেমেৰা ব্যৱহাৰ কৰি ফট\' তুলিব আৰু ভিডিঅ\' ৰেকর্ড কৰিব পাৰে।" + + + + "কম্পন নিয়ন্ত্ৰণ কৰক" "ভাইব্ৰেটৰ নিয়ন্ত্ৰণ কৰিবলৈ এপটোক অনুমতি দিয়ে।" "পোনপটীয়াকৈ ফ\'ন নম্বৰলৈ কল কৰক" @@ -450,9 +454,11 @@ "এপটোক এনে কল কৰিবলৈ দিয়ে যিটোৰ আৰম্ভণি অইন এটা এপত হৈছিল।" "ফ\'ন নম্বৰসমূহ পঢ়ে" "এপটোক ডিভাইচটোৰ ফ\'ন নম্বৰসমূহ চাবলৈ অনুমতি দিয়ে।" + "গাড়ীৰ স্ক্রীনখন অন কৰি ৰখা" "টে\'বলেট সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ক" "টিভি সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ে" "ফ\'ন সুপ্ত অৱস্থালৈ যোৱাত বাধা দিয়ক" + "এপ্‌টোক গাড়ীৰ স্ক্রীনখন অন কৰি ৰাখিবলৈ অনুমতি দিয়ে।" "টে\'বলেট সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।" "টিভিটোক সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।" "ফ\'ন সুপ্ত অৱস্থালৈ যোৱাৰ পৰা প্ৰতিৰোধ কৰিবলৈ এপটোক অনুমতি দিয়ে।" diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index d15fd8d1899a..14a8493c6ad7 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -434,6 +434,8 @@ "Bu tətbiq fiziki fəaliyyətinizi tanıya bilər." "şəkil və video çəkmək" "Bu tətbiq istədiyiniz zaman kameranı istifadə edərək şəkil çəkə və video qeydə ala bilər." + "Tətbiqə və ya xidmətə kamera cihazlarının açılması və ya bağlanması haqqında geri zənglər qəbul etməyə icazə verin." + "Hər hansı kamera cihazı açıldıqda (hansı tətbiq paketi tərəfindən) və ya bağlandıqda bu imza tətbiqi geri zənglər qəbul edə bilər." "vibrasiyaya nəzarət edir" "Tətbiqə vibratoru idarə etmə icazəsi verir." "telefon nömrələrinə birbaşa zəng edir" @@ -450,9 +452,11 @@ "Tətbiqə digər tətbiqdə başlayan zəngə davam etmək icazəsi verilir." "telefon nömrələrini oxuyun" "Tətbiqə cihazın telefon nömrələrinə daxil olmağa icazə verir." + "avtomobilin ekranını aktiv saxlamaq" "planşetin yuxu rejiminin qarşısını almaq" "TV-ni yuxu rejiminə keçməyə qoyma" "telefonun yuxu rejiminə keçməsini əngəllə" + "Tətbiqə avtomobilin ekranını aktiv saxlamaq icazəsi verir." "Tətbiqə planşetin yuxu rejimini qadağan etməyə imkan verir." "Proqrama TV-ni yuxulamağa qoymamaq imkanı verir." "Tətbiqə telefonun yuxu rejimini qadağan etmək imkanı verir." diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 837973d9f1fe..291f54099128 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -297,7 +297,7 @@ "Želite li da omogućite da <b>%1$s</b> šalje i pregleda SMS-ove?" "Memorijski prostor" "pristupa slikama, medijima i datotekama na uređaju" - "Želite li da omogućite da <b>%1$s</b> pristupa slikama, medijskim datotekama i datotekama na uređaju?" + "Želite li da omogućite da <b>%1$s</b> pristupa slikama, medijskim i drugim datotekama na uređaju?" "Mikrofon" "snima zvuk" "Želite li da omogućite da <b>%1$s</b> snima zvuk?" @@ -437,6 +437,8 @@ "Ova aplikacija može da prepozna fizičke aktivnosti." "snimanje fotografija i video snimaka" "Ova aplikacija može da snima fotografije i video snimke pomoću kamere u bilo kom trenutku." + "Dozvolite aplikaciji ili usluzi da dobija povratne pozive o otvaranju ili zatvaranju uređaja sa kamerom." + "Ova aplikacija za potpise može da dobija povratne pozive kada se bilo koji uređaj sa kamerom otvara ili zatvara (pomoću nekog paketa aplikacija)." "kontrola vibracije" "Dozvoljava aplikaciji da kontroliše vibraciju." "direktno pozivanje brojeva telefona" @@ -453,9 +455,11 @@ "Dozvoljava aplikaciji da nastavi poziv koji je započet u drugoj aplikaciji." "čitanje brojeva telefona" "Dozvoljava aplikaciji da pristupa brojevima telefona na uređaju." + "ne isključuj ekran u automobilu" "sprečavanje prelaska tableta u stanje spavanja" "sprečavanje TV-a da pređe u stanje spavanja" "sprečavanje prelaska telefona u stanje spavanja" + "Dozvoljava aplikaciji da ne isključuje ekran u automobilu." "Dozvoljava aplikaciji da spreči tablet da pređe u stanje spavanja." "Dozvoljava aplikaciji da spreči TV da pređe u stanje spavanja." "Dozvoljava aplikaciji da spreči telefon da pređe u stanje spavanja." diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 6fb269bbbe77..d0e50aae7de3 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -91,7 +91,7 @@ "Экстранныя выклікі ў сетцы Wi‑Fi недаступныя" "Абвесткі" "Пераадрасацыя выкліку" - "Рэжым экстраннага зваротнага выкліку" + "Рэжым экстранных зваротных выклікаў" "Стан мабільнай перадачы даных" "SMS-паведамленні" "Паведамленні галасавой пошты" @@ -440,6 +440,8 @@ "Гэта праграма можа распазнаваць фізічную актыўнасць." "рабіць фатаграфіі і відэа" "Гэта праграма можа рабіць фота і запісваць відэа з дапамогай камеры ў любы час." + "Дазволіць праграме ці сэрвісу атрымліваць зваротныя выклікі наконт адкрыцця ці закрыцця прылад камеры." + "Гэта праграма для подпісу можа атрымліваць зваротныя вылікі, калі адкрываецца (пакетам праграм) або закрываецца прылада камеры." "кіраванне вібрацыяй" "Дазваляе прыкладанням кіраваць вібрацыяй." "непасрэдна набіраць тэлефонныя нумары" @@ -456,9 +458,11 @@ "Дазваляе праграме працягваць выклік, які пачаўся ў іншай праграме." "счытваць нумары тэлефонаў" "Дазваляе праграме атрымліваць доступ да нумароў тэлефонаў на прыладзе." + "пакідаць экран аўтамабіля ўключаным" "прадухіліць планшэт ад пераходу ў рэжым сну" "прадухіленне пераходу тэлевізара ў рэжым сну" "забараняць тэлефону пераходзіць ў рэжым сну" + "Дазваляе праграме пакідаць экран аўтамабіля ўключаным." "Дазваляе прыкладанням прадухіляць пераход планшэта ў рэжым сну." "Дазваляе праграме прадухіляць пераход тэлевізара ў рэжым сну." "Дазваляе прыкладанням прадухіляць тэлефон ад пераходу ў рэжым сну." diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index dabc00be6a02..6a747f41107b 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -434,6 +434,8 @@ "Това приложение може да разпознава физическата ви активност." "правене на снимки и видеоклипове" "Това приложение може по всяко време да прави снимки и да записва видеоклипове посредством камерата." + "Разрешаване на приложение или услуга да получават обратни повиквания за отварянето или затварянето на снимачни устройства." + "Това приложение за подписване може да получава обратни повиквания, когато снимачно устройство бъде отворено (от кой пакет на приложение) или затворено." "контролиране на вибрирането" "Разрешава на приложението да контролира устройството за вибрация." "директно обаждане до телефонни номера" @@ -450,9 +452,11 @@ "Разрешава на приложението да продължи обаждане, стартирано в друго приложение." "четене на телефонните номера" "Разрешава на приложението да осъществява достъп до телефонните номера на устройството." + "постоянно включен екран на автомобила" "предотвратяване на спящия режим на таблета" "предотвратяване на преминаването на телевизора в спящ режим" "предотвратява спящ режим на телефона" + "Дава възможност на приложението да поддържа екрана на автомобила включен." "Разрешава на приложението да предотвратява преминаването на таблета в спящ режим." "Разрешава на приложението да предотвратява преминаването в спящ режим на телевизора." "Разрешава на приложението да предотвратява преминаването на телефона в спящ режим." diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 038e72664d4c..252308d6f21a 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -434,6 +434,10 @@ "এই অ্যাপ আপনার শারীরিক অ্যাক্টিভিটি শনাক্ত করতে পারবে।" "ছবি এবং ভিডিও তোলে" "এই অ্যাপটি যে কোনো সময় ক্যামেরা ব্যবহার করে ছবি তুলতে বা ভিডিও রেকর্ড করতে পারে৷" + + + + "ভাইব্রেশন নিয়ন্ত্রণ করুন" "অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷" "সরাসরি ফোন নম্বরগুলিতে কল করে" @@ -450,9 +454,11 @@ "অন্য কোনও অ্যাপ দিয়ে কল করলে এই অ্যাপটিকে সেটি চালিয়ে যেতে দেয়।" "ফোন নম্বরগুলি পড়া হোক" "অ্যাপটিকে এই ডিভাইসের ফোন নম্বরগুলি অ্যাক্সেস করতে দেয়।" + "গাড়ির স্ক্রিন চালু রাখা আছে" "ঘুমানো থেকে ট্যাবলেটকে প্রতিরোধ করে" "টিভিকে নিদ্রায় যাওয়া থেকে প্রতিরোধ করে" "ঘুমানো থেকে ফোনটিকে প্রতিরোধ করে" + "গাড়ির স্ক্রিন চালু রাখতে অ্যাপকে অনুমতি দেয়।" "অ্যাপ্লিকেশানকে ট্যাবলেট নিদ্রায় যাওয়া থেকে প্রতিরোধ করার মঞ্জুরি দেয়৷" "অ্যাপ্লিকেশানকে টিভিকে নিদ্রায় যাওয়া থেকে প্রতিরোধ করার মঞ্জুরি দেয়৷" "অ্যাপ্লিকেশানকে ফোনকে নিদ্রায় যাওয়া থেকে প্রতিরোধ করার মঞ্জুরি দেয়৷" @@ -1352,7 +1358,7 @@ "কোনো অনুমতির প্রয়োজন নেই" "এর জন্য অর্থপ্রদান করতে হতে পারে" "ঠিক আছে" - "এই ডিভাইসটি USB এর মাধ্যমে চার্জ করুন" + "এই ডিভাইসটি USB দিয়ে চার্জ করা হচ্ছে" "সংযুক্ত ডিভাইসটি USB এর মাধ্যমে চার্জ করা হচ্ছে" "USB ফাইল ট্রান্সফার চালু করা হয়েছে" "USB এর মাধ্যমে PTP চালু করা হয়েছে" diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 661910b939b0..6a284c94eecc 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -437,6 +437,8 @@ "Ova aplikacija može prepoznati vašu fizičku aktivnost." "snimanje slika i videozapisa" "Ova aplikacija može slikati fotografije i snimati videozapise koristeći kameru bilo kada." + "Dozvoliti aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju kamera." + "Ova aplikacija za potpisivanje može primati povratne pozive kada se otvara ili zatvara bilo koja kamera (kojim paketom aplikacija)." "kontrola vibracije" "Dozvoljava aplikaciji upravljanje vibracijom." "izravno zvanje telefonskih brojeva" @@ -453,9 +455,11 @@ "Dozvoljava aplikaciji nastavljanje poziva koji je započet u drugoj aplikaciji." "čitanje telefonskih brojeva" "Dozvoljava aplikaciji pristup telefonskim brojevima uređaja." + "ostavi ekran automobila uključenim" "sprečavanje tableta da uđe u režim mirovanja" "spriječi ulazak TV-a u režim mirovanja" "sprečavanje telefona da uđe u režim mirovanja" + "Dozvoljava aplikaciji da ostavi ekran automobila uključenim." "Dozvoljava aplikaciji da spriječi tablet da ode u stanje mirovanja." "Dozvoljava aplikaciji da spriječi ulazak TV-a u režim mirovanja." "Dozvoljava aplikaciji da spriječi telefon da ode u stanje mirovanja." diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index a79d847a11fa..e945690f2988 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -182,11 +182,11 @@ Autoritat de certificació instal·lada "Per un tercer desconegut" - "Per l\'administrador del teu perfil professional" + "Per l\'administrador del teu perfil de treball" "Per %s" - "S\'ha suprimit el perfil professional" - "Falta l\'aplicació d\'administració del perfil professional o està malmesa. Com a conseqüència, s\'han suprimit el teu perfil professional i les dades relacionades. Contacta amb l\'administrador per obtenir ajuda." - "El teu perfil professional ja no està disponible en aquest dispositiu" + "S\'ha suprimit el perfil de treball" + "Falta l\'aplicació d\'administració del perfil de treball o està malmesa. Com a conseqüència, s\'han suprimit el teu perfil de treball i les dades relacionades. Contacta amb l\'administrador per obtenir ajuda." + "El teu perfil de treball ja no està disponible en aquest dispositiu" "Has intentat introduir la contrasenya massa vegades" "El dispositiu està gestionat" "La teva organització gestiona aquest dispositiu i és possible que supervisi el trànsit de xarxa. Toca per obtenir més informació." @@ -276,7 +276,7 @@ "Mode segur" "Sistema Android" "Canvia al perfil personal" - "Canvia al perfil professional" + "Canvia al perfil de treball" "Contactes" "accedir als contactes" "Vols permetre que <b>%1$s</b> accedeixi als contactes?" @@ -434,6 +434,8 @@ "Aquesta aplicació pot reconèixer la teva activitat física." "fer fotos i vídeos" "Aquesta aplicació pot fer fotos i gravar vídeos amb la càmera en qualsevol moment." + "Permet que una aplicació o un servei pugui rebre crides de retorn sobre els dispositius de càmera que s\'obren o es tanquen." + "Aquesta aplicació de signatures pot rebre crides de retorn quan s’obre o es tanca un dispositiu de càmera (segons el paquet d’aplicació)." "controlar la vibració" "Permet que l\'aplicació controli el vibrador." "trucar directament a números de telèfon" @@ -450,9 +452,11 @@ "Permet que l\'aplicació continuï una trucada que s\'havia iniciat en una altra aplicació." "llegir els números de telèfon" "Permet que l\'aplicació accedeixi als números de telèfon del dispositiu." + "mantén la pantalla del cotxe encesa" "evita que la tauleta entri en mode de repòs" "impedir que el televisor entri en mode de repòs" "impedir que el telèfon entri en mode de repòs" + "Permet que l\'aplicació mantingui la pantalla del cotxe encesa." "Permet que l\'aplicació impedeixi que la tauleta entri en repòs." "Permet a l\'aplicació impedir que el televisor entri en repòs." "Permet que l\'aplicació impedeixi que el telèfon entri en repòs." @@ -1459,8 +1463,8 @@ "Denega" "Permís sol·licitat" "S\'ha sol·licitat permís\nper al compte %s." - "Estàs utilitzant aquesta aplicació fora del perfil professional." - "Estàs utilitzant l\'aplicació al perfil professional." + "Estàs utilitzant aquesta aplicació fora del perfil de treball." + "Estàs utilitzant l\'aplicació al perfil de treball." "Mètode d\'introducció de text" "Sincronització" "Accessibilitat" @@ -1549,7 +1553,7 @@ "Comparteix amb %s" "Llisca el dit. Mantén premut." "Llisca per desbloquejar." - "Torna a la pàgina d\'inici" + "Navega fins a la pàgina d\'inici" "Navega cap amunt" "Més opcions" "%1$s, %2$s" @@ -1877,7 +1881,7 @@ "La sol·licitud SS s\'ha canviat per una videotrucada" "La sol·licitud SS s\'ha canviat per una sol·licitud USSD" "S\'ha canviat a una nova sol·licitud SS" - "Perfil professional" + "Perfil de treball" "S\'ha enviat una alerta" "Desplega" "Replega" @@ -1909,15 +1913,15 @@ "L\'aplicació no està disponible" "%1$s no està disponible en aquests moments. Aquesta opció es gestiona a %2$s." "Més informació" - "Activar el perfil professional?" - "S\'activaran les teves aplicacions per a la feina, les notificacions, les dades i altres funcions del perfil professional" + "Activar el perfil de treball?" + "S\'activaran les teves aplicacions de treball, les notificacions, les dades i altres funcions del perfil de treball" "Activa" "Aquesta aplicació es va crear per a una versió antiga d\'Android i pot ser que no funcioni correctament. Prova de cercar actualitzacions o contacta amb el desenvolupador." "Cerca actualitzacions" "Tens missatges nous" "Obre l\'aplicació d\'SMS per veure\'ls" "Algunes funcions poden ser limitades" - "Perfil professional bloquejat" + "Perfil de treball bloquejat" "Toca per desbloquejar el perfil" "S\'ha connectat a %1$s" "Toca per veure els fitxers" diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index d5e736a76b86..5a1851b05431 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -440,6 +440,8 @@ "Tyto aplikace dokážou rozpoznat vaši fyzickou aktivitu." "pořizování fotografií a videí" "Tato aplikace může pomocí fotoaparátu kdykoli pořídit snímek nebo nahrát video." + "Povolte aplikaci nebo službě přijímat zpětná volání o otevření nebo zavření zařízení s fotoaparátem." + "Tato podpisová aplikace může přijímat zpětná volání při otevírání nebo zavírání jakéhokoli zařízení s fotoaparátem (balíčkem příslušné aplikace)." "ovládání vibrací" "Umožňuje aplikaci ovládat vibrace." "přímé volání na telefonní čísla" @@ -456,9 +458,11 @@ "Umožňuje aplikace pokračovat v hovoru, který byl zahájen v jiné aplikaci." "přístup k telefonním číslům" "Umožňuje aplikaci přístup k telefonním číslům v zařízení." + "ponechání zapnuté obrazovky auta" "bránění přechodu tabletu do režimu spánku" "zabránění přechodu televize do režimu spánku" "bránění přechodu telefonu do režimu spánku" + "Umožňuje aplikaci nechat obrazovku auta zapnutou." "Umožňuje aplikaci zabránit přechodu tabletu do režimu spánku." "Umožňuje aplikaci zabránit přechodu televize do režimu spánku." "Umožňuje aplikaci zabránit přechodu telefonu do režimu spánku." diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index f4e4f7377cbf..34c899115883 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -434,6 +434,8 @@ "Denne app kan genkende din fysiske aktivitet." "tage billeder og optage video" "Med denne app kan du tage billeder og optage video med kameraet når som helst." + "Tillad, at en app eller tjeneste modtager tilbagekald om kameraenheder, der åbnes eller lukkes." + "Denne signaturapp kan modtage tilbagekald, når en kameraenhed åbnes (efter app-pakke) eller lukkes." "administrere vibration" "Tillader, at appen kan administrere vibratoren." "ringe direkte op til telefonnumre" @@ -450,9 +452,11 @@ "Tillader, at appen fortsætter et opkald, der blev startet i en anden app." "læse telefonnumre" "Tillader, at appen får adgang til telefonnumrene på denne enhed." + "hold bilens skærm tændt" "afholde tabletcomputeren fra at gå i dvale" "forhindre tv i at gå i dvale" "afholde telefonen fra at gå i dvale" + "Tillader, at appen holder bilens skærm tændt." "Tillader, at appen kan forhindre tabletten i at gå i dvale." "Giver appen lov til at forhindre fjernsynet i at gå i dvale." "Tillader, at appen kan forhindre, at telefonen går i dvale." diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 9bd46b2b828f..34de9e22a44e 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -434,6 +434,8 @@ "Diese App kann deine körperliche Aktivität erkennen." "Bilder und Videos aufnehmen" "Diese App kann mit der Kamera jederzeit Bilder und Videos aufnehmen." + "Einer App oder einem Dienst den Empfang von Callbacks erlauben, wenn eine Kamera geöffnet oder geschlossen wird." + "Diese Premium-App kann Callbacks empfangen, wenn eine Kamera mit einem Anwendungspaket geöffnet oder geschlossen wird." "Vibrationsalarm steuern" "Ermöglicht der App, den Vibrationsalarm zu steuern" "Telefonnummern direkt anrufen" @@ -450,9 +452,11 @@ "Ermöglicht der App, einen Anruf weiterzuführen, der in einer anderen App begonnen wurde." "Telefonnummern vorlesen" "Ermöglicht der App, auf die Telefonnummern auf dem Gerät zuzugreifen." + "Autodisplay eingeschaltet lassen" "Ruhezustand des Tablets deaktivieren" "Ruhemodus des Fernsehers deaktivieren" "Ruhezustand deaktivieren" + "Ermöglicht der App, das Autodisplay eingeschaltet zu lassen." "Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren" "Ermöglicht der App, den Ruhemodus des Fernsehers zu deaktivieren" "Ermöglicht der App, den Ruhezustand des Telefons zu deaktivieren" diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 9b2259034ab9..bf6559c003c9 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -434,6 +434,8 @@ "Αυτή η εφαρμογή μπορεί να αναγνωρίσει τη σωματική σας δραστηριότητα." "κάνει λήψη φωτογραφιών και βίντεο" "Αυτή η εφαρμογή μπορεί να τραβήξει φωτογραφίες και βίντεο χρησιμοποιώντας την κάμερα, ανά πάσα στιγμή." + "Επιτρέψτε σε μια εφαρμογή ή μια υπηρεσία να λαμβάνει επανάκλησεις σχετικά με το άνοιγμα ή το κλείσιμο συσκευών κάμερας." + "Αυτή η εφαρμογή υπογραφής μπορεί να λαμβάνει επανακλήσεις κατά το άνοιγμα οποιασδήποτε συσκευής κάμερας (από οποιοδήποτε πακέτο εφαρμογής) ή κατά το κλείσιμο." "ελέγχει τη δόνηση" "Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης." "πραγματοποιεί απευθείας κλήση τηλεφωνικών αριθμών" @@ -450,9 +452,11 @@ "Επιτρέπει στην εφαρμογή να συνεχίσει μια κλήση η οποία ξεκίνησε σε άλλη εφαρμογή." "ανάγνωση αριθμών τηλεφώνου" "Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση στους αριθμούς τηλεφώνου της συσκευής" + "διατήρηση ενεργοποίησης οθόνης αυτοκινήτου" "αποτρέπει την μετάβαση του tablet σε κατάσταση αδράνειας" "αποτρέπει την μετάβαση της τηλεόρασης σε κατάσταση αδράνειας" "αποτρέπει το τηλεφώνο να μεταβεί σε κατάσταση αδράνειας" + "Επιτρέπει στην εφαρμογή να διατηρεί την οθόνη του αυτοκινήτου ενεργοποιημένη." "Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας." "Επιτρέπει στην εφαρμογή να εμποδίζει τη μετάβαση της τηλεόρασης στην κατάσταση αδράνειας." "Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του τηλεφώνου σε κατάσταση αδράνειας." diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 1ace09e87796..1cd734172de6 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -434,6 +434,8 @@ "This app can recognise your physical activity." "take pictures and videos" "This app can take pictures and record videos using the camera at any time." + "Allow an application or service to receive callbacks about camera devices being opened or closed." + "This signature app can receive callbacks when any camera device is being opened (by what application package) or closed." "control vibration" "Allows the app to control the vibrator." "directly call phone numbers" @@ -450,9 +452,11 @@ "Allows the app to continue a call which was started in another app." "read phone numbers" "Allows the app to access the phone numbers of the device." + "keep car screen turned on" "prevent tablet from sleeping" "prevent TV from sleeping" "prevent phone from sleeping" + "Allows the app to keep the car screen turned on." "Allows the app to prevent the tablet from going to sleep." "Allows the app to prevent the TV from going to sleep." "Allows the app to prevent the phone from going to sleep." diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 18c4fc7ff045..bd4a247340a5 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -434,6 +434,8 @@ "This app can recognise your physical activity." "take pictures and videos" "This app can take pictures and record videos using the camera at any time." + "Allow an application or service to receive callbacks about camera devices being opened or closed." + "This signature app can receive callbacks when any camera device is being opened (by what application package) or closed." "control vibration" "Allows the app to control the vibrator." "directly call phone numbers" @@ -450,9 +452,11 @@ "Allows the app to continue a call which was started in another app." "read phone numbers" "Allows the app to access the phone numbers of the device." + "keep car screen turned on" "prevent tablet from sleeping" "prevent TV from sleeping" "prevent phone from sleeping" + "Allows the app to keep the car screen turned on." "Allows the app to prevent the tablet from going to sleep." "Allows the app to prevent the TV from going to sleep." "Allows the app to prevent the phone from going to sleep." diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 1ace09e87796..1cd734172de6 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -434,6 +434,8 @@ "This app can recognise your physical activity." "take pictures and videos" "This app can take pictures and record videos using the camera at any time." + "Allow an application or service to receive callbacks about camera devices being opened or closed." + "This signature app can receive callbacks when any camera device is being opened (by what application package) or closed." "control vibration" "Allows the app to control the vibrator." "directly call phone numbers" @@ -450,9 +452,11 @@ "Allows the app to continue a call which was started in another app." "read phone numbers" "Allows the app to access the phone numbers of the device." + "keep car screen turned on" "prevent tablet from sleeping" "prevent TV from sleeping" "prevent phone from sleeping" + "Allows the app to keep the car screen turned on." "Allows the app to prevent the tablet from going to sleep." "Allows the app to prevent the TV from going to sleep." "Allows the app to prevent the phone from going to sleep." diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 1ace09e87796..1cd734172de6 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -434,6 +434,8 @@ "This app can recognise your physical activity." "take pictures and videos" "This app can take pictures and record videos using the camera at any time." + "Allow an application or service to receive callbacks about camera devices being opened or closed." + "This signature app can receive callbacks when any camera device is being opened (by what application package) or closed." "control vibration" "Allows the app to control the vibrator." "directly call phone numbers" @@ -450,9 +452,11 @@ "Allows the app to continue a call which was started in another app." "read phone numbers" "Allows the app to access the phone numbers of the device." + "keep car screen turned on" "prevent tablet from sleeping" "prevent TV from sleeping" "prevent phone from sleeping" + "Allows the app to keep the car screen turned on." "Allows the app to prevent the tablet from going to sleep." "Allows the app to prevent the TV from going to sleep." "Allows the app to prevent the phone from going to sleep." diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index f7d058f7fe79..dc3a35ed01bf 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -434,6 +434,8 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎This app can recognize your physical activity.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‏‎take pictures and videos‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎This app can take pictures and record videos using the camera at any time.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎Allow an application or service to receive callbacks about camera devices being opened or closed.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎This signature app can receive callbacks when any camera device is being opened (by what application package) or closed.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎control vibration‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎Allows the app to control the vibrator.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎directly call phone numbers‎‏‎‎‏‎" @@ -450,9 +452,11 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‎Allows the app to continue a call which was started in another app.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎read phone numbers‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎Allows the app to access the phone numbers of the device.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‎keep car screen turned on‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎‎prevent tablet from sleeping‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎prevent TV from sleeping‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎prevent phone from sleeping‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎Allows the app to keep the car screen turned on.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎Allows the app to prevent the tablet from going to sleep.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎Allows the app to prevent the TV from going to sleep.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎Allows the app to prevent the phone from going to sleep.‎‏‎‎‏‎" diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 588b63604f2e..373b01ce2543 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -434,6 +434,8 @@ "Esta app puede reconocer tu actividad física." "tomar fotografías y grabar videos" "Esta app puede tomar fotos y grabar videos con la cámara en cualquier momento." + "Permite que una aplicación o un servicio reciba devoluciones de llamada cuando se abren o cierran dispositivos de cámara." + "Esta app de firma puede recibir devoluciones de llamada cuando se cierra o se abre cualquier dispositivo de cámara (y qué paquete de aplicación lo hace)." "controlar la vibración" "Permite que la aplicación controle la vibración." "llamar directamente a números de teléfono" @@ -450,9 +452,11 @@ "Permite que la app continúe con una llamada que se inició en otra app." "leer números de teléfono" "Le permite a la app acceder a los números de teléfono del dispositivo." + "mantener la pantalla del vehículo encendida" "evitar que el tablet entre en estado de inactividad" "evitar que la TV entre en suspensión" "evitar que el dispositivo entre en estado de inactividad" + "Permite que la app mantenga la pantalla del vehículo encendida." "Permite que la aplicación evite que la tablet entre en estado de inactividad." "Permite que la aplicación evite que la TV se suspenda." "Permite que la aplicación evite que el dispositivo entre en estado de inactividad." @@ -1220,7 +1224,7 @@ "Tienes un volcado del montón del proceso de %1$s disponible para compartir. Ten cuidado: Es posible que este volcado contenga información personal sensible (incluido el contenido que hayas escrito) a la que puede acceder el proceso." "Seleccionar una acción para el texto" "Volumen del timbre" - "Volumen de los medios" + "Volumen multimedia" "Reproduciendo a través de Bluetooth" "Tono de silencio establecido" "Volumen de llamadas entrantes" @@ -1231,7 +1235,7 @@ "Volumen de Bluetooth" "Volumen del tono de llamada" "Volumen de la llamada" - "Volumen de los medios" + "Volumen multimedia" "Volumen de notificación" "Tono predeterminado" "Predeterminado (%1$s)" diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index f52aa9f6ad77..0581942dad9f 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -434,6 +434,8 @@ "Esta aplicación puede reconocer tu actividad física." "realizar fotografías y vídeos" "Esta aplicación puede hacer fotografías y grabar vídeos con la cámara en cualquier momento." + "Permitir que una aplicación o servicio reciba retrollamadas cada vez que se abra o cierre una cámara." + "Esta aplicación especial puede recibir retrollamadas cada vez que se abre o se cierra una cámara mediante cualquier paquete de aplicaciones." "controlar la vibración" "Permite que la aplicación controle la función de vibración." "llamar directamente a números de teléfono" @@ -450,9 +452,11 @@ "Permite que la aplicación continúe una llamada que se ha iniciado en otra aplicación." "leer números de teléfono" "Permite que la aplicación acceda a los números de teléfono del dispositivo." + "mantener la pantalla del coche encendida" "impedir que el tablet entre en modo de suspensión" "evitar que la TV entre en suspensión" "impedir que el teléfono entre en modo de suspensión" + "Permite que la aplicación deje la pantalla del coche encendida." "Permite que la aplicación impida que el tablet entre en modo de suspensión." "Permite que la aplicación evite que la TV entre en modo de suspensión." "Permite que la aplicación impida que el teléfono entre en modo de suspensión." @@ -807,7 +811,7 @@ "Introduce el código PIN para desbloquear." "Código PIN incorrecto" "Para desbloquear el teléfono, pulsa la tecla de menú y, a continuación, pulsa 0." - "Número de emergencia" + "Llamada de emergencia" "Sin servicio" "Pantalla bloqueada" "Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia." @@ -1223,9 +1227,9 @@ "Volumen de multimedia" "Reproduciendo a través de Bluetooth" "Tono de silencio establecido" - "Volumen de la llamada" - "Volumen de la llamada de Bluetooth" - "Volumen de la alarma" + "Volumen de llamada" + "Volumen de llamada Bluetooth" + "Volumen de alarma" "Volumen de notificaciones" "Volumen" "Volumen de Bluetooth" diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index d420a7a90302..9e85c5e3b178 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -434,6 +434,8 @@ "See rakendus saab tuvastada teie füüsilised tegevused." "piltide ja videote tegemine" "See rakendus saab mis tahes ajal kaameraga pildistada ja videoid salvestada." + "Lubab rakendusel või teenusel kaameraseadmete avamise või sulgemise kohta tagasikutseid vastu võtta." + "See allkirjarakendus saab mis tahes kaameraseadme avamisel (vastava rakendusepaketiga) või sulgemisel tagasikutseid vastu võtta." "juhtige vibreerimist" "Võimaldab rakendusel juhtida vibreerimist." "helista otse telefoninumbritele" @@ -450,9 +452,11 @@ "Lubab rakendusel jätkata kõnet, mida alustati teises rakenduses." "lugeda telefoninumbreid" "Rakendusel lubatakse juurde pääseda seadme telefoninumbritele." + "hoida auto ekraani sisselülitatuna" "tahvelarvuti uinumise vältimine" "teleri unerežiimi lülitumise takistamine" "väldi telefoni uinumist" + "Lubab rakendusel auto ekraani sisselülitatuna hoida." "Võimaldab rakendusel vältida tahvelarvuti uinumist." "Lubab rakendusel takistada teleri unerežiimi lülitumist." "Võimaldab rakendusel vältida telefoni uinumist." diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index ddab35663835..9b08e767ae26 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -89,7 +89,7 @@ "Ezin duzu egin larrialdi-deirik Wi-Fi bidez" "Alertak" "Dei-desbideratzea" - "Larrialdi-deiak soilik jasotzeko modua" + "Larrialdi-zerbitzuen deiak jasotzeko modua" "Datu-konexioaren egoera" "SMS mezuak" "Erantzungailuko mezuak" @@ -434,6 +434,8 @@ "Aplikazioak ariketa fisikoa hauteman dezake." "atera argazkiak eta grabatu bideoak" "Aplikazioak edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko." + "Eman baimena aplikazio edo zerbitzuari jakinarazpenak jasotzeko kamerak ireki edo ixten direnean." + "Kamera ireki edo itxi dela (eta zer aplikazio-paketerekin) dioten jakinarazpenak jaso ditzake sinatzeko aplikazio honek." "kontrolatu dardara" "Bibragailua kontrolatzeko aukera ematen die aplikazioei." "deitu zuzenean telefono-zenbakietara" @@ -450,9 +452,11 @@ "Beste aplikazio batean hasitako dei bat jarraitzea baimentzen dio aplikazioari." "irakurri telefono-zenbakiak" "Gailuaren telefono-zenbakiak atzitzeko baimena ematen die aplikazioei." + "mantendu piztuta autoko pantaila" "eragotzi tableta inaktibo ezartzea" "eragotzi telebista inaktibo geratzea" "eragotzi telefonoa inaktibo ezartzea" + "Autoko pantaila piztuta mantentzeko baimena ematen dio aplikazioari." "Tableta inaktibo ezartzea galaraztea baimentzen die aplikazioei." "Telebista inaktibo ezar dadin eragoztea baimentzen die aplikazioei." "Telefonoa inaktibo ezartzea galaraztea baimentzen die aplikazioei." @@ -486,9 +490,9 @@ "Wi-Fi sarbide-puntuetara konektatzeko edo haietatik deskonektatzeko baimena ematen die aplikazioei, baita Wi-Fi sareen gailu-konfigurazioari aldaketak egitekoa ere." "onartu Wi-Fi Multicast harrera" "Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez tableta soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du." - "Wi-Fi sareko gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez telebista soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du." + "Wifi-sareko gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez telebista soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du." "Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez telefonoa soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du." - "atzitu Bluetooth ezarpenak" + "atzitu Bluetooth-aren ezarpenak" "Tokiko Bluetooth tableta konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei." "Tokiko Bluetooth telebista konfiguratzea eta urruneko gailuak hautematea eta haiekin parekatzea baimentzen die aplikazioei." "Tokiko Bluetooth telefonoa konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei." @@ -498,7 +502,7 @@ "Tableta WiMAX sareetara konektatzeko edo haietatik deskonektatzeko baimena ematen die aplikazioei." "Telebista WiMAX sareetara konektatzea edo haietatik deskonektatzea baimentzen die aplikazioei." "Telefonoa WiMAX sareetara konektatzeko edo haietatik deskonektatzeko baimena ematen die aplikazioei." - "partekatu Bluetooth gailuekin" + "partekatu Bluetooth bidezko gailuekin" "Tabletaren Bluetooth konfigurazioa ikusteko eta parekatutako gailuekin konexioak egiteko eta onartzeko baimena ematen die aplikazioei." "Telebistaren Bluetooth konexioaren konfigurazioa ikustea eta parekatutako gailuekin konexioak sortzea eta onartzea baimentzen die aplikazioei." "Telefonoaren Bluetooth konfigurazioa ikusteko eta parekatutako gailuekin konexioak egiteko eta onartzeko baimena ematen die aplikazioei." @@ -522,7 +526,7 @@ "Argazki-bilduma aldatzeko baimena ematen die aplikazioei." "multimedia-edukien bildumako kokapena irakurri" "Multimedia-edukien bildumako kokapena irakurtzeko baimena ematen die aplikazioei." - "Egiaztatu zu zarela" + "Egiaztatu zeu zarela" "Hardware biometrikoa ez dago erabilgarri" "Utzi da autentifikazioa" "Ez da ezagutu" @@ -1517,7 +1521,7 @@ "Ez egin ezer, oraingoz" "Aukeratu kontu bat" "Gehitu kontu bat" - "Gehitu kontua" + "Gehitu kontu bat" "Handitu" "Txikitu" "Eduki sakatuta %s." @@ -1604,7 +1608,7 @@ "Telefonoa" "Konektatu bozgorailuak oinarrira" "HDMI" - "Aurikularrak" + "Entzungailuak" "USB" "Sistema" "Bluetooth bidezko audioa" diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 6b0f738e3f10..94f9766253e7 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -434,6 +434,8 @@ "این برنامه نمی‌تواند فعالیت فیزیکی‌تان را تشخیص دهد." "عکسبرداری و فیلمبرداری" "این برنامه می‌تواند در هرزمانی با استفاده از دوربین عکس و فیلم بگیرد." + "مجاز کردن برنامه یا سرویس برای دریافت پاسخ تماس درباره دستگاه‌های دوربینی که باز یا بسته می‌شوند." + "این برنامهٔ امضا می‌تواند هروقت دستگاه دوربین باز (براساس بسته برنامه) یا بسته می‌شود، پاسخ تماس دریافت کند." "کنترل لرزش" "‏به برنامه اجازه می‎دهد تا لرزاننده را کنترل کند." "تماس مستقیم با شماره تلفن‌ها" @@ -450,9 +452,11 @@ "به برنامه اجازه می‌دهد تماسی را که در برنامه دیگری شروع شده ادامه دهد." "خواندن شماره تلفن‌ها" "به برنامه امکان می‌دهد به شماره تلفن‌های دستگاه دسترسی داشته باشد." + "روشن نگه داشتن صفحه‌نمایش خودرو" "ممانعت از به خواب رفتن رایانهٔ لوحی" "جلوگیری از به حالت خواب رفتن تلویزیون" "ممانعت از به خواب رفتن تلفن" + "به برنامه اجازه می‌دهد صفحه‌نمایش خودرو را روشن نگه دارد." "‏به برنامه اجازه می‎دهد تا از غیرفعال شدن رایانهٔ لوحی جلوگیری کند." "به برنامه اجازه می‌دهد تا از به حالت خواب رفتن تلویزیون جلوگیری کند." "‏به برنامه اجازه می‎دهد تا از غیرفعال شدن تلفن جلوگیری کند." diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 7e3d80ad990b..34ec6028f957 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -434,6 +434,8 @@ "Sovellus voi tunnistaa liikkumisesi." "ota kuvia ja videoita" "Tämä sovellus voi ottaa kameralla kuvia ja videoita koska tahansa." + "Salli sovelluksen tai palvelun vastaanottaa vastakutsuja kameralaitteiden avaamisesta tai sulkemisesta." + "Tämä allekirjoitussovellus voi vastaanottaa vastakutsuja, kun mikä tahansa kameralaite avataan tai suljetaan (jollakin sovelluspaketilla)" "hallita värinää" "Antaa sovelluksen hallita värinää." "soittaa puhelinnumeroihin suoraan" @@ -450,9 +452,11 @@ "Antaa sovelluksen jatkaa puhelua, joka aloitettiin toisessa sovelluksessa." "lukea puhelinnumeroita" "Anna sovelluksen käyttää laitteella olevia puhelinnumeroita." + "pitää auton näytön päällä" "estä tablet-laitetta menemästä virransäästötilaan" "Estä television siirtyminen virransäästötilaan" "estä puhelinta menemästä virransäästötilaan" + "Sallii sovelluksen pitää auton näytön päällä." "Antaa sovelluksen estää tablet-laitetta siirtymästä virransäästötilaan." "Antaa sovelluksen estää televisiota siirtymästä virransäästötilaan." "Antaa sovelluksen estää puhelinta siirtymästä virransäästötilaan." diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 23dfdb48a8ec..0ec2ef977723 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -294,7 +294,7 @@ "Autoriser <b>%1$s</b> à envoyer et à afficher des messages texte?" "Stockage" "accéder aux photos, aux contenus multimédias et aux fichiers sur votre appareil" - "Autoriser <b>%1$s</b> à accéder aux photos, aux médias et aux fichiers de votre appareil?" + "Autoriser <b>%1$s</b> à accéder aux photos, au contenu multimédia et aux fichiers de votre appareil?" "Microphone" "enregistrer des fichiers audio" "Autoriser <b>%1$s</b> à enregistrer l\'audio?" @@ -434,6 +434,8 @@ "Cette application peut reconnaître vos activités physiques." "prendre des photos et filmer des vidéos" "Cette application peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo en tout temps." + "Autoriser une application ou un service de recevoir des rappels relatifs à l\'ouverture ou à la fermeture des appareils photos." + "Cette application signature peut recevoir des rappels lorsque l\'appareil photo est ouvert ou fermé (par le paquet d\'application) en question." "gérer le vibreur" "Permet à l\'application de gérer le vibreur de l\'appareil." "appeler directement des numéros de téléphone" @@ -450,9 +452,11 @@ "Permet à l\'application de continuer un appel commencé dans une autre application." "lire les numéros de téléphone" "Permet à l\'application d\'accéder aux numéros de téléphone de l\'appareil." + "garder l\'écran de la voiture allumé" "empêcher la tablette de passer en mode veille" "empêcher le téléviseur de passer en mode veille" "empêcher le téléphone de passer en mode veille" + "Permet à l\'application de garder l\'écran de la voiture allumé." "Permet à l\'application d\'empêcher la tablette de passer en mode veille." "Permet à l\'application d\'empêcher le téléviseur à passer en mode veille." "Permet à l\'application d\'empêcher le téléphone de passer en mode veille." diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index de8f8a475a19..ea065a98e965 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -434,6 +434,8 @@ "Cette application peut reconnaître votre activité physique." "prendre des photos et enregistrer des vidéos" "Cette application peut utiliser l\'appareil photo pour prendre des photos et enregistrer des vidéos à tout moment." + "Autoriser une application ou un service à recevoir des rappels liés à l\'ouverture ou à la fermeture de caméras" + "Cette application de signature peut recevoir des rappels lorsqu\'une caméra est ouverte (par un package d\'application) ou fermée." "contrôler le vibreur" "Permet à l\'application de contrôler le vibreur." "appeler directement les numéros de téléphone" @@ -450,9 +452,11 @@ "Autorise l\'application à continuer un appel qui a été démarré dans une autre application." "lire les numéros de téléphone" "Permet à l\'application d\'accéder aux numéros de téléphone de l\'appareil." + "laisser l\'écran de la voiture allumé" "empêcher la tablette de passer en mode veille" "empêcher l\'activation du mode veille sur le téléviseur" "empêcher le téléphone de passer en mode veille" + "Permet à l\'application de laisser l\'écran de la voiture allumé." "Permet à l\'application d\'empêcher la tablette de passer en mode veille." "Permet à l\'application d\'empêcher l\'activation du mode veille sur le téléviseur." "Permet à l\'application d\'empêcher le téléphone de passer en mode veille." diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 4917ca5acb0c..f4b9308d486c 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -434,6 +434,8 @@ "Esta aplicación pode recoñecer a túa actividade física." "facer fotos e vídeos" "Esta aplicación pode utilizar a cámara en calquera momento para sacar fotos e gravar vídeos." + "Permitir que unha aplicación ou servizo reciba retrochamadas cando se abran ou se pechen dispositivos con cámara." + "Esta aplicación de sinaturas pode recibir retrochamadas cando un paquete de aplicacións abra ou peche un dispositivo con cámara." "controlar a vibración" "Permite á aplicación controlar o vibrador." "chamar directamente aos números de teléfono" @@ -450,9 +452,11 @@ "Permite que a aplicación continúe unha chamada que se iniciou noutra aplicación." "ler números de teléfono" "Permite que a aplicación acceda aos números de teléfono do dispositivo." + "manter acendida a pantalla do coche" "evitar que a tableta entre en modo de inactividade" "evitar que a televisión entre en modo de suspensión" "evitar que o teléfono entre en modo de suspensión" + "Permite que a aplicación manteña acendida a pantalla do coche." "Permite á aplicación evitar que a tableta acceda ao modo de suspensión." "Permite que a aplicación impida que a televisión entre en modo de suspensión." "Permite á aplicación evitar que o teléfono acceda ao modo de suspensión." diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 853d27f2c84b..59fd056e8c38 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -303,7 +303,7 @@ "<b>%1$s</b>ને તમારી શારીરિક પ્રવૃત્તિને ઍક્સેસ કરવાની મંજૂરી આપવી છે?" "કૅમેરો" "ચિત્રો લેવાની અને વીડિઓ રેકોર્ડ કરવાની" - "<b>%1$s</b>ને ચિત્રો લેવાની અને વીડિઓ રેકૉર્ડ કરવાની મંજૂરી આપીએ?" + "<b>%1$s</b>ને ચિત્રો લેવાની અને વીડિયો રેકૉર્ડ કરવાની મંજૂરી આપીએ?" "કૉલ લૉગ" "ફોન કૉલ લૉગ વાંચો અને લખો" "<b>%1$s</b>ને તમારા ફોનના કૉલ લૉગ ઍક્સેસ કરવાની મંજૂરી આપીએ?" @@ -434,6 +434,10 @@ "આ ઍપ તમારી શારીરિક પ્રવૃત્તિને ઓળખી શકે છે." "ચિત્રો અને વિડિઓઝ લો" "આ ઍપ્લિકેશન, કૅમેરાનો ઉપયોગ કરીને કોઈપણ સમયે ચિત્રો લઈ અને વિડિઓઝ રેકોર્ડ કરી શકે છે." + + + + "વાઇબ્રેશન નિયંત્રિત કરો" "એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે." "સીધા જ ફોન નંબર્સ પર કૉલ કરો" @@ -450,9 +454,11 @@ "એક અન્ય તૃતીય પક્ષ ઍપમાં ચાલુ થયેલા કૉલને આ ઍપમાં ચાલુ રાખવાની મંજૂરી આપે છે." "ફોન નંબર વાંચો" "ઍપ્લિકેશનને ઉપકરણનાં ફોન નંબરને ઍક્સેસ કરવાની મંજૂરી આપે છે." + "કારની સ્ક્રીન ચાલુ રાખો." "ટેબ્લેટને નિષ્ક્રિય થતું અટકાવો" "ટીવીને નિષ્ક્રિય થતો અટકાવો" "ફોનને નિષ્ક્રિય થતો અટકાવો" + "ઍપને કારની સ્ક્રીન ચાલુ રાખવાની મંજૂરી આપો." "એપ્લિકેશનને ટેબ્લેટને નિષ્ક્રિય થઈ જતો અટકાવવાની મંજૂરી આપે છે." "એપ્લિકેશનને TV ને નિષ્ક્રિય થઈ જતો અટકાવવાની મંજૂરી આપે છે." "એપ્લિકેશનને ફોનને નિષ્ક્રિય થઈ જતો અટકાવવાની મંજૂરી આપે છે." diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index d63817b0be45..9e4e6d9e5b1c 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -434,6 +434,10 @@ "यह ऐप्लिकेशन आपके शरीर की गतिविधि को पहचान सकता है." "चित्र और वीडियो लें" "यह ऐप्लिकेशन किसी भी समय कैमरे का उपयोग करके चित्र ले सकता है और वीडियो रिकॉर्ड कर सकता है." + + + + "कंपन (वाइब्रेशन) को नियंत्रित करें" "ऐप्स को कंपनकर्ता नियंत्रित करने देता है." "फ़ोन नंबर पर सीधे कॉल करें" @@ -450,9 +454,11 @@ "इसके ज़रिए आप, किसी ऐप्लिकेशन में शुरू किया गया कॉल दूसरे ऐप्लिकेशन में जारी रख सकते हैं." "फ़ोन नंबर पढ़ना" "ऐप को डिवाइस के फ़ोन नंबर का इस्तेमाल करने देती है." + "कार की स्क्रीन चालू रखना" "टैबलेट को सोने (कम बैटरी मोड) से रोकें" "टीवी को सोने (कम बैटरी मोड) से रोकें" "फ़ोन को सोने (कम बैटरी मोड) से रोकें" + "यह अनुमति देने पर, ऐप्लिकेशन कार की स्क्रीन चालू रख पाएगा." "ऐप्स को टैबलेट को प्रयोग में नहीं हो जाने से रोकता है." "ऐप को टीवी को सोने (कम बैटरी मोड) से रोकने की अनुमति देता है." "ऐप्स को फ़ोन को प्रयोग में नहीं होने से रोकता है." diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index b89451aa610e..3c612f0ac50c 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -437,6 +437,8 @@ "Ova aplikacija može prepoznati vašu tjelesnu aktivnost." "snimi fotografije i videozapise" "Aplikacija u svakom trenutku može snimati fotografije i videozapise fotoaparatom." + "Dopustite aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju fotoaparata." + "Aplikacija za potpise može primati povratne pozive prilikom otvaranja (putem nekog paketa aplikacija) ili zatvaranja fotoaparata." "upravljanje vibracijom" "Aplikaciji omogućuje nadzor nad vibratorom." "izravno pozivanje telefonskog broja" @@ -453,9 +455,11 @@ "Omogućuje aplikaciji da nastavi poziv započet u nekoj drugoj aplikaciji." "čitati telefonske brojeve" "Aplikaciji omogućuje da pristupi telefonskim brojevima na uređaju." + "zadržati zaslon automobila uključenim" "spriječi mirovanje tabletnog uređaja" "sprječavanje mirovanja televizora" "sprečava telefon da prijeđe u stanje mirovanja" + "Aplikaciji omogućuje da zaslon automobila zadrži uključenim." "Aplikaciji omogućuje sprječavanje prelaska tabletnog računala u mirovanje." "Aplikaciji omogućuje sprječavanje prelaska televizora u stanje mirovanja." "Aplikaciji omogućuje da spriječi prelazak telefona u mirovanje." diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 2dbb70ebc483..315f0f8c6e1f 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -434,6 +434,8 @@ "Az alkalmazás képes felismerni a testmozgást." "fotók és videók készítése" "Az alkalmazás a kamera használatával bármikor készíthet fényképeket és rögzíthet videókat." + "Visszahívás fogadásának engedélyezése alkalmazás vagy szolgáltatás számára, ha a kamerákat megnyitják vagy bezárják." + "Az aláíró alkalmazás fogadhat visszahívásokat bármelyik kamera (adott alkalmazáscsomag általi) megnyitásakor vagy bezárásakor." "rezgés szabályozása" "Lehetővé teszi az alkalmazás számára a rezgés vezérlését." "telefonszámok közvetlen hívása" @@ -450,9 +452,11 @@ "Engedélyezi az alkalmazásnak, hogy folytassa a hívást, amelyet valamelyik másik alkalmazásban kezdtek meg." "telefonszámok olvasása" "Engedélyezi az alkalmazás számára az eszköz telefonszámaihoz való hozzáférést." + "az autó képernyőjének bekapcsolva tartása" "táblagép alvás üzemmódjának megakadályozása" "a tévé alvó üzemmódba való lépésének megakadályozása" "telefon alvó üzemmódjának megakadályozása" + "Lehetővé teszi az alkalmazás számára az autó képernyőjének bekapcsolva tartását." "Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a táblagép alvó üzemmódra váltson." "Lehetővé teszi az alkalmazás számára azt, hogy megakadályozza a tévé alvó üzemmódba való lépését." "Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a telefon alvó üzemmódra váltson." diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 401e27428224..67ac61a6dd50 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -434,6 +434,8 @@ "Հավելվածը կարող է ճանաչել ձեր ֆիզիկական ակտիվությունը:" "լուսանկարել և տեսանկարել" "Այս հավելվածը կարող է ցանկացած պահի լուսանկարել և տեսագրել՝ օգտագործելով տեսախցիկը:" + "Թույլատրել հավելվածին կամ ծառայությանը հետզանգեր ստանալ՝ տեսախցիկների բացվելու և փակվելու դեպքում։" + "Ստորագրությունների այս հավելվածը կարող է հետզանգեր ստանալ՝ ցանկացած տեսախցիկի բացվելու (կնշվի բացող հավելվածը) և փակվելու դեպքում։" "կառավարել թրթռումը" "Թույլ է տալիս հավելվածին կառավարել թրթռոցը:" "ուղղակիորեն զանգել հեռախոսահամարներին" @@ -450,9 +452,11 @@ "Թույլ է տալիս հավելվածին շարունակել մեկ այլ հավելվածի միջոցով սկսած զանգը:" "օգտագործել հեռախոսահամարները" "Հավելվածին թույլ է տալիս օգտագործել սարքի հեռախոսահամարները:" + "միացրած թողնել մեքենայի էկրանը" "զերծ պահել պլանշետը քնելուց" "թույլ չտալ հեռուստացույցին մտնել քնի ռեժիմ" "կանխել հեռախոսի քնի ռեժիմին անցնելը" + "Հավելվածին թույլ է տալիս միացրած թողնել մեքենայի էկրանը։" "Թույլ է տալիս հավելվածին կանխել պլանշետի` քնի ռեժիմին անցնելը:" "Թույլ է տալիս հավելվածին կանխել, որ հեռուստացույցը մտնի քնի ռեժիմ:" "Թույլ է տալիս հավելվածին կանխել հեռախոսի` քնի ռեժիմին անցնելը:" @@ -645,7 +649,7 @@ "Ծրագրին թույլ է տալիս ստանալ Android Beam-ով ընթացիկ փոխանցումների մասին տեղեկատվություն:" "հեռացնել DRM վկայագրեր" "Ծրագրին թույլ է տալիս հեռացնել DRM վկայագրեր: Սովորական ծրագրերի համար երբեք պետք չի գալիս:" - "Կապակցում օպերատորի հաղորդագրությունների ծառայության հետ" + "Միացում օպերատորի հաղորդագրությունների ծառայության հետ" "Թույլ է տալիս տիրոջը կապվել օպերատորի հաղորդագրությունների ծառայության վերին մակարդակի միջերեսի հետ: Սա երբեք չի պահանջվում սովորական հավելվածների համար:" "կապվել օպերատորի ծառայություններին" "Թույլ է տալիս սեփականատիրոջը կապվել օպերատորի ծառայություններին: Սովորական հավելվածների դեպքում չի պահանջվում:" @@ -1592,7 +1596,7 @@ "Ընտրել գործունեությունը" "Կիսվել" "Ուղարկվում է..." - "Գործարկե՞լ զննարկիչը:" + "Գործարկե՞լ դիտարկիչը:" "Ընդունե՞լ զանգը:" "Միշտ" "Միշտ բացել" diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index dc2ca1f8c39c..4f32666363b5 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -89,7 +89,7 @@ "Tidak dapat melakukan panggilan darurat melalui Wi-Fi" "Notifikasi" "Penerusan panggilan" - "Mode panggilan balik darurat" + "Mode telepon balik darurat" "Status data seluler" "Pesan SMS" "Notifikasi pesan suara" @@ -434,6 +434,8 @@ "Aplikasi ini dapat mengenali aktivitas fisik Anda." "ambil gambar dan video" "Aplikasi ini dapat mengambil foto dan merekam video menggunakan kamera kapan saja." + "Izinkan aplikasi atau layanan untuk menerima callback tentang perangkat kamera yang sedang dibuka atau ditutup." + "Aplikasi tanda tangan ini dapat menerima callback saat perangkat kamera sedang dibuka (oleh paket aplikasi) atau ditutup." "kontrol getaran" "Mengizinkan aplikasi untuk mengendalikan vibrator." "panggil nomor telepon secara langsung" @@ -450,9 +452,11 @@ "Mengizinkan aplikasi melanjutkan panggilan yang dimulai di aplikasi lain." "membaca nomor telepon" "Mengizinkan aplikasi mengakses nomor telepon perangkat." + "tetap aktifkan layar mobil" "cegah tablet dari tidur" "cegah agar TV tidak tidur" "mencegah ponsel menjadi tidak aktif" + "Mengizinkan aplikasi untuk menjaga agar layar mobil tetap aktif." "Mengizinkan apl mencegah tablet tidur." "Mengizinkan aplikasi untuk mencegah agar TV tidak tidur." "Mengizinkan apl mencegah ponsel tidur." diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 4bcbaedd1796..340d8a5067de 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -434,6 +434,8 @@ "Þetta forrit getur greint hreyfingu þína." "taka myndir og myndskeið" "Þetta forrit getur tekið myndir og tekið upp myndskeið með myndavélinni hvenær sem er." + "Leyfa forriti eða þjónustu að taka við svörum um myndavélar sem verið er að opna eða loka." + "Þetta undirritunarforrit getur tekið við svörum þegar verið er að opna (með forritapakka) eða loka hvaða myndavél sem er." "stjórna titringi" "Leyfir forriti að stjórna titraranum." "hringja beint í símanúmer" @@ -450,9 +452,11 @@ "Leyfir forritinu að halda áfram með símtal sem hófst í öðru forriti." "lesa símanúmer" "Veitir forritinu aðgang að símanúmerum tækisins." + "hafa kveikt á skjá bílsins" "koma í veg fyrir að spjaldtölvan fari í biðstöðu" "koma í veg fyrir að sjónvarpið fari í biðstöðu" "koma í veg fyrir að síminn fari í biðstöðu" + "Gerir forritinu kleift að hafa kveikt á skjá bílsins." "Leyfir forriti að koma í veg fyrir að spjaldtölvan fari í biðstöðu." "Leyfir forriti að koma í veg fyrir að sjónvarpið fari í biðstöðu." "Leyfir forriti að koma í veg fyrir að síminn fari í biðstöðu." diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index a750669ab8fc..4f3f735fd7f4 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -434,6 +434,8 @@ "Questa app può riconoscere la tua attività fisica." "acquisizione di foto e video" "Questa app può scattare foto e registrare video tramite la fotocamera in qualsiasi momento." + "Consenti a un\'applicazione o a un servizio di ricevere callback relativi all\'apertura o alla chiusura di videocamere." + "Questa app di firma può ricevere callback quando viene aperta (dal pacchetto dell\'applicazione) o chiusa qualsiasi videocamera." "controllo vibrazione" "Consente all\'applicazione di controllare la vibrazione." "chiamata diretta n. telefono" @@ -450,9 +452,11 @@ "Consente all\'app di continuare una chiamata che è stata iniziata in un\'altra app." "lettura dei numeri di telefono" "Consente all\'app di accedere ai numeri di telefono del dispositivo." + "Mantenere attivo lo schermo dell\'auto" "disattivazione stand-by del tablet" "disattivazione della modalità di sospensione della TV" "disattivazione stand-by del telefono" + "Consente all\'app di mantenere attivo lo schermo dell\'auto." "Consente all\'applicazione di impedire lo stand-by del tablet." "Consente all\'app di impedire l\'attivazione della modalità di sospensione della TV." "Consente all\'applicazione di impedire lo stand-by del telefono." @@ -1187,7 +1191,7 @@ "Mostra sempre" "L\'app %1$s è stata realizzata per una versione non compatibile del sistema operativo Android e potrebbe avere un comportamento imprevisto. Potrebbe essere disponibile una versione aggiornata dell\'app." "Mostra sempre" - "Verifica la presenza di aggiornamenti" + "Cerca aggiornamenti" "L\'applicazione %1$s (processo %2$s) ha violato la norma StrictMode autoimposta." "Il processo %1$s ha violato la norma StrictMode autoimposta." "Aggiornamento del telefono…" @@ -1913,7 +1917,7 @@ "Le tue app di lavoro, le notifiche, i dati e altri elementi del profilo di lavoro saranno attivati." "Attiva" "Questa app è stata realizzata per una versione precedente di Android e potrebbe non funzionare correttamente. Prova a verificare la disponibilità di aggiornamenti o contatta lo sviluppatore." - "Verifica la presenza di aggiornamenti" + "Cerca aggiornamenti" "Hai nuovi messaggi" "Apri l\'app SMS per la visualizzazione" "Alcune funzionalità sono limitate" diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 35039f2ebc4d..196cf46b2356 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -440,6 +440,8 @@ "האפליקציה מזהה את הפעילות הגופנית שלך." "צלם תמונות וסרטונים" "אפליקציה זו יכולה להשתמש במצלמה כדי לצלם תמונות ולהקליט סרטונים בכל עת." + "‏אפליקציה או שירות יוכלו לקבל קריאות חוזרות (callback) כשמכשירי מצלמה ייפתחו או ייסגרו." + "‏אפליקציית הפרימיום הזו יכולה לקבל קריאות חוזרות (callback) כשמכשיר מצלמה כלשהו נפתח (באמצעות חבילת אפליקציה) או נסגר." "שליטה ברטט" "מאפשר לאפליקציה לשלוט ברטט." "התקשר ישירות למספרי טלפון" @@ -456,9 +458,11 @@ "הרשאה זו מתירה לאפליקציה להמשיך שיחה שהחלה באפליקציה אחרת." "גישה למספרי הטלפון" "מתירה לאפליקציה גישה למספרי הטלפון במכשיר." + "מסך המכונית יישאר דלוק" "מנע מהטאבלט לעבור למצב שינה" "מניעת מעבר למצב שינה בטלוויזיה" "מניעת מעבר הטלפון למצב שינה" + "מסך המכונית יישאר דלוק כשהאפליקציה פועלת." "מאפשר לאפליקציה למנוע מהטאבלט לעבור למצב שינה." "מאפשרת לאפליקציה למנוע מהטלוויזיה לעבור למצב שינה." "מאפשר לאפליקציה למנוע מהטלפון לעבור למצב שינה." diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 6441fecccb05..ef64d4403f4e 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -434,6 +434,8 @@ "このアプリで身体活動が認識されるようにします。" "写真と動画の撮影" "このアプリは、いつでもカメラを使用して写真や動画を撮影できます。" + "カメラデバイスが起動または終了したときにコールバックを受け取ることを、アプリまたはサービスに許可してください。" + "この署名アプリを使用すると、カメラデバイスが(なんらかのアプリ パッケージによって)起動するとき、または終了するときにコールバックを受け取ることができます。" "バイブレーションの制御" "バイブレーションの制御をアプリに許可します。" "電話番号発信" @@ -450,9 +452,11 @@ "別のアプリで通話を続行することをこのアプリに許可します。" "電話番号の読み取り" "デバイスの電話番号へのアクセスをアプリに許可します。" + "車の画面を常にオンにする" "タブレットのスリープを無効化" "テレビのスリープを無効化" "デバイスのスリープを無効にする" + "車の画面を常にオンにすることをアプリに許可します。" "タブレットのスリープを無効にすることをアプリに許可します。" "テレビのスリープを無効にすることをアプリに許可します。" "モバイル デバイスのスリープを無効にすることをアプリに許可します。" @@ -1817,8 +1821,8 @@ "管理者により更新されています" "管理者により削除されています" "OK" - "電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する\n\n""詳細" - "電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマをオンにする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する" + "電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマを ON にする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能を OFF にする、または制限する\n\n""詳細" + "電池を長持ちさせるためにバッテリー セーバーが行う操作:\n·ダークテーマを ON にする\n·バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能を OFF にする、または制限する" "データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータにアクセスすることはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。" "データセーバーを ON にしますか?" "ON にする" diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 40e9a1e52827..2d6c9f65e855 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -434,6 +434,8 @@ "ამ აპს შეუძლია თქვენი ფიზიკური აქტივობის ამოცნობა." "სურათებისა და ვიდეოების გადაღება" "ამ აპს ნებისმიერ დროს შეუძლია კამერით სურათების გადაღება და ვიდეოების ჩაწერა." + "ნება დაერთოს აპლიკაციას ან სერვისს, მიიღოს გადმორეკვები კამერის მოწყობილობის გახსნის ან დახურვისას." + "ამ მინაწერის აპს შეუძლია მიიღოს გადმორეკვები, როდესაც რომელიმე კამერის მოწყობილობა იხსნება (რომელიმე აპლიკაციის პაკეტით) ან იხურება." "ვიბრაციის კონტროლი" "აპს შეეძლება, მართოს ვიბრირება." "პირდაპირი დარეკვა ტელეფონის ნომრებზე" @@ -450,9 +452,11 @@ "ნებას რთავს აპს, გააგრძელოს ზარი, რომელიც სხვა აპშია წამოწყებული." "ტელეფონის ნომრების წაკითხვა" "აპს მოწყობილობის ტელეფონის ნომრებზე წვდომის საშუალებას მისცემს." + "ჩართული ჰქონდეს მანქანის ეკრანი" "დაიცავით ტაბლეტი დაძინებისგან" "ტელევიზორის დაცვა დაძინებისაგან" "ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა" + "ნებას რთავს აპს, ჩართული ჰქონდეს მანქანის ეკრანი." "აპს შეეძლება ხელი შეუშალოს ტაბლეტის დაძინებას." "ნებას რთავს აპლიკაციას დაიცვას ტელევიზორი დაძინებისაგან." "აპს შეეძლება ხელი შეუშალოს ტელეფონის დაძინებას." diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 4c4f36d5cd40..e56670b4aefc 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -434,6 +434,8 @@ "Бұл қолданба физикалық әрекетті тани алады." "фотосурет жасау және бейне жазу" "Бұл қолданба кез келген уақытта камерамен суретке түсіруі және бейнелерді жазуы мүмкін." + "Қолданбаға не қызметке ашылып не жабылып жатқан камера құрылғылары туралы кері шақыру алуға рұқсат ету" + "Кез келген камера ашылып (көрсетілген қолданба пакеті арқылы) не жабылып жатқанда, бұл қолтаңба қолданбасы кері шақыру алады." "тербелісті басқару" "Қолданбаға вибраторды басқаруға рұқсат береді." "нөмірлерге тікелей телефон шалу" @@ -450,9 +452,11 @@ "Қолданбаға басқа қолданбадағы қоңырауды жалғастыруға рұқсат береді." "телефон нөмірлерін оқу" "Қолданбаға құрылғының телефон нөмірлерін алуға мүмкіндік береді." + "көлік экранын қосулы күйде ұстау" "планшетті ұйқыдан бөгеу" "ТД ұйықтауын болдырмау" "телефонды ұйқыдан бөгеу" + "Қолданбаға көлік экранын қосулы күйде ұстауға мүмкіндік береді." "Қолданбаға планшеттің ұйқыға кетуін болдырмауға рұқсат береді." "Қолданбаға ТД ұйқыға кетуін болдырауға рұқсат етеді." "Қолданбаға телефонның ұйқыға кетуін болдырмауға рұқсат береді." diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 152379ae493d..946c99144444 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -434,6 +434,8 @@ "កម្មវិធីនេះ​អាចស្គាល់សកម្មភាព​រាងកាយ​របស់អ្នក។" "ថត​រូប និងវីដេអូ" "កម្មវិធី​នេះ​អាច​ថត​រូប​ និង​ថត​វីដេអូ​ ដោយ​ប្រើ​កាមេរ៉ា​បាន​គ្រប់​ពេល​។" + "អនុញ្ញាតឱ្យកម្មវិធី ឬសេវាកម្ម​ទទួលការហៅត្រឡប់វិញអំពី​កាមេរ៉ាដែលកំពុងបិទ ឬបើក។" + "កម្មវិធីពិសេសនេះ​អាចទទួលការហៅត្រឡប់វិញបាន នៅពេលកំពុងបិទ ឬបើកកាមេរ៉ា (ដោយកញ្ចប់កម្មវិធី)។" "ពិនិត្យ​ការ​ញ័រ" "ឲ្យ​កម្មវិធី​គ្រប់គ្រង​កម្មវិធី​ញ័រ។" "ហៅ​លេខ​ទូរស័ព្ទ​ដោយ​ផ្ទាល់" @@ -450,9 +452,11 @@ "អនុញ្ញាត​ឱ្យ​កម្មវិធី​បន្ត​ការ​ហៅ​ទូរសព្ទ​ ដែល​បាន​ចាប់ផ្តើម​នៅក្នុង​កម្មវិធី​ផ្សេង​។" "អាន​លេខ​ទូរសព្ទ" "អនុញ្ញាត​ឲ្យ​កម្មវិធីនេះ​ចូលប្រើប្រាស់​លេខទូរសព្ទ​របស់​ឧបករណ៍​នេះ។" + "បន្តបើក​អេក្រង់​រថយន្ត" "ការពារ​​កុំព្យូទ័រ​បន្ទះ​មិន​ឲ្យ​ដេក" "បង្ការទូរទស្សន៍ពីការបិទពន្លឺ" "ការ​ពារ​ទូរស័ព្ទ​មិន​ឲ្យ​ដេក" + "អនុញ្ញាតឱ្យ​កម្មវិធី​បន្តបើក​អេក្រង់​រថយន្ត។" "ឲ្យ​​កម្មវិធី​ការពារ​កុំព្យូទ័រ​បន្ទះ​មិន​ឲ្យ​ដេក។" "អនុញ្ញាតឲ្យកម្មវិធីបង្ការទូរទស្សន៍ពីការបិទពន្លឺ។" "ឲ្យ​កម្មវិធី​ការពារ​ទូរស័ព្ទ​មិន​ឲ្យ​ដេក។" diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 71185c1e46b0..cf5572d6865f 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -434,6 +434,10 @@ "ಈ ಆ್ಯಪ್‌ ನಿಮ್ಮ ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಗುರುತಿಸಬಹುದು." "ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ" "ಈ ಅಪ್ಲಿಕೇಶನ್ ಯಾವ ಸಮಯದಲ್ಲಾದರೂ ಕ್ಯಾಮರಾ ಬಳಸಿಕೊಂಡು ಚಿತ್ರಗಳು ಮತ್ತು ವಿಡಿಯೋಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು." + + + + "ವೈಬ್ರೇಷನ್‌‌ ನಿಯಂತ್ರಿಸಿ" "ವೈಬ್ರೇಟರ್‌ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ." "ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ನೇರವಾಗಿ ಕರೆ ಮಾಡಿ" @@ -450,9 +454,11 @@ "ಮತ್ತೊಂದು ಅಪ್ಲಿಕೇಶನ್‌ನಲ್ಲಿ ಪ್ರಾರಂಭವಾದ ಕರೆಯನ್ನು ಮುಂದುವರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡಿ." "ಫೋನ್‌ ಸಂಖ್ಯೆಗಳನ್ನು ಓದಿ" "ಸಾಧನದ ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ಪ್ರವೇಶ ಪಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ." + "ಕಾರ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್‌ನಲ್ಲೇ ಇರಿಸಿ" "ಟ್ಯಾಬ್ಲೆಟ್ ನಿದ್ರಾವಸ್ಥೆಯನ್ನು ತಡೆಯಿರಿ" "ಟಿವಿಗೆ ನಿದ್ರಿಸುವುದನ್ನು ತಪ್ಪಿಸಿ" "ಫೋನ್ ಆಫ್ ಆಗುವುದರಿಂದ ತಡೆಯಿರಿ" + "ಕಾರ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆನ್‌ನಲ್ಲೇ ಇರಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ." "ಟ್ಯಾಬ್ಲೆಟ್‌ ನಿದ್ರೆಗೆ ಹೋಗುವುದನ್ನು ತಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ." "ಟಿವಿ ನಿದ್ರೆಗೆ ಹೋಗುವುದನ್ನು ತಡೆಗಟ್ಟಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ." "ಫೋನ್‌ ನಿದ್ರೆಗೆ ಹೋಗುವುದನ್ನು ತಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ." @@ -874,7 +880,7 @@ "ಪ್ಯಾಟರ್ನ್ ಪೂರ್ಣಗೊಂಡಿದೆ" "ಪ್ಯಾಟರ್ನ್ ಪ್ರದೇಶ." "%1$s.%3$d ರಲ್ಲಿ %2$d ವಿಜೆಟ್." - "ವಿಜೆಟ್ ಸೇರಿಸು." + "ವಿಜೆಟ್ ಸೇರಿಸಿ." "ಖಾಲಿ" "ಅನ್‌ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ವಿಸ್ತರಿಸಲಾಗಿದೆ." "ಅನ್‌ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ಸಂಕುಚಿಸಲಾಗಿದೆ." diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 278fac58c932..712226c4d5b8 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -434,6 +434,8 @@ "이 앱에서 내 신체 활동을 확인할 수 있습니다." "사진과 동영상 찍기" "이 앱은 언제든지 카메라를 사용하여 사진을 촬영하고 동영상을 녹화할 수 있습니다." + "애플리케이션 또는 서비스에서 카메라 기기 열림 또는 닫힘에 대한 콜백을 수신하도록 허용" + "이 서명 앱은 사용되는 애플리케이션 패키지와 관련 없이 카메라 기기가 열릴 때나 닫힐 때 콜백을 수신할 수 있습니다." "진동 제어" "앱이 진동을 제어할 수 있도록 허용합니다." "전화번호 자동 연결" @@ -450,9 +452,11 @@ "다른 앱에서 수신한 전화를 계속하려면 앱을 허용합니다." "전화번호 읽기" "앱에서 기기의 전화번호에 액세스하도록 허용합니다." + "차량 화면 켜진 상태로 유지" "태블릿이 절전 모드로 전환되지 않도록 설정" "TV의 절전 모드 전환 방지" "휴대전화가 절전 모드로 전환되지 않도록 설정" + "앱에서 차량 화면을 켜진 상태로 유지하도록 허용합니다." "앱이 태블릿의 절전 모드 전환을 막도록 허용합니다." "앱이 TV가 절전 모드로 전환되는 것을 방지할 수 있도록 허용합니다." "앱이 휴대전화의 절전 모드 전환을 막도록 허용합니다." diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 161e4e6cb8f0..41569d58215a 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -184,12 +184,12 @@ "Аныкталбаган үчүнчү тараптардан" "Жумуш профилиңиздин администратору тарабынан" "%s тарабынан" - "Жумуш профили жок кылынды" - "Жумуш профилинин башкаруучу колдонмосу жок же бузулгандыктан, жумуш профилиңиз жана ага байланыштуу дайындар жок кылынды. Жардам алуу үчүн администраторуңузга кайрылыңыз." - "Жумуш профилиңиз бул түзмөктөн жок кылынды" + "Жумуш профили өчүрүлдү" + "Жумуш профилинин башкаруучу колдонмосу жок же бузулгандыктан, жумуш профилиңиз жана ага байланыштуу дайындар өчүрүлдү. Жардам алуу үчүн администраторуңузга кайрылыңыз." + "Жумуш профилиңиз бул түзмөктөн өчүрүлдү" "Өтө көп жолу сырсөздү киргизүү аракети жасалды" "Түзмөктү ишкана башкарат" - "Ишканаңыз бул түзмөктү башкарат жана тармак трафигин көзөмөлдөшү мүмкүн. Чоо-жайын көрүү үчүн таптап коюңуз." + "Ишканаңыз бул түзмөктү башкарат жана тармак трафигин көзөмөлдөшү мүмкүн. Чоо-жайын билгиңиз келсе, таптап коюңуз." "Түзмөгүңүз тазаланат" "Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз." "Басып чыгаруу %s тарабынан өчүрүлдү." @@ -434,12 +434,14 @@ "Бул колдонмо кыймыл-аракетиңизди аныктап турат." "сүрөт жана видео тартуу" "Бул колдонмо каалаган убакта камера менен сүрөт же видеолорду тарта алат." + "Колдонмого же кызматка камера ачылып же жабылып жатканда чалууларды кабыл алууга уруксат берүү." + "Бул колдонмо камера ачылып же жабылып жатканда (колдонмонун таңгагы) чалууларды кабыл алат." "титирөөнү башкаруу" "Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет." "телефон номерлерине түз чалуу" "Колдонмого сиздин катышууңузсуз телефон номурларга чалуу уруксатын берет. Бул сиз күтпөгөн чыгымдарга же чалууларга алып келиши мүмкүн. Бул куткаруучулардын номурларына чалууга уруксат бербей тургандыгын эске алыңыз. Зыяндуу колдонмолор, сиздин ырастооңузсуз чалууларды аткарып, көп чыгымдарга себепкер болушу мүмкүн." "IMS чалуу кызматына мүмкүнчүлүк алуу" - "Колдонмого сизди катыштырбай туруп, IMS кызматынын жардамы менен чалууларды жасоо мүмкүнчүлүгүн берет." + "Колдонмого сизди катыштырбай туруп, IMS кызматынын жардамы менен, чалууларды жасоо мүмкүнчүлүгүн берет." "телефондун абалын жана аныктыгын окуу" "Колдонмого түзмөктүн чалуу мүмкүнчүлүктөрүнө жетки алуу уруксатын берет. Бул уруксат колдонмого, телефондун номурун, түзмөктүн ID-син, чалуунун абалын жана байланышта чыккан номурду аныктоого жол берет." "чалууларды тутум аркылуу өткөрүү" @@ -450,9 +452,11 @@ "Башка колдонмодон аткарылган чалууну бул колдонмодо улантууга уруксат берүү." "телефон номерлерин окуу" "Колдонмого түзмөктүн телефон номерлерин окуу мүмкүнчүлүгү берилет." + "унаанын экранын күйгүзүлгөн бойдон калтыруу" "планшетти уктатпай сактоо" "сыналгыны көшүтпөө" "телефонду уктатпай сактоо" + "Колдонмого унаанын экранын күйгүзүлгөн бойдон калтырууга уруксат берет." "Колдонмо планшетти көшүү режимине өткөрбөйт." "Колдонмо сыналгыны көшүү режимине өткөрбөйт." "Колдонмо телефонду көшүү режимине өткөрбөйт." @@ -528,11 +532,11 @@ "Таанылган жок" "Аныктыгын текшерүү жокко чыгарылды" "PIN код, графикалык ачкыч же сырсөз коюлган жок" - "Манжа изи жарым-жартылай аныкталды. Кайра аракет кылыңыз." - "Манжа изи иштелбей койду. Кайра аракет кылыңыз." - "Манжа изинин сенсору кирдеп калган. Тазалап, кайра аракет кылыңыз." - "Манжа өтө тез жылдырылды. Кайра аракет кылыңыз." - "Манжа өтө жай жылды. Кайра аракет кылыңыз." + "Манжа изи жарым-жартылай аныкталды. Кайталап көрүңүз." + "Манжа изи иштелбей койду. Кайталап көрүңүз." + "Манжа изинин сенсору кирдеп калган. Тазалап, кайталап көрүңүз." + "Манжа өтө тез жылдырылды. Кайталап көрүңүз." + "Манжа өтө жай жылды. Кайталап көрүңүз." "Манжа изи текшерилди" @@ -540,10 +544,10 @@ "Жүздүн аныктыгы текшерилди, эми \"Ырастоону\" басыңыз" "Манжа изинин аппараттык камсыздоосу жеткиликтүү эмес." "Манжа изин сактоо мүмкүн эмес. Учурдагы манжа изин алып салыңыз." - "Манжа изин күтүү мөөнөтү бүттү. Кайра аракет кылыңыз." + "Манжа изин күтүү мөөнөтү бүттү. Кайталап көрүңүз." "Манжа изи иш-аракети жокко чыгарылды." "Манжа изи операциясын колдонуучу жокко чыгарды." - "Аракеттер өтө көп болду. Кийинчерээк кайра аракет кылыңыз." + "Аракеттер өтө көп болду. Бир аздан кийин кайталап көрүңүз." "Өтө көп жолу аракет жасадыңыз. Манжа изинин сенсору өчүрүлдү." "Кайра бир аракеттениңиз." "Бир да манжа изи катталган эмес." @@ -559,7 +563,7 @@ "Жүзүнөн таануу" "Жүзүңүздү кайра таанытыңыз." "Мыкты таануу үчүн, жүзүңүздү кайра таанытыңыз" - "Жүзүңүз жакшы тартылган жок. Кайра аракет кылыңыз." + "Жүзүңүз жакшы тартылган жок. Кайталап көрүңүз." "Өтө жарык. Жарыктыкты азайтып көрүңүз." "Өтө караңгы. Жарыгыраак жерден тартып көрүңүз." "Телефонду алысыраак жылдырыңыз." @@ -572,7 +576,7 @@ "Телефонду жүзүңүздүн маңдайында кармаңыз." "Кыймылдап жибердиңиз. Телефонду түз кармаңыз." "Жүзүңүздү кайра таанытыңыз." - "Жүз таанылган жок. Кайра аракет кылыңыз." + "Жүз таанылган жок. Кайталап көрүңүз." "Мурункуга окшош болуп калды, башкача туруңуз." "Башыңызды бир аз гана эңкейтиңиз." "Башыңызды бир аз гана эңкейтиңиз." @@ -586,9 +590,9 @@ "Жаңы жүздү сактоо мүмкүн эмес. Адегенде эскисин өчүрүңүз." "Жүздүн аныктыгын текшерүү жокко чыгарылды." "Жүзүнөн таануу функциясын колдонуучу өчүрүп салды." - "Өтө көп жолу аракет жасадыңыз. Кийинчерээк кайра аракет кылыңыз." + "Өтө көп жолу аракет жасадыңыз. Бир аздан кийин кайталап көрүңүз." "Өтө көп жолу аракет кылдыңыз. Жүзүнөн таануу функциясы өчүрүлдү." - "Жүз ырасталбай жатат. Кайра аракет кылыңыз." + "Жүз ырасталбай жатат. Кайталап көрүңүз." "Жүзүнөн таануу функциясын жөндөй элексиз." "Жүзүнөн таануу функциясы бул түзмөктө иштебейт." "Жүз %d" @@ -847,9 +851,9 @@ "Кулпуну ачуу үлгүсүн %1$d жолу туура эмес тарттыңыз. Дагы %2$d жолу туура эмес тартсаңыз, планшетиңиздин кулпусун Google\'га кирип ачууга туура келет.\n\n %3$d секундадан кийин дагы аракет кылып көрүңүз." "Кулпуну ачуу үлгүсүн %1$d жолу туура эмес тарттыңыз. Дагы %2$d жолу туура эмес тартсаңыз, сыналгыңыздын кулпусун Google\'га кирип ачууга туура келет.\n\n %3$d секундадан кийин дагы аракет кылып көрүңүз." "Кулпуну ачуу үлгүсүн %1$d жолу туура эмес тарттыңыз. Дагы %2$d жолу туура эмес тартсаңыз, телефонуңуздун кулпусун Google\'га кирип ачууга туура келет.\n\n %3$d секундадан кийин дагы аракет кылып көрүңүз." - "Сиз планшетиңизди бөгөттөн чыгарууга %1$d жолу туура эмес аракет кылдыңыз. Дагы %2$d аракеттен кийин, планшет баштапкы абалына келтирилет жана бардык маалыматтар жок кылынат." + "Сиз планшетиңизди бөгөттөн чыгарууга %1$d жолу туура эмес аракет кылдыңыз. Дагы %2$d аракеттен кийин, планшет баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт." "Кулпуну ачуу үлгүсүн %1$d жолу туура эмес тарттыңыз. Дагы %2$d жолу туура эмес тартсаңыз, сыналгыңыз баштапкы абалга келтирилип, колдонуучунун бардык дайындары жок болот." - "Сиз телефонуңузду бөгөттөн чыгарууга %1$d жолу туура эмес аракет кылдыңыз. Дагы %2$d аракеттен кийин, телефон баштапкы абалына келтирилет жана бардык маалыматтар жок кылынат." + "Сиз телефонуңузду бөгөттөн чыгарууга %1$d жолу туура эмес аракет кылдыңыз. Дагы %2$d аракеттен кийин, телефон баштапкы абалына келтирилет жана бардык маалыматтар өчүрүлөт." "Сиз планшетти бөгөттөн чыгарууга %d жолу туура эмес аракет кылдыңыз. Планшет баштапкы абалына келтирилет." "Сыналгыңыздын кулпусун ачууда %d_0 жолу туура эмес аракет кылдыңыз. Сыналгыңыз баштапкы абалга келтирилет." "Сиз телефонду бөгөттөн чыгарууга %d жолу туура эмес аракет кылдыңыз. Телефон баштапкы абалына келтирилет." @@ -885,7 +889,7 @@ "Медиа башкаруу" "Виджет иреттөө башталды." "Виджет иреттөө аяктады." - "%1$s виждети жок кылынды." + "%1$s виждети өчүрүлдү." "Бөгөттөн чыгаруу аймагын кеңейтүү." "Жылмыштырып ачуу." "Үлгү менен ачуу." @@ -1241,11 +1245,11 @@ "Эскертменин добуштары" "Белгисиз" "\"%1$s\" тармагына туташпай койду" - "Купуялык жөндөөлөрүн өзгөртүү үчүн таптап, кайра аракет кылыңыз" + "Купуялык жөндөөлөрүн өзгөртүү үчүн таптап, кайталап көрүңүз" "Купуялык жөндөөлөрүн өзгөртөсүзбү?" "%1$s түзмөгүңүздүн MAC дарегин, уникалдуу идентификаторуңузду колдонуп туташканы жатат. Ушуну менен түзмөгүңүздүн жайгашкан жерине жакын жердеги түзмөктөр көз сала алышат. \n\nЭгер улантсаңыз, %1$s купуялык жөндөөлөрүңүздү өзгөртүп, кайра туташууга аракет кылат." "Жөндөөнү өзгөртүү" - "Жөндөө жаңыртылды. Кайра туташып көрүңүз." + "Жөндөө жаңырды. Кайра туташып көрүңүз." "Купуялык жөндөөлөрүн өзгөртүүгө болбойт" "Тармак табылган жок" @@ -1331,7 +1335,7 @@ "Муну кийин Тууралоолор > Колдонмолордон өзгөртө аласыз" "Дайыма уруксат берүү" "Эч качан уруксат берилбесин" - "SIM-карта алынып салынды" + "SIM-карта өчүрүлдү" "Сиз жарактуу SIM салып, кайра иштетмейинче, мобилдик тармак жеткиликсиз болот." "Даяр" "SIM-карта кошулду" @@ -1401,7 +1405,7 @@ "%s колдоого алынбайт" "Бул түзмөктө %s колдоого алынбайт. Колдоого алынуучу форматта орнотуу үчүн таптап коюңуз." "Бул түзмөктө %s колдоого алынбайт. Колдоого алынуучу форматта орнотуу үчүн тандаңыз." - "%s күтүүсүздөн алынып салынды" + "%s күтүүсүздөн өчүрүлдү" "Мазмунду жоготуп албаш үчүн алып салуудан мурда медианы өчүрүңүз" "%s чыгарылды" "Айрым функциялар талаптагыдай иштебей калышы мүмкүн. Жаңы сактагычты салыңыз." @@ -1657,9 +1661,9 @@ "Сиз PIN-кодуңузду %1$d жолу туура эмес тердиңиз. \n\n %2$d секундадан кийин кайталаңыз." "Сиз сырсөзүңүздү %1$d жолу туура эмес тердиңиз. \n\n %2$d секундадан кийин кайталаңыз." "Сиз бөгөттөн чыгаруу үлгүсүн %1$d жолу туура эмес көрсөттүңүз. \n\n %2$d секундадан кийин кайталаңыз." - "Сиз планшетиңизди %1$d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы %2$d ийгиликсиз аракеттен кийин, планшет баштапкы абалына кайтарылат жана бардык берилиштериңиз жок кылынат." + "Сиз планшетиңизди %1$d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы %2$d ийгиликсиз аракеттен кийин, планшет баштапкы абалына кайтарылат жана бардык берилиштериңиз өчүрүлөт." "Кулпуну ачуу үлгүсүн %1$d жолу туура эмес тарттыңыз. Дагы %2$d жолу туура эмес тартсаңыз, сыналгыңыз баштапкы абалга келтирилип, колдонуучунун бардык дайындары жок болот." - "Сиз телефонуңузду %1$d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы %2$d ийгиликсиз аракеттен кийин, телефон баштапкы абалына кайтарылат жана бардык берилиштериңиз жок кылынат." + "Сиз телефонуңузду %1$d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Дагы %2$d ийгиликсиз аракеттен кийин, телефон баштапкы абалына кайтарылат жана бардык берилиштериңиз өчүрүлөт." "Сиз планшетиңизди %d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Планшет баштапкы абалына кайтарылат." "Сыналгыңыздын кулпусун ачууда %d_0 жолу туура эмес аракет кылдыңыз. Сыналгыңыз баштапкы абалга келтирилет." "Сиз телефонуңузду %d жолу ийгиликсиз бөгөттөн чыгаруу аракетин кылдыңыз. Телефон баштапкы абалына кайтарылат." @@ -1795,7 +1799,7 @@ %d секунддан кийин кайталаңыз 1 секунддан кийин кайталаңыз - "Кийинчерээк кайталаңыз" + "Бир аздан кийин кайталап көрүңүз" "Толук экран режими" "Чыгуу үчүн экранды ылдый сүрүп коюңуз." "Түшүндүм" @@ -1997,11 +2001,11 @@ "Зыянкеч колдонмо аныкталды" "%1$s колдонмосу %2$s үлгүлөрүн көрсөткөнү жатат" "Түзөтүү" - "Чалуулар менен эскертмелер дирилдөө режиминде иштейт" + "Чалуулар менен билдирмелер дирилдөө режиминде иштейт" "Чалуулар менен эскертмелердин үнү өчүрүлөт" "Тутум өзгөрүүлөрү" "Тынчымды алба" - "Жаңы: \"Тынчымды алба\" режими эскертмелерди жашырууда" + "Жаңы: \"Тынчымды алба\" режими билдирмелерди жашырууда" "Көбүрөөк маалымат алып, өзгөртүү үчүн таптаңыз." "\"Тынчымды алба\" режими өзгөрдү" "Бөгөттөлгөн нерселерди көрүү үчүн таптаңыз." diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 9f9fe2c7433c..3367722c867d 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -434,6 +434,8 @@ "ແອັບນີ້ສາມາດຈັດລະບຽບການເຄື່ອນໄຫວທາງກາຍຂອງທ່ານໄດ້." "ຖ່າຍຮູບ ແລະວິດີໂອ" "This app can take pictures and record videos using the camera at any time." + "ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ຫຼື ບໍລິການຮັບການເອີ້ນກັບກ່ຽວກັບອຸປະກອນກ້ອງຖືກເປີດ ຫຼື ປິດໄດ້." + "ແອັບລາຍເຊັນນີ້ສາມາດຮັບການເອີ້ນກັບໄດ້ເມື່ອມີອຸປະກອນກ້ອງໃດຖືກເປີດ (ໂດຍແພັກເກດແອັບພລິເຄຊັນຫຍັງ) ຫຼື ຖືກປິດ." "ຄວບຄຸມການສັ່ນ" "ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມໂຕສັ່ນ." "ໂທຫາເບີໂທລະສັບໂດຍກົງ" @@ -450,9 +452,11 @@ "ອະນຸຍາດໃຫ້ແອັບສືບຕໍ່ການໂທເຊິ່ງອາດຖືກເລີ່ມຕົ້ນໃນແອັບອື່ນ." "ອ່ານເບີໂທລະສັບ" "ອະນຸຍາດໃຫ້ແອັບເຂົ້າເຖິງເບີໂທລະສັບຂອງອຸປະກອນໄດ້." + "ເປີດໜ້າຈໍລົດໄວ້ຕະຫຼອດ" "ຂັດຂວາງບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ" "ປ້ອງ​ກັນ​ບໍ່​ໃຫ້ໂທລະພາບຫຼັບ​ພັກ" "ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ" + "ອະນຸຍາດໃຫ້ແອັບເຮັດໃຫ້ໜ້າຈໍລົດເປີດໄວ້ຕະຫຼອດ." "ອະນຸຍາດໃຫ້ແອັບຯ ປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ." "ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ປ້ອງ​ກັນ​ບໍ່​ໃຫ້ໂທລະພາບຫຼັບ​ພັກ." "ອະນຸຍາດໃຫ້ແອັບຯປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍໂທລະສັບ." diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index d41670f8f8b2..282fa238ab56 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -440,6 +440,8 @@ "Ši programa gali atpažinti jūsų fizinę veiklą." "fotografuoti ir filmuoti" "Ši programa gali bet kada fotografuoti ir įrašyti vaizdo įrašų naudodama fotoaparatą." + "Leisti programai ar paslaugai sulaukti atgalinio skambinimo, kai atidaromas ar uždaromas fotoaparatas." + "Ši pasirašymo programa gali sulaukti atgalinio skambinimo, kai atidaromas ar uždaromas (kurio nors programos paketo) koks nors fotoaparatas." "valdyti vibraciją" "Leidžiama programai valdyti vibravimą." "skambinti tiesiogiai telefono numeriais" @@ -456,9 +458,11 @@ "Programai leidžiama tęsti skambutį, kuris buvo pradėtas naudojant kitą programą." "skaityti telefonų numerius" "Programai leidžiama pasiekti įrenginio telefonų numerius." + "palikti automobilio ekraną įjungtą" "neleisti planšetiniam kompiuteriui užmigti" "neleisti įjungti TV miego būsenos" "neleisti telefonui snausti" + "Programai leidžiama palikti automobilio ekraną įjungtą." "Leidžiama programai neleisti planšetiniam kompiuteriui užmigti." "Programai leidžiama nustatyti, kad TV nebūtų perjungtas į miego būseną." "Leidžiama programai neleisti telefonui užmigti." diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index c5e269fa0c43..17dfeaa04772 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -437,6 +437,8 @@ "Šī lietotne var noteikt jūsu fiziskās aktivitātes." "uzņemt attēlus un videoklipus" "Šī lietotne jebkurā brīdī var uzņemt attēlus un ierakstīt videoklipus, izmantojot kameru." + "Atļaut lietojumprogrammai vai pakalpojumam saņemt atzvanus par kameras ierīču atvēršanu vai aizvēršanu" + "Šajā parakstu lietotnē var saņemt atzvanus, ja tiek atvērta vai aizvērta jebkāda kameras ierīce (atkarībā no lietojumprogrammas pakotnes)." "kontrolēt vibrosignālu" "Ļauj lietotnei kontrolēt vibrosignālu." "tieši zvanīt uz tālruņa numuriem" @@ -453,9 +455,11 @@ "Ļauj lietotnei turpināt zvanu, kas tika sākts citā lietotnē." "lasīt tālruņa numurus" "Ļauj lietotnei piekļūt ierīcē esošajiem tālruņa numuriem." + "paturēt ieslēgtu automašīnas ekrānu" "novērst planšetdatora pāriešanu miega režīmā" "novērst televizora pāreju miega režīmā" "novērst tālruņa pāriešanu miega režīmā" + "Ļauj lietotnei paturēt ieslēgtu automašīnas ekrānu." "Ļauj lietotnei novērst planšetdatora pāriešanu miega režīmā." "Ļauj lietotnei novērst televizora pāreju miega režīmā." "Ļauj lietotnei novērst tālruņa pāriešanu miega režīmā." diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index af73a792ddfd..fcfa19500706 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -21,9 +21,9 @@ "Б" - "КБ" - "МБ" - "ГБ" + "KB" + "MB" + "GB" "ТБ" "ПБ" "%1$s %2$s" @@ -434,6 +434,8 @@ "Апликацијава може да ја препознава вашата физичка активност." "снимај слики и видеа" "Апликацијава може да фотографира и да снима видеа со камерата во секое време." + "Дозволете апликацијатa или услугата да прима повратни повици за отворањето или затворањето на уредите со камера." + "Оваа апликација за потпис може да прима повратни повици кога кој било уред со камера (од некој пакет за апликации) е отворен или затворен." "контролирај вибрации" "Дозволува апликацијата да ги контролира вибрациите." "директно избирај телефонски броеви" @@ -450,9 +452,11 @@ "Овозможува апликацијата да продолжи повик започнат на друга апликација." "да чита телефонски броеви" "Ѝ дозволува на апликацијата да пристапи до телефонските броеви на уредот." + "оставете го екранот на автомобилот вклучен" "спречи режим на штедење кај таблет" "спречи го телевизорот да премине во режим на мирување" "спречи телефон од режим на штедење" + "Дозволува апликацијата да го држи екранот на автомобилот вклучен." "Дозволува апликацијата да го спречи таблетот да не заспие." "Дозволува апликацијата да го спречи телевизорот да оди во режим на мирување." "Дозволува апликацијата да го спречи телефонот да не заспие." @@ -1115,7 +1119,7 @@ "Дефинирајте го избраниот текст" "Капацитетот е речиси полн" "Некои системски функции може да не работат" - "Нема доволно меморија во системот. Проверете дали има слободен простор од 250 МБ и рестартирајте." + "Нема доволно меморија во системот. Проверете дали има слободен простор од 250 MB и рестартирајте." "%1$s работи" "Допрете за повеќе информации или за сопирање на апликацијата." "Во ред" @@ -1163,7 +1167,7 @@ "%1$s постојано запира" "%1$s постојано запира" "Отвори ја апликацијата повторно" - "Испрати повратни информации" + "Испратете повратни информации" "Затвори" "Исклучи го звукот додека уредот не се рестартира" "Почекај" diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 7602575ba90a..d474ff59d511 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -434,6 +434,10 @@ "നിങ്ങളുടെ ശാരീരിക പ്രവർത്തനം ഈ ആപ്പിന് തിരിച്ചറിയാനാവും." "ചിത്രങ്ങളും വീഡിയോകളും എടുക്കുക" "ഏതുസമയത്തും ക്യാമറ ഉപയോഗിച്ചുകൊണ്ട് ചിത്രങ്ങൾ എടുക്കാനും വീഡിയോകൾ റെക്കോർഡുചെയ്യാനും ഈ ആപ്പിന് കഴിയും." + + + + "വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക" "വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു." "ഫോൺ നമ്പറുകളിലേക്ക് നേരിട്ട് വിളിക്കുക" @@ -450,9 +454,11 @@ "മറ്റൊരു ആപ്പിൽ ആരംഭിച്ച കോൾ തുടരാൻ ആപ്പിനെ അനുവദിക്കുന്നു." "ഫോൺ നമ്പറുകൾ റീഡുചെയ്യൽ" "ഉപകരണത്തിന്റെ ഫോൺ നമ്പറുകൾ ആക്‌സസ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു." + "കാറിലെ സ്ക്രീൻ ഓണാക്കി വയ്ക്കുക" "ഉറങ്ങുന്നതിൽ നിന്ന് ടാബ്‌ലെറ്റിനെ തടയുക" "ടിവിയെ നിർജ്ജീവമാകുന്നതിൽ നിന്ന് തടയുക" "ഉറങ്ങുന്നതിൽ നിന്ന് ഫോണിനെ തടയുക" + "കാറിലെ സ്ക്രീൻ ഓണാക്കി വയ്ക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു." "ടാബ്‌ലെറ്റ് സുഷുപ്തിയിലാകുന്നതിൽ നിന്നും തടയുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു." "ടിവി നിർജ്ജീവമാകുന്നത് തടയുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു." "ഫോൺ സുഷുപ്തിയിലാകുന്നതിൽ നിന്നും തടയുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു." diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 241ec82461eb..0234996f8587 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -434,6 +434,8 @@ "Энэ апп таны биеийн дасгал хөдөлгөөнийг таних боломжтой." "зураг авах болон видео бичих" "Энэ апп ямар ч үед камер ашиглан зураг авж, видео хийх боломжтой." + "Аппликэйшн эсвэл үйлчилгээнд камерын төхөөрөмжүүдийг нээж эсвэл хааж байгаа тухай залгасан дуудлага хүлээн авахыг зөвшөөрөх." + "Гарын үсгийн энэ апп нь дурын камерын төхөөрөмжийг нээх (ямар аппликэйшний багцаар болох) эсвэл хаах үед буцааж залгасан дуудлага хүлээн авах боломжтой." "чичиргээг удирдах" "Апп нь чичиргээг удирдах боломжтой." "утасны дугаарт шууд дуудлага хийх" @@ -450,9 +452,11 @@ "Аппад өөр аппад эхлүүлсэн дуудлагыг үргэлжлүүлэхийг зөвшөөрдөг." "утасны дугаарыг унших" "Төхөөрөмжийн утасны дугаарт хандах зөвшөөрлийг апп-д олгоно." + "машины дэлгэцийг асаалттай байлгах" "таблетыг унтуулахгүй байлгах" "Телевиз-ийн гэрэл унтрахаас сэргийл" "утсыг унтуулахгүй байлгах" + "Аппад машины дэлгэцийг асаалттай байлгахыг зөвшөөрдөг." "Апп нь таблетыг унтахаас сэргийлэх боломжтой" "Апп-д телевизийг унтраахгүй байлгахыг зөвшөөрдөг." "Апп нь утсыг унтахаас сэргийлэх боломжтой" diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 6f5e199c8b19..1cb979e95107 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -294,7 +294,7 @@ "<b>%1$s</b> ला एसएमएस पाठवू आणि पाहू द्यायचे?" "स्टोरेज" "तुमच्या डिव्हाइस वरील फोटो, मीडिया आणि फायलींमध्‍ये अ‍ॅक्सेस" - "<b>%1$s</b> ला तुमच्या डिव्हाइसवरील फोटो, मीडिया आणि फायली अ‍ॅक्सेस करू द्यायचे?" + "<b>%1$s</b> ला तुमच्या डिव्हाइसवरील फोटो, मीडिया आणि फाइल अ‍ॅक्सेस करू द्यायच्या?" "मायक्रोफोन" "ऑडिओ रेकॉर्ड" "<b>%1$s</b> ला ऑडिओ रेकॉर्ड करू द्यायचा?" @@ -434,6 +434,10 @@ "हे अ‍ॅप तुमच्या शारीरिक ॲक्टिव्हिटी ओळखू शकते." "चित्रे आणि व्हिडिओ घ्या" "हा अ‍ॅप कोणत्याही वेळी कॅमेरा वापरून चित्रेे घेऊ आणि व्ह‍िडिओ रेकॉर्ड करू शकतो." + + + + "व्हायब्रेट नियंत्रित करा" "अ‍ॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते." "फोन नंबरवर प्रत्यक्ष कॉल करा" @@ -450,9 +454,11 @@ "दुसऱ्या ॲपमध्ये सुरू झालेल्या कॉलला पुढे सुरू ठेवण्याची ॲपला अनुमती देते." "फोन नंबर वाचा" "ॲपला डिव्हाइसच्या फोन नंबरमध्ये प्रवेश करण्याची अनुमती देते." + "कारची स्क्रीन सुरू ठेवा" "टॅबलेट निष्क्रिय होण्यापासून प्रतिबंधित करा" "निष्क्रिय होण्यापासून प्रतिबंध करा" "फोन निष्‍क्रिय होण्‍यापासून प्रतिबंधित करा" + "ॲपला कारची स्क्रीन सुरू ठेवण्याची अनुमती देते." "टॅब्लेटला निष्क्रिय होण्यापासून प्रतिबंधित करण्यासाठी अ‍ॅप ला अनुमती देते." "निष्क्रिय होण्यापासून टीव्हीला प्रतिबंध करण्यासाठी ॲपला अनुमती देते." "फोनला निष्क्रिय होण्यापासून प्रतिबंधित करण्यासाठी अ‍ॅप ला अनुमती देते." diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 1698bb7cedac..2c7be25fadbd 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -434,6 +434,8 @@ "Apl ini dapat mengecam aktiviti fizikal anda." "ambil gambar dan video" "Apl ini boleh mengambil gambar dan merakam video menggunakan kamera pada bila-bila masa." + "Benarkan aplikasi atau perkhidmatan menerima panggilan balik tentang peranti kamera yang dibuka atau ditutup." + "Apl tandatangan ini boleh menerima panggilan balik apabila mana-mana peranti kamera dibuka (oleh pakej aplikasi tertentu) atau ditutup." "kawal getaran" "Membenarkan apl mengawal penggetar." "panggil terus nombor telefon" @@ -450,9 +452,11 @@ "Membenarkan apl meneruskan panggilan yang dimulakan dalam apl lain." "baca nombor telefon" "Membenarkan apl mengakses nombor telefon peranti." + "pastikan skrin kereta sentiasa hidup" "menghalang tablet daripada tidur" "halang TV daripada tidur" "halang telefon daripada tidur" + "Membenarkan apl memastikan skrin kereta sentiasa hidup." "Membenarkan apl menghalang tablet daripada tidur." "Membenarkan apl menghalang TV daripada tidur." "Membenarkan apl menghalang telefon daripada tidur." diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 99e5d4258cef..b43add50b95b 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -434,6 +434,8 @@ "ဤအက်ပ်က သင်၏ကိုယ်လက်လှုပ်ရှားမှုကို မှတ်သားနိုင်ပါသည်။" "ဓါတ်ပုံနှင့်ဗွီဒီယိုရိုက်ခြင်း" "ဤအက်ပ်သည် ကင်မရာကို အသုံးပြု၍ ဓာတ်ပုံနှင့် ဗီဒီယိုများကို အချိန်မရွေး ရိုက်ကူးနိုင်ပါသည်။" + "ကင်မရာစက်များ ပွင့်နေခြင်း သို့မဟုတ် ပိတ်နေခြင်းနှင့် ပတ်သက်ပြီး ပြန်လည်ခေါ်ဆိုမှုများ ရယူရန် အပလီကေးရှင်း သို့မဟုတ် ဝန်ဆောင်မှုကို ခွင့်ပြုခြင်း။" + "(မည်သည့် အပလီကေးရှင်းပက်ကေ့ဂျ်ကြောင့်) ကင်မရာစက်တစ်ခုခု ပွင့်နေသည့်အခါ သို့မဟုတ် ပိတ်နေသည့်အခါ ဤအထူးသီးသန့်အက်ပ်က ပြန်လည်ခေါ်ဆိုမှုများ ရယူနိုင်သည်။" "တုန်ခုန်မှုအား ထိန်းချုပ်ခြင်း" "အက်ပ်အား တုန်ခါစက်ကို ထိန်းချုပ်ခွင့် ပြုသည်။" "ဖုန်းနံပါတ်များကိုတိုက်ရိုက်ခေါ်ဆိုခြင်း" @@ -450,9 +452,11 @@ "အခြားအက်ပ်တွင် စတင်ထားသည့် ဖုန်းခေါ်ဆိုမှုကို ဆက်လက်ပြုလုပ်ရန် ဤအက်ပ်ကို ခွင့်ပြုသည်။" "ဖုန်းနံပါတ်များကို ဖတ်ရန်" "အက်ပ်ကို စက်ပစ္စည်း၏ ဖုန်းနံပါတ်များအား အသုံးပြုခွင့်ပေးပါ။" + "ကားဖန်သားပြင်ကို ဖွင့်ထားပါ" "တက်ပလက်အား ပိတ်ခြင်းမှ ကာကွယ်ခြင်း" "တီဗွီအား နားနေခြင်းမှ ကာကွယ်ရန်" "ဖုန်းအနားယူခြင်းမပြုလုပ်စေရန်" + "ကားဖန်သားပြင် ဖွင့်ထားနိုင်စေရန် အက်ပ်ကို ခွင့်ပြုပေးပါ။" "အက်ပ်အား တက်ဘလက်ကို အနားမယူနိုင်အောင် ဟန့်တားခွင့် ပြုသည်။" "တီဗွီ ရပ်နားသွားခြင်းအား ကာကွယ်ရန် အက်ပ်အား ခွင့်ပြုပါ။" "အက်ပ်အား ဖုန်းကို အနားမယူနိုင်အောင် ဟန့်တားခွင့် ပြုသည်။" @@ -1235,7 +1239,7 @@ "အကြောင်းကြားသံအတိုးအကျယ်" "မူရင်းမြည်သံ" "မူရင်း (%1$s)" - "တစ်ခုမှမဟုတ်" + "တစ်ခုမျှမဟုတ်" "မြည်သံများ" "နှိုးစက်သံ" "အကြောင်းကြားချက်အသံ" diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index e2d45e7d86aa..74bf9d73aa1f 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -298,7 +298,7 @@ "Mikrofon" "ta opp lyd" "Vil du la <b>%1$s</b> ta opp lyd?" - "Fysisk aktivitet-" + "Fysisk aktivitet" "tilgang til den fysiske aktiviteten din" "Vil du gi <b>%1$s</b> tilgang til den fysiske aktiviteten din?" "Kamera" @@ -434,6 +434,8 @@ "Denne appen kan gjenkjenne den fysiske aktiviteten din." "ta bilder og videoer" "Denne appen kan når som helst ta bilder og spille inn videoer ved hjelp av kameraet." + "Tillat at en app eller tjeneste mottar tilbakekallinger om kameraenheter som åpnes eller lukkes." + "Denne signaturappen kan motta tilbakekallinger når en kameraenhet blir åpnet (av hvilken app-pakke) eller lukket." "kontrollere vibreringen" "Lar appen kontrollere vibreringsfunksjonen." "ringe telefonnummer direkte" @@ -450,9 +452,11 @@ "Lar appen fortsette et anrop som ble startet i en annen app." "les telefonnumre" "Gir appen tilgang til telefonnumrene til enheten." + "hold bilskjermen på" "hindre nettbrettet fra å gå over til sovemodus" "hindre TV-en i å gå i hvilemodus" "forhindre telefonen fra å sove" + "Tillater at appen holder bilskjermen på." "Lar appen hindre nettbrettet fra å gå over i sovemodus." "Gjør at appen hindrer TV-en i å gå i dvale." "Lar appen hindre telefonen fra å gå over i sovemodus." diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index fa594d8694cb..e1dc55f98f40 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -434,6 +434,10 @@ "यो अनुप्रयोगले तपाईंको शारीरिक गतिविधिको पहिचान गर्न सक्छ।" "तस्बिरहरू र भिडियोहरू लिनुहोस्।" "यस अनुप्रयोगले जुनसुकै समय क्यामेराको प्रयोग गरी तस्बिर खिच्न र भिडियो रेकर्ड गर्न सक्छ।" + + + + "कम्पन नियन्त्रण गर्नुहोस्" "अनुप्रयोगलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।" "फोन नम्बरहरूमा सीधै कल गर्नुहोस्" @@ -450,9 +454,11 @@ "यस अनुप्रयोगलाई अर्को अनुप्रयोगमा सुरु गरिएको कल जारी राख्ने अनुमति दिन्छ।" "फोन नम्बरहरू पढ्ने" "उक्त अनुप्रयोगलाई यस यन्त्रको फोन नम्बरहरूमाथि पहुँच राख्न दिनुहोस्।" + "कारको स्क्रिन सक्रिय राख्नुहोस्" "ट्याब्लेटलाई निन्द्रामा जानबाट रोक्नुहोस्" "TV निभ्नबाट जोगाउनुहोस्" "फोनलाई निदाउनबाट रोक्नुहोस्" + "यो अनुमतिले यस अनुप्रयोगलाई कारको स्क्रिन सक्रिय राख्न दिन्छ।" "ट्याब्लेटलाई निस्क्रिय हुनबाट रोक्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।" "अनुप्रयोगलाई अनुमति दिन्छ TV लाई निभ्नबाट जोगाउन।" "फोनलाई निस्क्रिय हुनबाट रोक्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।" diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index f1eb7a9ab891..cc35c8ee44ce 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -434,6 +434,8 @@ "Deze app kan je fysieke activiteit herkennen." "foto\'s en video\'s maken" "Deze app kan op elk moment foto\'s maken en video\'s opnemen met de camera." + "Een app of service toestaan callbacks te ontvangen over camera-apparaten die worden geopend of gesloten." + "Deze ondertekeningsapp kan callback ontvangen als een camera-apparaat wordt geopend (en door welk app-pakket) of gesloten." "trilling beheren" "Hiermee kan de app de trilstand beheren." "telefoonnummers rechtstreeks bellen" @@ -450,9 +452,11 @@ "Hiermee kan de app een gesprek voortzetten dat is gestart in een andere app." "telefoonnummers lezen" "Hiermee kan de app toegang krijgen tot de telefoonnummers van het apparaat." + "autoscherm ingeschakeld houden" "voorkomen dat tablet overschakelt naar slaapmodus" "voorkomen dat tv overschakelt naar slaapmodus" "voorkomen dat telefoon overschakelt naar slaapmodus" + "Hiermee kan de app het autoscherm ingeschakeld houden." "Hiermee kan de app voorkomen dat de tablet overschakelt naar de slaapmodus." "Hiermee kan de app voorkomen dat de tv overschakelt naar de slaapmodus." "Hiermee kan de app voorkomen dat de telefoon overschakelt naar de slaapmodus." diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index f3333c0479e6..9ef8e0ae71fe 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -434,6 +434,10 @@ "ଏହି ଆପ୍‍ଣ ଆପଣଙ୍କ ଶାରୀରିକ ଗତିବିଧିକୁ ଚିହ୍ନଟ କରିପାରେ" "ଫଟୋ ଓ ଭିଡିଓଗୁଡ଼ିକୁ ନିଅନ୍ତୁ" "ଏହି ଆପ୍‍ ଯେକୌଣସି ସମୟରେ କ୍ୟାମେରା ବ୍ୟବହାର କରି ଫଟୋ ଉଠାଇପାରେ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରେ।" + + + + "କମ୍ପନ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ" "ଆପ୍‍କୁ, ଭାଇବ୍ରେଟର୍‍ ନିୟନ୍ତ୍ରଣ କରିବାକୁ ଦେଇଥାଏ।" "ସିଧାସଳଖ ଫୋନ୍ ନମ୍ବରଗୁଡ଼ିକୁ କଲ୍ କରନ୍ତୁ" @@ -450,9 +454,11 @@ "ଅନ୍ୟ ଆପ୍‌ରେ ଆରମ୍ଭ ହୋଇଥିବା ଗୋଟିଏ କଲ୍‌କୁ ଜାରି ରଖିବା ପାଇଁ ଆପ୍‌କୁ ଅନୁମତି ଦିଅନ୍ତୁ।" "ଫୋନ୍‍ ନମ୍ବର ପଢ଼େ" "ଏହି ଡିଭାଇସର ଫୋନ୍‍ ନମ୍ବର ଆକ୍ସେସ୍‍ କରିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।" + "କାର ସ୍କ୍ରିନକୁ ଚାଲୁ ରଖନ୍ତୁ" "ଟାବଲେଟ୍‌କୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍‌କୁ ଯିବାକୁ ରୋକନ୍ତୁ" "ଟିଭିକୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍‌ରୁ ଯିବାକୁ ରୋକନ୍ତୁ।" "ଫୋନକୁ ସ୍ଲୀପିଙ୍ଗ ମୋଡ୍‌କୁ ଯିବାକୁ ରୋକନ୍ତୁ" + "କାର ସ୍କ୍ରିନକୁ ଚାଲୁ ରଖିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦେଇଥାଏ।" "ଆପ୍‍କୁ, ଟାବଲେଟ୍‍ଟିକୁ ସ୍ଲୀପ୍‍ ମୋଡ୍‍କୁ ଯିବାରେ ପ୍ରତିରୋଧ କରିବାକୁ ଦେଇଥାଏ।" "TVକୁ ଶୁଆଇବାକୁ ଯିବାରୁ ରୋକିବାକୁ ଆପ୍‌ ଅନୁମତି ଦେଇଥାଏ।" "ଆପ୍‍କୁ, ଫୋନ୍‌ଟିକୁ ସ୍ଲୀପ୍‍ ମୋଡ୍‍କୁ ଯିବାରେ ପ୍ରତିରୋଧ କରିବାକୁ ଦେଇଥାଏ।" diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 8471660d2684..3b264d3147a4 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -434,6 +434,8 @@ "ਇਹ ਐਪ ਤੁਹਾਡੀ ਸਰੀਰਕ ਸਰਗਰਮੀ ਨੂੰ ਪਛਾਣ ਸਕਦੀ ਹੈ।" "ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਬਣਾਓ" "ਇਹ ਐਪ ਕਿਸੇ ਵੀ ਸਮੇਂ ਕੈਮਰੇ ਨੂੰ ਵਰਤ ਕੇ ਤਸਵੀਰਾਂ ਖਿੱਚ ਸਕਦੀ ਹੈ ਅਤੇ ਵੀਡੀਓ ਫ਼ਾਈਲਾਂ ਰਿਕਾਰਡ ਕਰ ਸਕਦੀ ਹੈ।" + "ਐਪਲੀਕੇਸ਼ਨ ਜਾਂ ਸੇਵਾ ਨੂੰ ਕੈਮਰਾ ਡੀਵਾਈਸਾਂ ਦੇ ਚਾਲੂ ਜਾਂ ਬੰਦ ਕੀਤੇ ਜਾਣ ਬਾਰੇ ਕਾਲਬੈਕ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ।" + "ਇਹ ਸਿਗਨੇਚਰ ਐਪ ਕੋਈ ਵੀ ਕੈਮਰਾ ਡੀਵਾਈਸ ਚਾਲੂ ਹੋਣ (ਕਿਸ ਐਪਲੀਕੇਸ਼ਨ ਪੈਕੇਜ ਰਾਹੀਂ) ਜਾਂ ਬੰਦ ਹੋਣ \'ਤੇ ਕਾਲਬੈਕ ਪ੍ਰਾਪਤ ਕਰ ਸਕਦੀ ਹੈ।" "ਵਾਈਬ੍ਰੇਸ਼ਨ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ" "ਐਪ ਨੂੰ ਵਾਈਬ੍ਰੇਟਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।" "ਫ਼ੋਨ ਨੰਬਰਾਂ ਤੇ ਸਿੱਧੇ ਕਾਲ ਕਰੋ" @@ -450,9 +452,11 @@ "ਐਪ ਨੂੰ ਉਹ ਕਾਲ ਜਾਰੀ ਰੱਖਣ ਦਿਓ ਜਿਸਨੂੰ ਹੋਰ ਐਪ ਤੋਂ ਚਾਲੂ ਕੀਤਾ ਗਿਆ ਸੀ।" "ਫ਼ੋਨ ਨੰਬਰ ਪੜ੍ਹੋ" "ਐਪ ਨੂੰ ਡੀਵਾਈਸ ਦੇ ਫ਼ੋਨ ਨੰਬਰਾਂ \'ਤੇ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦੀ ਹੈ।" + "ਕਾਰ ਦੀ ਸਕ੍ਰੀਨ ਚਾਲੂ ਰੱਖੋ" "ਟੈਬਲੈੱਟ ਨੂੰ ਸਲੀਪ ਤੇ ਜਾਣ ਤੋਂ ਰੋਕੋ" "TV ਨੂੰ ਸਲੀਪਿੰਗ ਤੋਂ ਰੋਕੋ" "ਫ਼ੋਨ ਨੂੰ ਸਲੀਪਿੰਗ ਤੋਂ ਰੋਕੋ" + "ਐਪ ਨੂੰ ਕਾਰ ਦੀ ਸਕ੍ਰੀਨ ਹਰ ਵੇਲੇ ਚਾਲੂ ਰੱਖਣ ਦਿੰਦਾ ਹੈ।" "ਐਪ ਨੂੰ ਟੈਬਲੈੱਟ ਨੂੰ ਸਲੀਪ ਤੇ ਜਾਣ ਤੋਂ ਰੋਕਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।" "ਐਪ ਨੂੰ TV ਨੂੰ ਸਲੀਪ ਤੇ ਜਾਣ ਤੋਂ ਰੋਕਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।" "ਐਪ ਨੂੰ ਫ਼ੋਨ ਨੂੰ ਸਲੀਪ ਤੇ ਜਾਣ ਤੋਂ ਰੋਕਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।" diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index dbc3282bc38b..3273578d597a 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -95,7 +95,7 @@ "Stan mobilnej transmisji danych" "SMS-y" "Wiadomości poczty głosowej" - "Połączenia przez Wi-Fi" + "Połączenie przez Wi-Fi" "Stan karty SIM" "Stan karty SIM – wysoki priorytet" "Drugie urządzenie zażądało trybu „TTY pełny”" @@ -133,14 +133,14 @@ - "%s, połączenia przez Wi-Fi" + "%s, połączenie przez Wi-Fi" "%s, połączenia przez Wi-Fi" "Połączenie przez WLAN" "%s, połączenie przez WLAN" "%s, Wi-Fi" "Połączenia przez Wi-Fi | %s" "%s, VoWifi" - "Połączenia przez Wi-Fi" + "Połączenie przez Wi-Fi" "Wi-Fi" "Połączenia przez Wi-Fi" "VoWifi" @@ -298,7 +298,7 @@ "SMS" "wysyłanie i wyświetlanie SMS‑ów" "Zezwolić aplikacji <b>%1$s</b> na wysyłanie i wyświetlanie SMS-ów?" - "Pamięć" + "Pamięć wewnętrzna" "dostęp do zdjęć, multimediów i plików na Twoim urządzeniu" "Zezwolić aplikacji <b>%1$s</b> na dostęp do zdjęć, multimediów i plików na urządzeniu?" "Mikrofon" @@ -440,6 +440,8 @@ "Ta aplikacja może rozpoznawać Twoją aktywność fizyczną." "wykonywanie zdjęć i filmów wideo" "Ta aplikacja może w dowolnym momencie robić zdjęcia i nagrywać filmy przy użyciu aparatu." + "Zezwól na dostęp aplikacji lub usługi na otrzymywanie wywoływania zwrotnego o urządzeniach z aparatem, kiedy są one uruchamiane lub zamykane." + "Aplikacja z podpisami może korzystać z wywoływania zwrotnego, kiedy urządzenie z aparatem jest uruchamiane (przez jaki pakiet aplikacji) albo zamykane." "sterowanie wibracjami" "Pozwala aplikacji na sterowanie wibracjami." "bezpośrednie wybieranie numerów telefonów" @@ -456,9 +458,11 @@ "Zezwala na kontynuowanie przez aplikację połączenia rozpoczętego w innej aplikacji." "odczytywanie numerów telefonów" "Zezwala aplikacji na dostęp do numerów telefonów na urządzeniu." + "utrzymuj włączony ekran samochodu" "zapobieganie przechodzeniu tabletu do trybu uśpienia" "powstrzymywanie usypiania telewizora" "zapobieganie przejściu telefonu w stan uśpienia" + "Zezwala aplikacji na utrzymywanie włączonego ekranu samochodu" "Pozwala aplikacji na zapobieganie przechodzeniu tabletu do trybu uśpienia." "Pozwala aplikacji powstrzymać uśpienie telewizora." "Pozwala aplikacji na zapobieganie przechodzeniu telefonu w tryb uśpienia." diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 43721005895d..e050d50c0626 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -434,6 +434,8 @@ "Este app pode reconhecer sua atividade física." "tirar fotos e gravar vídeos" "Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento." + "Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados." + "Esse app de assinatura pode receber callbacks quando um dispositivo de câmera é aberto (por qualquer pacote de apps) ou fechado." "controlar vibração" "Permite que o app controle a vibração." "ligar diretamente para números de telefone" @@ -450,9 +452,11 @@ "Permite que o app continue uma chamada que foi iniciada em outro app." "ler números de telefone" "Permite que o app acesse os número de telefone do dispositivo." + "manter a tela do carro ativada" "impedir modo de inatividade do tablet" "impedir a suspensão da TV" "impedir modo de inatividade do telefone" + "Permite que o app mantenha a tela do carro ativada." "Permite que o app impeça a suspensão do tablet." "Permite que o app impeça a suspensão da TV." "Permite que o app impeça a suspensão do telefone." @@ -514,8 +518,8 @@ "Permite que o app execute métodos para adicionar e excluir modelos de impressão digital para uso." "usar hardware de impressão digital" "Permite que o app use hardware de impressão digital para autenticação." - "modificar sua coleção de músicas" - "Permite que o app modifique sua coleção de músicas." + "modificar sua biblioteca de música" + "Permite que o app modifique sua biblioteca de música." "modificar sua coleção de vídeos" "Permite que o app modifique sua coleção de vídeos." "modificar sua coleção de fotos" @@ -912,7 +916,7 @@ "Confirmar navegação" "Sair desta página" "Permanecer nesta página" - "%s\n\nTem certeza que quer sair desta página?" + "%s\n\nVocê quer mesmo sair desta página?" "Confirmar" "Dica: toque duas vezes para aumentar e diminuir o zoom." "Preench. aut." diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 3ee2ea50b81d..a9e8f1490e1b 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -434,6 +434,8 @@ "Esta aplicação consegue reconhecer a sua atividade física." "tirar fotos e vídeos" "Esta aplicação pode tirar fotos e gravar vídeos através da câmara em qualquer altura." + "Permitir que uma app ou um serviço receba chamadas de retorno sobre dispositivos de câmara que estão a ser abertos ou fechados" + "Esta app de assinatura pode receber chamadas de retorno quando qualquer dispositivo de câmara está a ser aberto (e por que pacote de apps) ou fechado." "controlar vibração" "Permite à aplicação controlar o vibrador." "marcar números de telefone diretamente" @@ -450,9 +452,11 @@ "Permite à aplicação continuar uma chamada iniciada noutra aplicação." "ler os números de telefone" "Permite à aplicação aceder aos números de telefone do dispositivo." + "manter o ecrã do automóvel ligado" "impedir que o tablet entre em inactividade" "impedir a TV de entrar no modo de suspensão" "impedir modo de inactividade do telefone" + "Permite que a app mantenha o ecrã do automóvel ligado." "Permite que a aplicação impeça o tablet de entrar no modo de suspensão." "Permite à aplicação impedir a TV de entrar em modo de suspensão." "Permite que a aplicação impeça o telemóvel de entrar em inatividade." diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 43721005895d..e050d50c0626 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -434,6 +434,8 @@ "Este app pode reconhecer sua atividade física." "tirar fotos e gravar vídeos" "Este app pode tirar fotos e gravar vídeos usando a câmera a qualquer momento." + "Permitir que um aplicativo ou serviço receba callbacks sobre dispositivos de câmera sendo abertos ou fechados." + "Esse app de assinatura pode receber callbacks quando um dispositivo de câmera é aberto (por qualquer pacote de apps) ou fechado." "controlar vibração" "Permite que o app controle a vibração." "ligar diretamente para números de telefone" @@ -450,9 +452,11 @@ "Permite que o app continue uma chamada que foi iniciada em outro app." "ler números de telefone" "Permite que o app acesse os número de telefone do dispositivo." + "manter a tela do carro ativada" "impedir modo de inatividade do tablet" "impedir a suspensão da TV" "impedir modo de inatividade do telefone" + "Permite que o app mantenha a tela do carro ativada." "Permite que o app impeça a suspensão do tablet." "Permite que o app impeça a suspensão da TV." "Permite que o app impeça a suspensão do telefone." @@ -514,8 +518,8 @@ "Permite que o app execute métodos para adicionar e excluir modelos de impressão digital para uso." "usar hardware de impressão digital" "Permite que o app use hardware de impressão digital para autenticação." - "modificar sua coleção de músicas" - "Permite que o app modifique sua coleção de músicas." + "modificar sua biblioteca de música" + "Permite que o app modifique sua biblioteca de música." "modificar sua coleção de vídeos" "Permite que o app modifique sua coleção de vídeos." "modificar sua coleção de fotos" @@ -912,7 +916,7 @@ "Confirmar navegação" "Sair desta página" "Permanecer nesta página" - "%s\n\nTem certeza que quer sair desta página?" + "%s\n\nVocê quer mesmo sair desta página?" "Confirmar" "Dica: toque duas vezes para aumentar e diminuir o zoom." "Preench. aut." diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 1427b0c4f729..c31fd4676721 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -437,6 +437,8 @@ "Această aplicație vă poate recunoaște activitatea fizică." "realizarea de fotografii și videoclipuri" "Această aplicație poate să facă fotografii și să înregistreze videoclipuri folosind camera foto în orice moment." + "Permiteți unei aplicații sau unui serviciu să primească apeluri inverse atunci când sunt deschise sau închise dispozitive cu cameră." + "Această aplicație cu semnătură poate primi apeluri inverse atunci când este deschis (de un pachet al aplicației) sau închis orice dispozitiv cu cameră." "controlează vibrarea" "Permite aplicației să controleze mecanismul de vibrare." "apelare directă numere de telefon" @@ -453,9 +455,11 @@ "Permite aplicației să continue un apel care a fost inițiat dintr-o altă aplicație." "să citească numerele de telefon" "Permite aplicației să acceseze numerele de telefon ale dispozitivului." + "menține ecranul mașinii activat" "împiedicarea computerului tablet PC să intre în repaus" "împiedică intrarea televizorului în stare de inactivitate" "împiedicare intrare telefon în repaus" + "Permite aplicației să mențină ecranul mașinii activat." "Permite aplicației să împiedice intrarea tabletei în stare de repaus." "Permite aplicației să împiedice intrarea televizorului în stare de inactivitate." "Permite aplicației să împiedice intrarea telefonului în stare de repaus." diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 01bd4709b066..1d4d9b2c9eed 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -306,7 +306,7 @@ "Разрешить приложению <b>%1$s</b> записывать аудио?" "Физическая активность" "доступ к данным о физической активности" - "Открыть приложению <b>%1$s</b> доступ к данным о физической активности?" + "Разрешить приложению <b>%1$s</b> доступ к данным о физической активности?" "Камера" "снимать фото и видео" "Разрешить приложению <b>%1$s</b> снимать фото и видео?" @@ -440,6 +440,8 @@ "Приложение может распознавать физическую активность." "Фото- и видеосъемка" "Приложение может в любое время делать фотографии и снимать видео с помощью камеры." + "Разрешить приложению или сервису получать обратные вызовы при открытии и закрытии камер" + "Это приложение для создания подписей сможет получать обратные вызовы при открытии (с указанием открывающего приложения) и закрытии любых камер." "Управление функцией вибросигнала" "Приложение сможет контролировать вибросигналы." "Осуществление телефонных вызовов" @@ -456,9 +458,11 @@ "Разрешает приложению продолжить вызов, начатый в другом приложении." "чтение номеров телефонов" "Разрешает приложению доступ к телефонным номерам устройства." + "Не выключать экран автомобиля" "Отключение спящего режима" "запрещать переход в спящий режим" "Отключение спящего режима" + "Приложение сможет держать экран автомобиля включенным." "Приложение сможет запрещать перевод планшетного ПК в спящий режим." "Отключение перехода телевизора в спящий режим." "Приложение сможет запрещать перевод телефона в спящий режим." @@ -756,7 +760,7 @@ "MMS" "Особый" "День рождения" - "Юбилей" + "Годовщина" "Другой" "Новый тип" "Личный" @@ -1180,7 +1184,7 @@ "Редактировать с помощью приложения:" "Редактировать с помощью приложения \"%1$s\"" "Изменить" - "Отправка данных" + "Поделиться" "Поделиться через %1$s" "Поделиться" "Выберите приложение" diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 77055f439c43..973571a8844f 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -434,6 +434,8 @@ "මෙම යෙදුමට ඔබේ ශාරීරික ක්‍රියාකාරකම හඳුනා ගැනීමට නොහැකිය" "පින්තූර සහ වීඩියෝ ගන්න" "මෙම යෙදුමට ඕනෑම වේලාවක කැමරාව භාවිත කර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට හැකිය." + "විවෘත වෙමින් හෝ වැසෙමින් පවතින කැමරා උපාංග පිළිබඳ පසු ඇමතුම් ලබා ගැනීමට යෙදුමකට හෝ සේවාවකට ඉඩ දෙන්න." + "මෙම අත්සන් යෙදුමට ඕනෑම කැමරා යෙදුමක් විවෘත වෙමින් හෝ වැසෙමින් (කුමන යෙදුම් පැකේජයෙන්ද) පවතින විට පසු ඇමතුම් ලබා ගැනීමට හැකිය." "කම්පනය පාලනය කිරීම" "කම්පකය පාලනයට යෙදුමට අවසර දෙන්න." "දුරකථන අංක වෙත ඍජුවම අමතන්න" @@ -450,9 +452,11 @@ "වෙනත් යෙදුමක ආරම්භ කරන ලද ඇමතුමක් දිගටම කරගෙන යාමට යෙදුමට ඉඩ දෙයි." "දුරකථන අංක කියවන්න" "උපාංගයේ දුරකථන අංක වෙත ප්‍රවේශයට යෙදුමට ඉඩ දෙයි." + "මෝටර් රථ තිරය ක්‍රියාත්මකව තබා ගන්න" "ටැබ්ලටය නින්දෙන් වැළක්වීම" "රූපවාහිනිය නින්දට යාමෙන් නවත්වන්න" "දුරකථනය නින්දට යාමෙන් වළකන්න" + "යෙදුමට මෝටර් රථ තිරය ක්‍රියාත්මකව තබා ගැනීමට ඉඩ දෙයි." "ටැබ්ලටය නින්දට යාමෙන් වැලැක්වීමට යෙදුමට අවසර දෙන්න." "යෙදුමට රූපවාහිනිය නින්දට යාමට නැවැත්වීම අවසර දෙයි." "දුරකථනය නින්දට යාමෙන් වැලැක්වීමට යෙදුමට අවසර දෙන්න." diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 31e8915cda4a..4b14c49a0c08 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -440,6 +440,8 @@ "Táto aplikácia dokáže rozpoznať vašu fyzickú aktivitu." "fotiť a nakrúcať videá" "Táto aplikácia môže kedykoľvek fotografovať a zaznamenávať videá pomocou fotoaparátu." + "Povoliť aplikácii alebo službe prijímať spätné volanie, keď sú zariadenia s kamerou otvorené alebo zatvorené." + "Táto podpisová aplikácia môže prijímať spätné volanie, keď je ľubovoľné zariadenie s kamerou otvorené (balíkom aplikácie, ktorý určíte) alebo zatvorené." "ovládať vibrovanie" "Umožňuje aplikácii ovládať vibrácie." "priamo volať na telefónne čísla" @@ -456,9 +458,11 @@ "Umožňuje aplikácii pokračovať v hovore začatom v inej aplikácii." "čítanie telefónnych čísel" "Umožňuje aplikácii pristupovať k telefónnym číslam zariadenia." + "zabránenie vypnutiu obrazovky auta" "zabránenie prechodu tabletu do režimu spánku" "zabránenie televízoru v prechode do režimu spánku" "deaktivovať režim spánku" + "Umožňuje aplikácii zabrániť vypnutiu obrazovky auta." "Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku." "Umožňuje aplikácii zabrániť televízoru v prechode do režimu spánku." "Umožňuje aplikácii zabrániť prechodu telefónu do režimu spánku." @@ -2005,7 +2009,7 @@ "Sociálne siete a komunikácia" "Noviny a časopisy" "Mapy a navigácia" - "Produktivita" + "Kancelárske" "Úložisko zariadenia" "Ladenie cez USB" "hodina" diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 8d3827f489a4..8a1579e77462 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -440,6 +440,8 @@ "Ta aplikacija lahko prepoznava vašo telesno dejavnost." "fotografiranje in snemanje videoposnetkov" "Ta aplikacija lahko poljubno uporablja fotoaparat za snemanje fotografij ali videoposnetkov." + "Aplikaciji ali storitvi dovoli prejemanje povratnih klicev o odpiranju ali zapiranju naprav s fotoaparati." + "Ta aplikacija za podpise lahko prejema povratne klice, ko se odpira (s katerim paketom aplikacij) ali zapira katera koli naprava s fotoaparatom." "nadzor vibriranja" "Aplikaciji omogoča nadzor vibriranja." "neposredno klicanje telefonskih številk" @@ -456,9 +458,11 @@ "Aplikaciji dovoljuje nadaljevanje klica, ki se je začel v drugi aplikaciji." "branje telefonskih številk" "Aplikaciji dovoljuje dostop do telefonskih številk v napravi." + "Ohranjanje vklopljenega zaslona avtomobila" "preprečitev prehoda tabličnega računalnika v stanje pripravljenosti" "preprečevanje preklopa televizorja v stanje pripravljenosti" "preprečevanje prehoda v stanje pripravljenosti telefona" + "Aplikaciji omogoča, da zaslon avtomobila ohranja vklopljen." "Omogoča, da aplikacija prepreči prehod tabličnega računalnika v stanje pripravljenosti." "Aplikaciji dovoljuje, da prepreči preklop televizorja v stanje pripravljenosti." "Aplikaciji omogoča, da v telefonu prepreči prehod v stanje pripravljenosti." diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 7d3368d695c1..decc3387a4d6 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -434,6 +434,8 @@ "Ky aplikacion mund të njohë aktivitetin tënd fizik." "bëj fotografi dhe video" "Ky aplikacion mund të nxjerrë fotografi dhe të regjistrojë video me kamerën tënde në çdo kohë." + "Lejo që një aplikacion ose shërbim të marrë telefonata mbrapsht për pajisjet e kamerës që hapen ose mbyllen." + "Ky aplikacion i nënshkrimit mund të marrë telefonata mbrapsht kur hapet ose mbyllet një pajisje e kamerës (nga një paketë e aplikacionit)." "kontrollo dridhjen" "Lejon aplikacionin të kontrollojë dridhësin." "telefono drejtpërdrejt numrat e telefonit" @@ -450,9 +452,11 @@ "Lejon që aplikacioni të vazhdojë një telefonatë që është nisur në një aplikacion tjetër." "lexo numrat e telefonit" "Lejon që aplikacioni të ketë qasje te numrat e telefonit të pajisjes." + "të mbajë ekranin e makinës të aktivizuar" "parandalo kalimin e tabletit në fjetje" "parandalo kalimin e televizorit në fjetje" "parandalo kalimin e telefonit në fjetje" + "Lejon që aplikacioni të mbajë ekranin e makinës të aktivizuar." "Lejon aplikacionin të parandalojë tabletin nga fjetja." "Lejon aplikacionin të parandalojë televizorin nga fjetja." "Lejon aplikacionin të parandalojë telefonin nga fjetja." @@ -1333,7 +1337,7 @@ "Mos lejo asnjëherë" "Karta SIM u hoq" "Rrjeti celular nuk do të mundësohet derisa ta rinisësh pajisjen me një kartë të vlefshme SIM në të." - "U krye!" + "U krye" "Karta SIM u shtua" "Rinise pajisjen për të pasur qasje në rrjetin celular." "Rifillo" @@ -1346,7 +1350,7 @@ "Cakto kohën" "Vendos datën" "Cakto" - "U krye!" + "U krye" "E RE: " "Ofruar nga %1$s." "Nuk kërkohen leje" @@ -1447,7 +1451,7 @@ "Kërko" "Dërgo" "Përpara" - "U krye!" + "U krye" "I mëparshëm" "Ekzekuto" "Telefono numrin\nduke përdorur %s" @@ -1498,7 +1502,7 @@ %d nga gjithsej %d 1 përputhje - "U krye!" + "U krye" "Po fshin hapësirën ruajtëse të brendshme…" "Shpërndaj" "Gjej" @@ -1539,7 +1543,7 @@ "Alt" "Anulo" "Fshi" - "U krye!" + "U krye" "Ndryshim modaliteti" "Shift" "Enter" @@ -1799,7 +1803,7 @@ "Po shikon ekranin e plotë" "Për të dalë, rrëshqit nga lart poshtë." "E kuptova" - "U krye!" + "U krye" "Rrëshqitësi rrethor i orëve" "Rrëshqitësi rrethor i minutave" "Përzgjidh orët" diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index afea01a24265..e7110fe6ed02 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -297,7 +297,7 @@ "Желите ли да омогућите да <b>%1$s</b> шаље и прегледа SMS-ове?" "Меморијски простор" "приступа сликама, медијима и датотекама на уређају" - "Желите ли да омогућите да <b>%1$s</b> приступа сликама, медијским датотекама и датотекама на уређају?" + "Желите ли да омогућите да <b>%1$s</b> приступа сликама, медијским и другим датотекама на уређају?" "Микрофон" "снима звук" "Желите ли да омогућите да <b>%1$s</b> снима звук?" @@ -437,6 +437,8 @@ "Ова апликација може да препозна физичке активности." "снимање фотографија и видео снимака" "Ова апликација може да снима фотографије и видео снимке помоћу камере у било ком тренутку." + "Дозволите апликацији или услузи да добија повратне позиве о отварању или затварању уређаја са камером." + "Ова апликација за потписе може да добија повратне позиве када се било који уређај са камером отвара или затвара (помоћу неког пакета апликација)." "контрола вибрације" "Дозвољава апликацији да контролише вибрацију." "директно позивање бројева телефона" @@ -453,9 +455,11 @@ "Дозвољава апликацији да настави позив који је започет у другој апликацији." "читање бројева телефона" "Дозвољава апликацији да приступа бројевима телефона на уређају." + "не искључуј екран у аутомобилу" "спречавање преласка таблета у стање спавања" "спречавање ТВ-а да пређе у стање спавања" "спречавање преласка телефона у стање спавања" + "Дозвољава апликацији да не искључује екран у аутомобилу." "Дозвољава апликацији да спречи таблет да пређе у стање спавања." "Дозвољава апликацији да спречи ТВ да пређе у стање спавања." "Дозвољава апликацији да спречи телефон да пређе у стање спавања." diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index d4d980d8a560..82c1336e6d67 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -209,7 +209,7 @@ "Förbereder uppdatering …" "Uppdateringspaketet behandlas ..." "Startar om …" - "Återställ standardinställning" + "Återställer standardinställning" "Startar om …" "Avslutar…" "Din surfplatta stängs av." @@ -298,7 +298,7 @@ "Mikrofon" "spela in ljud" "Vill du ge <b>%1$s</b> behörighet att spela in ljud?" - "Fysiska aktivitet" + "Fysisk aktivitet" "åtkomst till data om fysisk aktivitet" "Vill du ge <b>%1$s</b> åtkomst till data om fysisk aktivitet?" "Kamera" @@ -434,6 +434,8 @@ "Den här appen kan känna igen fysisk aktivitet." "ta bilder och spela in videoklipp" "Appen kan ta kort och spela in video med kameran när som helst." + "Tillåt att en app eller tjänst får återanrop när en kameraenhet öppnas eller stängs." + "Den här signerade appen kan få återanrop när en kameraenhet öppnas (efter applikationspaket) eller stängs." "styra vibration" "Tillåter att appen styr vibrationen." "ringa telefonnummer direkt" @@ -450,9 +452,11 @@ "Tillåter att appen fortsätter ett samtal som har startats i en annan app." "läsa telefonnummer" "Appen beviljas åtkomst till enhetens telefonnummer." + "låta bilens skärm vara på" "förhindra att surfplattan går in i viloläge" "förhindra att TV:n försätts i viloläge" "förhindra att telefonen sätts i viloläge" + "Tillåter appen att låta bilens skärm vara på." "Tillåter att appen förhindrar att surfplattan går in i viloläge." "Tillåter att appen förhindrar att TV:n försätts i viloläge." "Tillåter att appen förhindrar att mobilen går in i viloläge." diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 1bca94a195e6..90ef9489adb9 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -434,6 +434,8 @@ "Programu hii inaweza kutambua shughuli unazofanya." "Kupiga picha na kurekodi video" "Programu hii inaweza kupiga picha na kurekodi video kwa kutumia kamera wakati wowote." + "Ruhusu programu au huduma ipokee simu zinazopigwa tena kuhusu vifaa vya kamera kufunguliwa au kufungwa." + "Programu ya sahihi inaweza kupokea simu zinazopigwa tena wakati kifaa chochote cha kamera kinafunguliwa (kulingana na kifurushi cha programu) au kufungwa." "Kudhibiti mtetemo" "Inaruhusu programu kudhibiti kitingishi." "piga simu moja kwa moja kwa nambari za simu" @@ -450,9 +452,11 @@ "Huruhusu programu kuendelea na simu ambayo ilianzishwa katika programu nyingine." "kusoma nambari za simu" "Inaruhusu programu kufikia nambari za simu zilizo kwenye kifaa." + "kuweka skrini ya gari isijizime" "zuia kompyuta ndogo dhidi ya kulala" "zuia runinga isiingie katika hali tuli" "kuzuia simu isilale" + "Huruhusu programu kuweka skrini ya gari isijizime." "Inaruhusu programu kuzuia kompyuta kibao kwenda kulala." "Huruhusu programu kuzuia runinga kuingia katika hali tuli" "Inaruhusu programu kuzuia simu isiende kulala." @@ -1267,7 +1271,7 @@ "Ungependa kuruhusu mitandao inayopendekezwa ya Wi-Fi?" "Mitandao inayopendekezwa kwa ajili ya %s. Huenda kifaa kikaunganisha kiotomatiki." "Ruhusu" - "Hapana, asante" + "Hapana" "Wi‑Fi itawashwa kiotomatiki" "Unapokuwa karibu na mtandao uliohifadhiwa wenye ubora wa juu" "Usiwashe tena" @@ -1964,7 +1968,7 @@ "Ungependa kusasisha %1$s na %2$s katika ""%3$s""?" "Ungependa kusasisha vipengee hivi katika ""%4$s"": %1$s, %2$s na %3$s?" "Hifadhi" - "Hapana, asante" + "Hapana" "Sasisha" "nenosiri" "anwani" diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 134a5f449046..c21f9ce6643e 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -377,7 +377,7 @@ "நினைவகத்தில் நிலையாக இருக்கும் தன்னுடைய பகுதிகளை உருவாக்கப் ஆப்ஸை அனுமதிக்கிறது. இதனால பிற பயன்பாடுகளுக்குக் கிடைக்கும் நினைவகம் வரையறுக்கப்பட்டு, மொபைலின் வேகத்தைக் குறைக்கலாம்" "முன்புலத்தில் இயங்கும் சேவையை இயக்குதல்" "முன்புலத்தில் இயங்கும் சேவைகளை உபயோகிக்க, ஆப்ஸை அனுமதிக்கிறது." - "பயன்பாட்டுச் சேமிப்பு இடத்தை அளவிடல்" + "ஆப்ஸ் சேமிப்பு இடத்தை அளவிடல்" "ஆப்ஸ், அதன் குறியீடு, தரவு, மற்றும் தற்காலிகச் சேமிப்பு அளவுகளை மீட்டெடுக்க அனுமதிக்கிறது" "சாதன அமைப்புகளை மாற்றுதல்" "முறைமையின் அமைப்பு தரவைத் திருத்த, ஆப்ஸை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் ஆப்ஸ், முறைமையின் உள்ளமைவைச் சிதைக்கலாம்." @@ -434,6 +434,10 @@ "உங்கள் உடல் செயல்பாட்டை இந்த ஆப்ஸால் கண்டறிய முடியும்." "படங்கள் மற்றும் வீடியோக்களை எடுத்தல்" "இந்த ஆப்ஸ் எப்போது வேண்டுமானாலும் கேமராவைப் பயன்படுத்தி படங்களை எடுக்கலாம், வீடியோக்களை ரெக்கார்டு செய்யலாம்." + + + + "அதிர்வைக் கட்டுப்படுத்துதல்" "அதிர்வைக் கட்டுப்படுத்தப் ஆப்ஸை அனுமதிக்கிறது." "தொலைபேசி எண்களை நேரடியாக அழைத்தல்" @@ -450,9 +454,11 @@ "மற்றொரு பயன்பாட்டில் தொடங்கப்பட்ட அழைப்பைத் தொடருவதற்கு, ஆப்ஸை அனுமதிக்கிறது." "ஃபோன் எண்களைப் படித்தல்" "சாதனத்தின் ஃபோன் எண்களை அணுக, ஆப்ஸை அனுமதிக்கும்." + "கார் திரையை ஆன் செய்து வைத்திருத்தல்" "டேப்லெட் உறக்க நிலைக்குச் செல்வதைத் தடுத்தல்" "டிவி உறக்கநிலைக்குச் செல்வதைத் தடுத்தல்" "தொலைபேசி உறக்கநிலைக்குச் செல்வதைத் தடுத்தல்" + "கார் திரையை ஆன் செய்து வைத்திருப்பதற்கு இந்த ஆப்ஸை அனுமதிக்கும்." "உறக்கநிலைக்குச் செல்லாமல் டேப்லெட்டைத் தடுக்க ஆப்ஸை அனுமதிக்கிறது." "டிவி உறக்க நிலைக்குச் செல்வதைத் தடுக்க, ஆப்ஸை அனுமதிக்கிறது." "உறக்கநிலைக்குச் செல்லாமல் மொபைலைத் தடுக்க ஆப்ஸை அனுமதிக்கிறது." @@ -475,7 +481,7 @@ "நெட்வொர்க் இணைப்புகளைக் காட்டு" "தற்போது இருக்கும் நெட்வொர்க்குகள் எவை மற்றும் இணைக்கப்பட்டுள்ளவை எவை போன்ற நெட்வொர்க் இணைப்புகள் குறித்த தகவலைப் பார்க்கப் ஆப்ஸை அனுமதிக்கிறது." "முழுமையான நெட்வொர்க் அணுகலைக் கொண்டிருக்கும்" - "நெட்வொர்க் சாக்கெட்டுகளை உருவாக்கவும் மற்றும் தனிப்பயன் நெட்வொர்க் நெறிமுறைகளைப் பயன்படுத்தவும் ஆப்ஸை அனுமதிக்கிறது. இணையத்தில் தரவை அனுப்ப உலாவியும், பிற பயன்பாடுகளும் இருப்பதால், இணையத்திற்குத் தரவை அனுப்ப இந்த அனுமதி தேவையில்லை." + "நெட்வொர்க் சாக்கெட்டுகளை உருவாக்கவும் மற்றும் பிரத்தியேக நெட்வொர்க் நெறிமுறைகளைப் பயன்படுத்தவும் ஆப்ஸை அனுமதிக்கிறது. இணையத்தில் தரவை அனுப்ப உலாவியும், பிற பயன்பாடுகளும் இருப்பதால், இணையத்திற்குத் தரவை அனுப்ப இந்த அனுமதி தேவையில்லை." "பிணைய இணைப்புத்தன்மையை மாற்றுதல்" "நெட்வொர்க் இணைப்பின் நிலையை மாற்ற, ஆப்ஸை அனுமதிக்கிறது." "இணைக்கப்பட்ட இணைப்புநிலையை மாற்றுதல்" @@ -692,30 +698,30 @@ "வீட்டு தொலைநகல்" "பேஜர்" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "அலுவலகம்" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "அலுவலகம்" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "அலுவலகம்" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "அலுவலகம்" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "AIM" @@ -727,7 +733,7 @@ "ICQ" "Jabber" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "மொபைல்" "அலுவலகம்" @@ -748,24 +754,24 @@ "பணியிட பேஜர்" "உதவியாளர்" "MMS" - "தனிப்பயன்" + "பிரத்தியேகம்" "பிறந்தநாள்" "ஆண்டுவிழா" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "அலுவலகம்" "மற்றவை" "மொபைல்" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "அலுவலகம்" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "அலுவலகம்" "மற்றவை" - "தனிப்பயன்" + "பிரத்தியேகம்" "AIM" "Windows Live" "Yahoo" @@ -777,8 +783,8 @@ "NetMeeting" "அலுவலகம்" "மற்றவை" - "தனிப்பயன்" - "தனிப்பயன்" + "பிரத்தியேகம்" + "பிரத்தியேகம்" "உதவியாளர்" "சகோதரர்" "குழந்தை" @@ -793,7 +799,7 @@ "உறவினர்" "சகோதரி" "துணைவர்" - "தனிப்பயன்" + "பிரத்தியேகம்" "வீடு" "அலுவலகம்" "மற்றவை" @@ -828,8 +834,8 @@ "சிம் கார்டு இல்லை அல்லது படிக்கக்கூடியதாக இல்லை. சிம் கார்டைச் செருகவும்." "பயன்படுத்த முடியாத சிம் கார்டு." "உங்கள் சிம் கார்டு நிரந்தரமாக முடக்கப்பட்டது.\n மற்றொரு சிம் கார்டிற்காக உங்கள் வயர்லெஸ் சேவை வழங்குநரைத் தொடர்புகொள்ளவும்." - "முந்தைய ட்ராக்" - "அடுத்த ட்ராக்" + "முந்தைய டிராக்" + "அடுத்த டிராக்" "இடைநிறுத்து" "இயக்கு" "நிறுத்து" @@ -1989,7 +1995,7 @@ "+ %1$d" "ஆப்ஸ் முந்தையப் பதிப்பிற்கு மாற்றப்பட்டது, அல்லது இந்த ஷார்ட்கட் வேலை செய்யவில்லை" "காப்புப் பிரதி மற்றும் மீட்டமைவைப் ஆப்ஸ் ஆதரிக்காத காரணத்தால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை" - "பயன்பாட்டுச் சான்றுகள் பொருந்தாத காரணத்தினால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை" + "ஆப்ஸ் சான்றுகள் பொருந்தாத காரணத்தினால், ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை" "ஷார்ட்கட்டை மீட்டமைக்க முடியவில்லை" "ஷார்ட்கட் முடக்கப்பட்டுள்ளது" "நிறுவல் நீக்கு" diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 6b7296278ede..9064c06f2b05 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -434,6 +434,8 @@ "ఈ యాప్ మీ భౌతిక కార్యాకలాపాన్ని గుర్తించగలదు." "చిత్రాలు మరియు వీడియోలు తీయడం" "ఈ యాప్‌ కెమెరాను ఉపయోగించి ఎప్పుడైనా చిత్రాలను తీయగలదు మరియు వీడియోలను రికార్డ్ చేయగలదు." + "కెమెరా పరికరాలు తెరుచుకుంటున్నప్పుడు లేదా మూసుకుంటున్నప్పుడు కాల్‌బ్యాక్‌లను స్వీకరించడానికి యాప్‌ను లేదా సర్వీస్‌ను అనుమతించండి." + "ఏదైనా కెమెరా పరికరం తెరుచుకుంటున్నప్పుడు (ఏదైనా యాప్ ప్యాకేజీ ద్వారా) లేదా మూసుకుంటున్నప్పుడు ఈ సిగ్నేచర్ యాప్ కాల్‌బ్యాక్‌లను అందుకోగలదు." "వైబ్రేషన్‌ను నియంత్రించడం" "వైబ్రేటర్‌ను నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది." "నేరుగా కాల్ చేసే ఫోన్ నంబర్‌లు" @@ -450,9 +452,11 @@ "మరో యాప్‌లో ప్రారంభించిన కాల్‌ని కొనసాగించడానికి యాప్‌ని అనుమతిస్తుంది." "ఫోన్ నంబర్‌లను చదువు" "పరికరం యొక్క ఫోన్ నంబర్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది." + "కార్ స్క్రీన్‌ను ఆన్ చేసి ఉంచండి" "టాబ్లెట్‌ను నిద్రావస్థకు వెళ్లనీయకుండా నిరోధించడం" "టీవీ నిద్రావస్థకు వెళ్లకుండా నిరోధించడం" "ఫోన్‌ను స్లీప్ మోడ్‌లోకి వెళ్లనీయకుండా నిరోధించగలగడం" + "కార్ స్క్రీన్ ఆన్ చేసి ఉంచడానికి ఈ యాప్‌ను అనుమతిస్తుంది." "నిద్రావస్థకి వెళ్లకుండా టాబ్లెట్‌ను నిరోధించడానికి యాప్‌ను అనుమతిస్తుంది." "టీవీ నిద్రావస్థకు వెళ్లకుండా నిరోధించడానికి అనువర్తనాన్ని అనుమతిస్తుంది." "నిద్రావస్థకి వెళ్లకుండా ఫోన్‌ను నిరోధించడానికి యాప్‌ను అనుమతిస్తుంది." diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 020196e0af6e..b1d6e10495ea 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -434,6 +434,8 @@ "แอปนี้จดจำกิจกรรมการเคลื่อนไหวร่างกายของคุณได้" "ถ่ายภาพและวิดีโอ" "แอปนี้สามารถถ่ายภาพและวิดีโอด้วยกล้องได้ทุกเมื่อ" + "อนุญาตให้แอปพลิเคชันหรือบริการได้รับโค้ดเรียกกลับเมื่อมีการเปิดหรือปิดอุปกรณ์กล้อง" + "แอปลายเซ็นนี้จะได้รับโค้ดเรียกกลับเมื่อมีการปิดหรือเปิดอุปกรณ์กล้อง (แพ็กเกจแอปพลิเคชันที่เปิด)" "ควบคุมการสั่นเตือน" "อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน" "โทรติดต่อหมายเลขโทรศัพท์โดยตรง" @@ -450,9 +452,11 @@ "อนุญาตให้แอปต่อสายที่เริ่มจากแอปอื่น" "อ่านหมายเลขโทรศัพท์" "อนุญาตให้แอปเข้าถึงหมายเลขโทรศัพท์ของอุปกรณ์นี้" + "เปิดหน้าจอในรถไว้" "ป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป" "ป้องกันไม่ให้ทีวีเข้าสู่โหมดสลีป" "ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป" + "อนุญาตให้แอปเปิดหน้าจอในรถไว้" "อนุญาตให้แอปพลิเคชันป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป" "อนุญาตให้แอปป้องกันไม่ให้ทีวีเข้าสู่โหมดสลีป" "อนุญาตให้แอปพลิเคชันป้องกันไม่ให้โทรศัพท์เข้าสู่โหมดสลีป" diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index b500b235dd5d..97209a71d781 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -434,6 +434,8 @@ "Matutukoy ng app na ito ang iyong pisikal na aktibidad." "kumuha ng mga larawan at video" "Makakakuha ng mga larawan at makakapag-record ng mga video ang app na ito gamit ang camera anumang oras." + "Payagan ang isang application o serbisyo na makatanggap ng mga callback tungkol sa pagbubukas o pagsasara ng mga camera device." + "Ang signature app na ito ay makakatanggap ng mga callback kapag binubuksan (ng anumang application package) o isinasara ng anumang camera device." "kontrolin ang pag-vibrate" "Pinapayagan ang app na kontrolin ang vibrator." "direktang tawagan ang mga numero ng telepono" @@ -450,9 +452,11 @@ "Pinapayagan ang app na ipagpatuloy ang isang tawag na sinimulan sa ibang app." "basahin ang mga numero ng telepono" "Pinapayagan ang app na i-access ang mga numero ng telepono ng device." + "panatilihing naka-on ang screen ng sasakyan" "pigilan ang tablet mula sa pag-sleep" "pigilan ang TV sa pag-sleep" "pigilan ang telepono mula sa paghinto" + "Pinapayagan ang app na panatilihing naka-on ang screen ng sasakyan." "Pinapayagan ang app na pigilan ang tablet mula sa pag-sleep." "Nagbibigay-daan sa app na pigilan ang TV na mapunta sa sleep." "Pinapayagan ang app na pigilan ang telepono mula sa pag-sleep." diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index c93cb552ae2e..84cbacdf01cb 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -434,6 +434,8 @@ "Bu uygulama fiziksel aktivitenizi algılayabilir." "resim çekme ve görüntü kaydetme" "Bu uygulama, herhangi bir zamanda kamerayı kullanarak fotoğraf ve video çekebilir." + "Bir uygulama veya hizmetin açılıp kapatılan kamera cihazları hakkında geri çağırmalar almasına izin verin." + "Bu imza uygulaması, herhangi bir kamera cihazı açıldığında (herhangi bir uygulama paketi tarafından) veya kapatıldığında geri çağırmalar alabilir." "titreşimi denetleme" "Uygulamaya, titreşimi denetleme izni verir." "telefon numaralarına doğrudan çağrı yap" @@ -450,9 +452,11 @@ "Uygulamanın, başka bir uygulamada başlatılan çağrıya devam etmesine izin verir." "telefon numaralarını oku" "Uygulamaya, cihazınızın telefon numaralarına erişme izni verir." + "arabanın ekranını açık tutma" "tabletin uykuya geçmesini önle" "TV\'nin uyku moduna geçmesini önleme" "telefonun uykuya geçmesini önleme" + "Uygulamaya, arabanın ekranını açık tutmaya izin verir." "Uygulamaya, tabletin uykuya geçmesini önleme izni verir." "Uygulamaya, TV\'nin uyku moduna geçmesini önleme izni verir." "Uygulamaya, telefonun uykuya geçmesini önleme izni verir." diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 5d8481195652..158696503519 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -440,6 +440,8 @@ "Цей додаток може розпізнавати фізичну активність." "фотограф. та знімати відео" "Цей додаток може будь-коли робити фотографії та записувати відео за допомогою камери." + "Дозволити додатку або сервісу отримувати зворотні виклики щодо відкриття чи закриття камер." + "Цей додаток для підпису може отримувати зворотні виклики, коли будь-яка камера відкривається (з указанням пакета додатка) чи закривається." "контролювати вібросигнал" "Дозволяє програмі контролювати вібросигнал." "прямо набирати номери тел." @@ -456,9 +458,11 @@ "Додаток може продовжувати виклик, початий в іншому додатку." "переглядати номери телефону" "Надає додаткам доступ до номерів телефону на пристрої." + "залишати екран автомобіля ввімкненим" "не доп.перехід пристр.в реж.сну" "не допускати перехід телевізора в режим сну" "Вимкнення режиму сну" + "Дозволяє додатку залишати екран автомобіля ввімкненим." "Дозволяє програмі не допускати перехід планшетного ПК у режим сну." "Додаток може не допускати перехід телевізора в режим сну." "Дозволяє програмі не допускати перехід телефону в режим сну." diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 1c1dda8d1472..777da6c64175 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -434,6 +434,10 @@ "یہ ایپ آپ کی جسمانی سرگرمی کی شناخت کر سکتی ہے۔" "تصاویر لیں اور ویڈیوز بنائیں" "یہ ایپ کسی بھی وقت کیمرا استعمال کرتے ہوئے تصاویر لے سکتی ہے اور ویڈیوز ریکارڈ کر سکتی ہے۔" + + + + "ارتعاش کو کنٹرول کریں" "ایپ کو وائبریٹر کنٹرول کرنے کی اجازت دیتا ہے۔" "براہ راست فون نمبرز پر کال کریں" @@ -450,9 +454,11 @@ "ایپ کو دوسری ایپ میں شروع کردہ کال کو جاری رکھنے کی اجازت ملتی ہے۔" "فون نمبرز پڑھیں" "ایپ کو آلہ کے فون نمبرز تک رسائی کرنے دیتا ہے۔" + "کار کی اسکرین آن رکھیں" "ٹیبلیٹ کو سلیپ وضع میں جانے سے روکیں" "‏TV کو سلیپ وضع میں جانے سے روکیں" "فون کو سلیپ وضع میں جانے سے روکیں" + "ایپ کو کار کی اسکرین آن رکھنے کی اجازت دیتا ہے۔" "ایپ کو ٹیبلیٹ کو سلیپ وضع میں جانے سے روکنے کی اجازت دیتا ہے" "‏ایپ کو TV کو سلیپ وضع میں جانے سے روکنے کی اجازت دیتا ہے۔" "ایپ کو فون کو سلیپ وضع میں جانے سے روکنے کی اجازت دیتا ہے" diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index cf4c874eb83f..4d0e33042bb4 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -434,6 +434,8 @@ "Bu ilova jismoniy harakatlaringizni aniqlay oladi." "rasm va videoga olish" "Bu ilova xohlagan vaqtda kamera orqali suratga olishi va video yozib olishi mumkin." + "Ilova yoki xizmatga kamera qurilmalari ochilayotgani yoki yopilayotgani haqida qayta chaqiruvlar qabul qilishi uchun ruxsat berish." + "Bu imzo ilovasi har qanday kamera qurilmasi ochilayotganda (istalgan ilova paketi tarafidan) yoki yopilayotganda qayta chaqiruvlar qabul qilishi mumkin." "tebranishni boshqarish" "Ilova tebranishli signallarni boshqarishi mumkin." "telefon raqamlariga tog‘ridan to‘g‘ri qo‘ng‘iroq qilish" @@ -450,9 +452,11 @@ "Ilovaga boshqa ilovada boshlangan chaqiruvni davom ettirish imkon beradi" "telefon raqamlarini o‘qish" "Ilovaga qurilmaning telefon raqamlaridan foydalanishiga ruxsat beradi." + "avtomobil ekranini yoniq holatda saqlab turish" "planshetni uyquga ketishiga yo‘l qo‘ymaslik" "televizorning uyqu rejimiga o‘tishining oldini olish" "telefonni uxlashiga yo‘l qo‘ymaslik" + "Ilova avtomobil ekranini yoniq holatda saqlaydi." "Ilova planshetning uyqu rejimiga o‘tib qolishining oldini olishi mumkin." "Ilovaga televizorning uyqu rejimiga o‘tishining oldini olish huquqini beradi." "Ilova telefonning uyqu rejimiga o‘tib qolishining oldini olishi mumkin." diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index a155d63a2a1f..f05cd214a351 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -434,6 +434,8 @@ "Ứng dụng này có thể nhận dạng hoạt động thể chất của bạn." "chụp ảnh và quay video" "Ứng dụng này có thể chụp ảnh và quay video bằng máy ảnh bất cứ lúc nào." + "Cho phép một ứng dụng hoặc dịch vụ nhận lệnh gọi lại khi các thiết bị máy ảnh đang được mở/đóng." + "Ứng dụng chữ ký này có thể nhận các lệnh gọi lại khi có bất kỳ thiết bị máy ảnh nào đang được mở (bằng gói ứng dụng) hoặc đóng." "kiểm soát rung" "Cho phép ứng dụng kiểm soát bộ rung." "gọi trực tiếp số điện thoại" @@ -450,9 +452,11 @@ "Cho phép ứng dụng tiếp tục cuộc gọi được bắt đầu trong một ứng dụng khác." "đọc số điện thoại" "Cho phép ứng dụng truy cập số điện thoại của thiết bị." + "duy trì trạng thái bật của màn hình ô tô" "ngăn máy tính bảng chuyển sang chế độ ngủ" "ngăn TV chuyển sang chế độ ngủ" "ngăn điện thoại chuyển sang chế độ ngủ" + "Cho phép ứng dụng này duy trì trạng thái bật của màn hình ô tô." "Cho phép ứng dụng ngăn máy tính bảng chuyển sang chế độ ngủ." "Cho phép ứng dụng ngăn TV chuyển sang chế độ ngủ." "Cho phép ứng dụng ngăn điện thoại chuyển sang chế độ ngủ." diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 833fd533fe73..fee0eab260e5 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -434,6 +434,8 @@ "此应用可以识别您的身体活动。" "拍摄照片和视频" "此应用可随时使用相机拍摄照片和录制视频。" + "允许应用或服务接收与打开或关闭摄像头设备有关的回调。" + "此签名应用可在任何摄像头设备(被某些应用软件包)打开或关闭时接收相应回调。" "控制振动" "允许应用控制振动器。" "拨打电话" @@ -450,9 +452,11 @@ "允许该应用继续进行在其他应用中发起的通话。" "读取电话号码" "允许该应用访问设备上的电话号码。" + "使车载显示屏保持开启状态" "阻止平板电脑进入休眠状态" "阻止电视进入休眠状态" "防止手机休眠" + "允许该应用使车载显示屏保持开启状态。" "允许应用阻止平板电脑进入休眠状态。" "允许应用阻止电视进入休眠状态。" "允许应用阻止手机进入休眠状态。" diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 2309b5005d35..413be2c28315 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -280,7 +280,7 @@ "通訊錄" "存取您的通訊錄" "允許「%1$s」<b></b>存取您的聯絡人嗎?" - "位置資訊" + "位置" "存取此裝置的位置" "允許「%1$s」<b></b>存取此裝置的位置資訊嗎?" "此應用程式目前只有您在使用時才能存取位置資訊" @@ -434,6 +434,8 @@ "此應用程式可識別您的體能活動。" "拍照和拍攝影片" "此應用程式可以隨時使用相機拍照和攝錄。" + "允許應用程式或服務接收相機裝置開啟或關閉的相關回電。" + "當任何相機裝置在開啟 (由應用程式套件) 或關閉時,此簽名應用程式就能接收回電。" "控制震動" "允許應用程式控制震動。" "直接撥打電話號碼" @@ -450,9 +452,11 @@ "允許應用程式繼續進行在其他應用程式中開始的通話。" "讀取電話號碼" "允許應用程式存取裝置上的電話號碼。" + "保持汽車螢幕開啟" "防止平板電腦進入休眠狀態" "阻止電視進入休眠狀態" "防止手機進入休眠狀態" + "允許應用程式保持汽車螢幕開啟。" "允許應用程式防止平板電腦進入休眠狀態。" "允許應用程式阻止電視進入休眠狀態。" "允許應用程式防止手機進入休眠狀態。" diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index cea8c1cd4253..ebbfdf1abbc5 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -434,6 +434,8 @@ "這個應用程式可以辨識你從事的體能活動。" "拍攝相片和影片" "這個應用程式隨時可使用相機拍照及錄影。" + "允許應用程式或服務接收相機裝置開啟或關閉的相關回呼。" + "當任何相機裝置在開啟 (由應用程式套件) 或關閉時,這個簽名應用程式就能接收回呼。" "控制震動" "允許應用程式控制震動。" "直接撥打電話號碼" @@ -450,9 +452,11 @@ "允許應用程式繼續進行在其他應用程式中發起的通話。" "讀取電話號碼" "允許應用程式存取裝置上的電話號碼資料。" + "讓車輛螢幕保持開啟" "防止平板電腦進入休眠狀態" "防止電視進入休眠狀態" "防止手機進入待命狀態" + "允許應用程式讓車輛螢幕保持開啟。" "允許應用程式防止平板電腦進入休眠狀態。" "允許應用程式防止電視進入休眠狀態。" "允許應用程式防止手機進入休眠狀態。" diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 087d0a9fda70..dc51f2ee0e41 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -434,6 +434,8 @@ "Lolu hlelo lokusebenza lingabona umsebenzi wakho." "thatha izithombe namavidiyo" "Lolu hlelo lokusebenza lungathatha izithombe futhi lirekhode amavidiyo lusebenzisa ikhamera noma kunini." + "Vumela uhlelo lokusebenza noma isevisi ukwamukela ukuphinda ufonelwe mayelana namadivayisi wekhamera avuliwe noma avaliwe." + "Lolu hlelo lokusebenza lesiginesha lungakwazi ukuthola ukuphinda ufonelwe uma noma iyiphi idivayisi yekhamera ivuliwe (ngephakheji yohlelo lokusebenza) noma ivaliwe." "lawula ukudlidliza" "Ivumela uhlelo lokusebenza ukulawula isidlidlizi." "ngokuqondile shayela izinombolo zocingo" @@ -450,9 +452,11 @@ "Ivumela uhlelo lokusebenza ukuze luqhube ikholi eqalwe kolunye uhlelo lokusebenza." "funda izinombolo zefoni" "Ivumela uhlelo lokusebenza ukufinyelela izinombolo zefoni zedivayisi." + "gcina isikrini semoto sivuliwe" "gwema ithebhulethi ukuba ingalali" "vimbela i-TV kusukela ekulaleni" "gwema ifoni ukuba ingalali" + "Ivumela uhlelo lokusebenza ukuthi lugcine isikrini semoto sivuliwe." "Ivumela uhlelo lokusebenza ukuthi linqande ithebulethi yakho ukuthi ilale." "Ivumela uhlelo lokusebenza ukuvimbela i-TV ukuthi ilale." "Ivumela uhlelo lokusebenza ukuthi inqande ucingo ukuthi lulale." -- GitLab From 52b5e54980c9045c9b1185ef8ec5ebedd0f2b028 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Mon, 16 Mar 2020 12:20:36 -0700 Subject: [PATCH 141/143] Camera: Clarify CAMERA_OPEN_CLOSE_LISTENER description Test: Build Bug: 151326743 Change-Id: Ia067f3b4021b184504147569374678f81f66daf3 --- core/res/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 044e07420c2d..d33cf42cd051 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1154,7 +1154,7 @@ Allow an application or service to receive callbacks about camera devices being opened or closed. - This signature app can receive callbacks when any camera device is being opened (by what application package) or closed. + This app can receive callbacks when any camera device is being opened (by what application) or closed. control vibration -- GitLab From 2ade5356f8fff3dc04c90a4cf459e0ae5f0e87a8 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Mon, 16 Mar 2020 22:13:38 -0700 Subject: [PATCH 142/143] Import translations. DO NOT MERGE Auto-generated-cl: translation import Change-Id: I1bf088868f58abbb8943fdac2c978dcd478810fe --- packages/SettingsLib/res/values-ar/arrays.xml | 2 +- .../SettingsLib/res/values-ar/strings.xml | 28 +++++++++---------- .../SettingsLib/res/values-es-rUS/strings.xml | 4 +-- .../SettingsLib/res/values-es/strings.xml | 4 +-- .../SettingsLib/res/values-eu/strings.xml | 8 +++--- .../SettingsLib/res/values-fr/strings.xml | 2 +- .../SettingsLib/res/values-gl/strings.xml | 2 +- .../SettingsLib/res/values-ja/strings.xml | 2 +- .../SettingsLib/res/values-ko/strings.xml | 2 +- .../SettingsLib/res/values-ky/strings.xml | 10 +++---- .../SettingsLib/res/values-pt-rPT/strings.xml | 2 +- .../SettingsLib/res/values-ru/strings.xml | 2 +- .../SettingsLib/res/values-ta/strings.xml | 8 +++--- .../SettingsLib/res/values-vi/strings.xml | 2 +- 14 files changed, 39 insertions(+), 39 deletions(-) diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml index 39ba506f2b3a..6e06c59c25a1 100644 --- a/packages/SettingsLib/res/values-ar/arrays.xml +++ b/packages/SettingsLib/res/values-ar/arrays.xml @@ -246,7 +246,7 @@ "عرض مناطق العجز في رؤية اللونين الأخضر والأحمر" - "الحد القياسي" + "الحدّ العادي" "ليست هناك عمليات بالخلفية" "عملية واحدة بحد أقصى" "عمليتان بحد أقصى" diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 2308f06b026a..edc8226c4f47 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -56,7 +56,7 @@ "اكتمل الاشتراك. جارٍ الاتصال…" "بطيئة جدًا" "بطيئة" - "موافق" + "حسنًا" "متوسطة" "سريعة" "سريعة جدًا" @@ -122,7 +122,7 @@ "سماعة رأس" "هاتف" "تصوير" - "سماعة أذن" + "السمّاعة" "جهاز إدخال طرفي" "بلوتوث" "جارٍ إقران سماعة الأذن الطبية اليسرى…" @@ -155,7 +155,7 @@ "إعدادات تحويل النص إلى كلام" "تحويل النص إلى كلام" "معدل سرعة الكلام" - "سرعة نطق الكلام" + "سرعة قول الكلام" "درجة الصوت" "للتأثير في نبرة الكلام المُرَكَّب" "اللغة" @@ -179,7 +179,7 @@ "المحرّك المفضّل" "عامة" "إعادة ضبط طبقة صوت الكلام" - "إعادة ضبط طبقة الصوت التي يتم نطق النص بها على الإعداد التلقائي." + "إعادة ضبط طبقة الصوت التي يتم قول النص بها على الإعداد التلقائي." "بطيء جدًا" "بطيء" @@ -213,7 +213,7 @@ "فتح قفل المصنّع الأصلي للجهاز" "‏السماح بإلغاء قفل برنامج bootloader" "هل تريد السماح بإلغاء قفل المصنّع الأصلي للجهاز؟" - "تحذير: لن تعمل ميزات الحماية على هذا الجهاز أثناء تشغيل هذا الإعداد." + "تحذير: لن تعمل ميزات الحماية على هذا الجهاز أثناء تفعيل هذا الإعداد." "اختيار تطبيق الموقع الزائف" "لم يتم تعيين تطبيق موقع زائف" "تطبيق الموقع الزائف: %1$s" @@ -346,7 +346,7 @@ "نابض بالحياة (تلقائي)" "طبيعي" - "قياسي" + "عادي" "ألوان محسَّنة" @@ -362,11 +362,11 @@ "‏تطبيق WebView" "‏تعيين تطبيق WebView" "لم يعد هذا الاختيار صالحًا. أعد المحاولة." - "التحويل إلى تشفير ملفات" + "التحويل إلى ترميز ملفات" "تحويل…" - "تم استخدام تشفير ملفات من قبل" - "التحويل إلى تشفير على الملف" - "تحويل قسم البيانات إلى تشفير على الملف.\n !!تحذير!! سيؤدي هذا إلى محو جميع بياناتك.\n لا تزال هذه الميزة في مرحلة ألفا، وقد لا تعمل على نحو سليم.\n للمتابعة، اضغط على \"مسح وتحويل…\"." + "تم استخدام ترميز ملفات من قبل" + "التحويل إلى ترميز على الملف" + "تحويل قسم البيانات إلى ترميز على الملف.\n !!تحذير!! سيؤدي هذا إلى محو جميع بياناتك.\n لا تزال هذه الميزة في مرحلة ألفا، وقد لا تعمل على نحو سليم.\n للمتابعة، اضغط على \"مسح وتحويل…\"." "مسح وتحويل…" "نمط لون الصورة" "‏استخدام sRGB" @@ -430,7 +430,7 @@ "أكبر مستوى" "مخصص (%d)" "القائمة" - "إدخال كلمة المرور لإعادة الضبط بحسب بيانات المصنع في الوضع التجريبي" + "إدخال كلمة المرور لإعادة الضبط على الإعدادات الأصلية في الوضع التجريبي" "التالي" "يلزم توفر كلمة مرور" "طرق الإدخال النشطة" @@ -454,9 +454,9 @@ "وقت أكثر." "وقت أقل." "إلغاء" - "موافق" - "تشغيل" - "تشغيل وضع \"الرجاء عدم الإزعاج\"" + "حسنًا" + "تفعيل" + "تفعيل وضع \"الرجاء عدم الإزعاج\"" "مطلقًا" "الأولوية فقط" "%1$s. %2$s" diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 39f44174375c..795980d516b2 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -64,7 +64,7 @@ "Desconectado" "Desconectando…" "Conectando…" - "Conectado a %1$s" + "Conectado%1$s" "Vinculando..." "Conectado (sin teléfono) a %1$s" "Conectado (sin archivos multimedia) a %1$s" @@ -170,7 +170,7 @@ "Este idioma necesita una conexión de red en funcionamiento para la salida de texto a voz." "Ejemplo de síntesis de voz" "Estado del idioma predeterminado" - "El idioma %1$s es totalmente compatible." + "El idioma %1$s es totalmente compatible" "El idioma %1$s requiere una conexión de red." "El idioma %1$s no es compatible." "Comprobando…" diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 76c983105b72..4712d6709736 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -188,7 +188,7 @@ "Más rápida" "Muy rápida" "Superrápida" - "Hiperrrápida" + "Hiperrápida" "La más rápida" "Seleccionar perfil" @@ -200,7 +200,7 @@ "Las opciones de desarrollador no están disponibles para este usuario" "Los ajustes de VPN no están disponibles para este usuario" "Los ajustes para compartir conexión no están disponibles para este usuario" - "Los ajustes del nombre de punto de acceso no están disponibles para este usuario" + "Los ajustes del nombre del punto de acceso no están disponibles para este usuario" "Depuración por USB" "Activar el modo de depuración cuando el dispositivo esté conectado por USB" "Revocar autorizaciones de depuración USB" diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 0722b8dac255..f1bb45fdfea6 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -27,7 +27,7 @@ "Desgaituta" "Ezin izan da konfiguratu IP helbidea" "Ez dago konektatuta sarearen kalitate eskasagatik" - "Ezin izan da konektatu Wi-Fi sarera" + "Ezin izan da konektatu wifi-sarera" "Autentifikazio-arazoa" "Ezin da konektatu" "Ezin da konektatu \"%1$s\" sarera" @@ -122,7 +122,7 @@ "Mikrofonodun entzungailua" "Telefonoa" "Irudietarako gailua" - "Aurikularra" + "Entzungailua" "Idazteko gailua" "Bluetooth gailua" "Ezkerreko audifonoa parekatzen…" @@ -223,7 +223,7 @@ "Wifi-sareen bilaketaren muga" "Datu-konexioa beti aktibo" "Konexioa partekatzeko hardwarearen azelerazioa" - "Erakutsi Bluetooth gailuak izenik gabe" + "Erakutsi Bluetooth bidezko gailuak izenik gabe" "Desgaitu bolumen absolutua" "Bluetooth AVRCP bertsioa" "Hautatu Bluetooth AVRCP bertsioa" @@ -270,7 +270,7 @@ "Ezarpen hauek garapen-xedeetarako pentsatu dira soilik. Baliteke ezarpenen eraginez gailua matxuratzea edo funtzionamendu okerra izatea." "Egiaztatu USBko aplikazioak" "Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak atzemateko" - "Bluetooth gailuak izenik gabe (MAC helbideak soilik) erakutsiko dira" + "Bluetooth bidezko gailuak izenik gabe (MAC helbideak soilik) erakutsiko dira" "Bluetooth bidezko bolumen absolutuaren eginbidea desgaitu egiten du urruneko gailuetan arazoak hautematen badira; esaterako, bolumena ozenegia bada edo ezin bada kontrolatu" "Tokiko terminala" "Gaitu tokiko shell-sarbidea duen terminal-aplikazioa" diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 78dedcfc512b..100088a82ca7 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -56,7 +56,7 @@ "Inscription terminée. Connexion…" "Très lente" "Lente" - "Correct" + "Correcte" "Moyenne" "Élevée" "Très rapide" diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 59b927b424ec..92f0ab07875a 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -309,7 +309,7 @@ "Desactivar encamiñamento audio USB" "Desactiva o encamiñamento automático a periféricos de audio USB" "Mostrar límites de deseño" - "Mostra os límites dos clips, as marxes, etc." + "Mostra os límites dos clips, as marxes etc." "Forzar dirección do deseño RTL" "Forza a dirección de pantalla a RTL (dereita a esquerda) para todas as configuración rexionais" "Forzar MSAA 4x" diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index f2e20fa5e19d..20e200068df9 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -201,7 +201,7 @@ "このユーザーはVPN設定を利用できません。" "このユーザーはテザリング設定を利用できません" "このユーザーはアクセスポイント名設定を利用できません" - "USBデバッグ" + "USB デバッグ" "USB接続時はデバッグモードにする" "USBデバッグの許可の取り消し" "バグレポートのショートカット" diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index a259bb10c2aa..3c2acd16ea1d 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -188,7 +188,7 @@ "더 빠르게" "매우 빠르게" "상당히 빠르게" - "매우 빠르게" + "굉장히 빠르게" "가장 빠르게" "프로필 선택" diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 84ca16705a66..565062c0124e 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -26,12 +26,12 @@ "Ажыратылды" "Өчүрүлгөн" "IP конфигурациясы бузулду" - "Тармактын сапаты начар болгондуктан туташкан жок" + "Тармактын сапаты начар болгондуктан, туташкан жок" "WiFi туташуусу бузулду" "Аутентификация маселеси бар" "Туташпай жатат" "\"%1$s\" тармагына туташпай койду" - "Сырсөздү текшерип, кайра аракет кылыңыз." + "Сырсөздү текшерип, кайталап көрүңүз." "Тейлөө аймагында эмес" "Автоматтык түрдө туташпайт" "Интернетке туташпай турат" @@ -115,7 +115,7 @@ "Жок" "Жупташканда байланыштарыңыз менен чалуу таржымалыңызды пайдалана аласыз." "%1$s менен жупташуу мүмкүн эмес." - "PIN же код туура эмес болгондуктан %1$s туташуу мүмкүн эмес." + "PIN же код туура эмес болгондуктан, %1$s туташуу мүмкүн эмес." "%1$s менен байланышуу мүмкүн эмес." "Жупташтырууну %1$s четке какты." "Компьютер" @@ -123,7 +123,7 @@ "Телефон" "Сүрөт тартуучу түзмөк" "Кулакчын" - "Дайындарды киргизүүчү сырткы түзмөк" + "Дайындарды киргизүүчү тышкы түзмөк" "Bluetooth" "Угуу аппаратынын сол кулагы жупташтырылууда…" "Угуу аппаратынын оң кулагы жупташтырылууда…" @@ -361,7 +361,7 @@ "Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз" "WebView кызматы" "WebView аткарылышын коюу" - "Тандалган нерсе жараксыз болуп калган. Кайра аракет кылыңыз." + "Тандалган нерсе жараксыз болуп калган. Кайталап көрүңүз." "Файлдарды шифрлөөгө өтүү" "Айландыруу…" "Файл мурунтан эле шифрленген" diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 0f9a4398cad6..345aa644db3a 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -237,7 +237,7 @@ "Acionar o codec de áudio Bluetooth\nSeleção: modo de canal" "Codec LDAC de áudio Bluetooth: qualidade de reprodução" "Acionar a seleção do codec LDAC de áudio\nBluetooth: Qualidade de reprodução" - "Transmissão em fluxo contínuo: %1$s" + "Stream: %1$s" "DNS privado" "Selecionar modo DNS privado" "Desativado" diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 1c277ccacb4b..70fc3fa48e34 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -110,7 +110,7 @@ "Используется для передачи файлов" "Использовать для ввода" "Использовать для слухового аппарата" - "Добавить" + "Подключить" "ДОБАВИТЬ" "Отмена" "Установление соединения обеспечивает доступ к вашим контактам и журналу звонков при подключении." diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index b09e6dceecbc..f04fab20c53a 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -147,7 +147,7 @@ "டெதெரிங்" "டெதெரிங் & போர்டபிள் ஹாட்ஸ்பாட்" "எல்லா பணிப் பயன்பாடுகளும்" - "வேறொருவர்" + "கெஸ்ட்" "அறியப்படாத" "பயனர்: %1$s" "சில இயல்புநிலைகள் அமைக்கப்பட்டன" @@ -246,7 +246,7 @@ "DNS வழங்குநரின் ஹோஸ்ட் பெயரை உள்ளிடவும்" "இணைக்க முடியவில்லை" "வயர்லெஸ் காட்சி சான்றுக்கான விருப்பங்களைக் காட்டு" - "வைஃபை நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக" + "வைஃபை நுழைவு அளவை அதிகரித்து, வைஃபை தேர்வுக் கருவியில் ஒவ்வொன்றிற்கும் SSID RSSI ஐ காட்டுக" "பேட்டரி தீர்ந்துபோவதைக் குறைத்து நெட்வொர்க்கின் செயல்திறனை மேம்படுத்தும்" "கட்டண நெட்வொர்க்" "கட்டணமில்லா நெட்வொர்க்" @@ -376,7 +376,7 @@ "நிறம் அடையாளங்காண முடியாமை (சிவப்பு-பச்சை)" "நிறம் அடையாளங்காண முடியாமை (நீலம்-மஞ்சள்)" "வண்ணத்திருத்தம்" - "இது சோதனை முறையிலான அம்சம், இது செயல்திறனைப் பாதிக்கலாம்." + "இது பரிசோதனை முறையிலான அம்சம், இது செயல்திறனைப் பாதிக்கலாம்." "%1$s மூலம் மேலெழுதப்பட்டது" "%1$s - %2$s" "கிட்டத்தட்ட %1$s மீதமுள்ளது" @@ -428,7 +428,7 @@ "பெரியது" "கொஞ்சம் பெரியது" "மிகப் பெரியது" - "தனிப்பயன் (%d)" + "பிரத்தியேக (%d)" "மெனு" "டெமோ பயன்முறையில் ஆரம்பநிலை மீட்டமைவைச் செயல்படுத்த, கடவுச்சொல்லை உள்ளிடவும்" "அடுத்து" diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index fcd2d3614265..981602aeee81 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -199,7 +199,7 @@ "Đặt tùy chọn cho phát triển ứng dụng" "Tùy chọn dành cho nhà phát triển không khả dụng cho người dùng này" "Cài đặt VPN không khả dụng cho người dùng này" - "Cài đặt chia sẻ kết nối không khả dụng cho người dùng này" + "Cài đặt cách chia sẻ kết nối không khả dụng cho người dùng này" "Cài đặt tên điểm truy cập không khả dụng cho người dùng này" "Gỡ lỗi qua USB" "Bật chế độ gỡ lỗi khi kết nối USB" -- GitLab From c5029c9007f7f3501c9d11924e1c48f49fd8161d Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Tue, 13 Aug 2019 13:24:07 -0700 Subject: [PATCH 143/143] Move filterMobileSubscriptionInSameGroup into KeyguardUpdateMonitor. This avoids race condition that, KeyguardUpdateMonitor refreshes active sub list however CarrierTextController filtered it based on stale active data subId. By move filterMobileSubscriptionInSameGroup into KeyguardUpdateMonitor, it becomes the single source of truth about which carrier name should be shown. Bug: 138456731 Bug: 151600673 Test: manual and unittest Change-Id: Ida3a90c5408b056cad7a79fbba84fe880ce1e5be Merged-In: Ida3a90c5408b056cad7a79fbba84fe880ce1e5be (cherry picked from commit 5c63b51d9e9e6c2b90575b71e62e66f39c9ff719) --- .../keyguard/CarrierTextController.java | 72 +------------------ .../keyguard/KeyguardUpdateMonitor.java | 49 ++++++++++++- .../systemui/statusbar/OperatorNameView.java | 2 +- .../policy/EmergencyCryptkeeperText.java | 2 +- .../keyguard/CarrierTextControllerTest.java | 54 ++++---------- .../keyguard/KeyguardUpdateMonitorTest.java | 40 ++++++++++- 6 files changed, 101 insertions(+), 118 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java index 2b8e3ee0dfc0..a246484c18eb 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java @@ -19,16 +19,12 @@ package com.android.keyguard; import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; import static android.telephony.PhoneStateListener.LISTEN_NONE; -import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; - import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; -import android.os.SystemProperties; -import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; @@ -37,20 +33,18 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; -import androidx.annotation.VisibleForTesting; - import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; import com.android.settingslib.WirelessUtils; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.keyguard.WakefulnessLifecycle; -import java.util.ArrayList; import java.util.List; import java.util.Objects; +import androidx.annotation.VisibleForTesting; + /** * Controller that generates text including the carrier names and/or the status of all the SIM * interfaces in the device. Through a callback, the updates can be retrieved either as a list or @@ -73,8 +67,6 @@ public class CarrierTextController { private Context mContext; private CharSequence mSeparator; private WakefulnessLifecycle mWakefulnessLifecycle; - @VisibleForTesting - protected boolean mDisplayOpportunisticSubscriptionCarrierText; private final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { @Override @@ -175,9 +167,6 @@ public class CarrierTextController { mSimSlotsNumber = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE)).getPhoneCount(); mSimErrorState = new boolean[mSimSlotsNumber]; - updateDisplayOpportunisticSubscriptionCarrierText(SystemProperties.getBoolean( - TelephonyProperties.DISPLAY_OPPORTUNISTIC_SUBSCRIPTION_CARRIER_TEXT_PROPERTY_NAME, - false)); } /** @@ -254,63 +243,8 @@ public class CarrierTextController { } } - /** - * @param subscriptions - */ - private void filterMobileSubscriptionInSameGroup(List subscriptions) { - if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) { - SubscriptionInfo info1 = subscriptions.get(0); - SubscriptionInfo info2 = subscriptions.get(1); - if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { - // If both subscriptions are primary, show both. - if (!info1.isOpportunistic() && !info2.isOpportunistic()) return; - - // If carrier required, always show signal bar of primary subscription. - // Otherwise, show whichever subscription is currently active for Internet. - boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig() - .getBoolean(CarrierConfigManager - .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN); - if (alwaysShowPrimary) { - subscriptions.remove(info1.isOpportunistic() ? info1 : info2); - } else { - subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription - ? info2 : info1); - } - - } - } - } - - /** - * updates if opportunistic sub carrier text should be displayed or not - * - */ - @VisibleForTesting - public void updateDisplayOpportunisticSubscriptionCarrierText(boolean isEnable) { - mDisplayOpportunisticSubscriptionCarrierText = isEnable; - } - protected List getSubscriptionInfo() { - List subs; - if (mDisplayOpportunisticSubscriptionCarrierText) { - SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext - .getSystemService( - Context.TELEPHONY_SUBSCRIPTION_SERVICE)); - subs = subscriptionManager.getActiveSubscriptionInfoList(false); - if (subs == null) { - subs = new ArrayList<>(); - } else { - filterMobileSubscriptionInSameGroup(subs); - } - } else { - subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); - if (subs == null) { - subs = new ArrayList<>(); - } else { - filterMobileSubscriptionInSameGroup(subs); - } - } - return subs; + return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); } protected void updateCarrierText() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 8d858dcb25df..4d82923e86a4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -30,6 +30,7 @@ import static android.os.BatteryManager.EXTRA_PLUGGED; import static android.os.BatteryManager.EXTRA_STATUS; import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; +import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; @@ -77,6 +78,7 @@ import android.os.UserManager; import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; +import android.telephony.CarrierConfigManager; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; @@ -257,6 +259,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private boolean mLogoutEnabled; // If the user long pressed the lock icon, disabling face auth for the current session. private boolean mLockIconPressed; + private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID; /** * Short delay before restarting biometric authentication after a successful try @@ -392,9 +395,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } }; - private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @VisibleForTesting + public PhoneStateListener mPhoneStateListener = new PhoneStateListener() { @Override public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveMobileDataSubscription = subId; mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED); } }; @@ -496,7 +501,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } - /** @return List of SubscriptionInfo records, maybe empty but never null */ + /** + * @return List of SubscriptionInfo records, maybe empty but never null. + */ public List getSubscriptionInfo(boolean forceReload) { List sil = mSubscriptionInfo; if (sil == null || forceReload) { @@ -508,7 +515,42 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } else { mSubscriptionInfo = sil; } - return mSubscriptionInfo; + return new ArrayList<>(mSubscriptionInfo); + } + + /** + * This method returns filtered list of SubscriptionInfo from {@link #getSubscriptionInfo}. + * above. Maybe empty but never null. + * + * In DSDS mode if both subscriptions are grouped and one is opportunistic, we filter out one + * of them based on carrier config. e.g. In this case we should only show one carrier name + * on the status bar and quick settings. + */ + public List getFilteredSubscriptionInfo(boolean forceReload) { + List subscriptions = getSubscriptionInfo(false); + if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) { + SubscriptionInfo info1 = subscriptions.get(0); + SubscriptionInfo info2 = subscriptions.get(1); + if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { + // If both subscriptions are primary, show both. + if (!info1.isOpportunistic() && !info2.isOpportunistic()) return subscriptions; + + // If carrier required, always show signal bar of primary subscription. + // Otherwise, show whichever subscription is currently active for Internet. + boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig() + .getBoolean(CarrierConfigManager + .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN); + if (alwaysShowPrimary) { + subscriptions.remove(info1.isOpportunistic() ? info1 : info2); + } else { + subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription + ? info2 : info1); + } + + } + } + + return subscriptions; } @Override @@ -2637,6 +2679,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { pw.println(" " + mSubscriptionInfo.get(i)); } } + pw.println(" Current active data subId=" + mActiveMobileDataSubscription); pw.println(" Service states:"); for (int subId : mServiceStates.keySet()) { pw.println(" " + subId + "=" + mServiceStates.get(subId)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java index d1b3c3cb12d8..2a5ccdb0c0a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java @@ -134,7 +134,7 @@ public class OperatorNameView extends TextView implements DemoMode, DarkReceiver private void updateText() { CharSequence displayText = null; - List subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); + List subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); final int N = subs.size(); for (int i = 0; i < N; i++) { int subId = subs.get(i).getSubscriptionId(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java index 0d6178b1176b..f2c0434a1a95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java @@ -97,7 +97,7 @@ public class EmergencyCryptkeeperText extends TextView { boolean allSimsMissing = true; CharSequence displayText = null; - List subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false); + List subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); final int N = subs.size(); for (int i = 0; i < N; i++) { int subId = subs.get(i).getSubscriptionId(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index 1421b06be621..1ae37e8200e4 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -71,15 +71,10 @@ public class CarrierTextControllerTest extends SysuiTestCase { private static final CharSequence AIRPLANE_MODE_TEXT = "Airplane mode"; private static final String TEST_CARRIER = "TEST_CARRIER"; private static final String TEST_CARRIER_2 = "TEST_CARRIER_2"; - private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24"; private static final int TEST_CARRIER_ID = 1; private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", - DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID, - TEST_CARRIER_ID, 0); - private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(0, "", 0, - TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", - DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID, + DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, null, TEST_CARRIER_ID, 0); private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0, TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", @@ -126,7 +121,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor); // This should not start listening on any of the real dependencies mCarrierTextController.setListening(mCarrierTextCallback); - mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText(false); } @Test @@ -135,7 +129,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { reset(mCarrierTextCallback); List list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); @@ -155,7 +149,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { reset(mCarrierTextCallback); List list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY); when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn( IccCardConstants.State.CARD_IO_ERROR); @@ -179,7 +173,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { @Test public void testWrongSlots() { reset(mCarrierTextCallback); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( IccCardConstants.State.CARD_IO_ERROR); @@ -193,7 +187,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { @Test public void testMoreSlotsThanSubs() { reset(mCarrierTextCallback); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the @@ -243,7 +237,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { List list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); @@ -267,7 +261,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { List list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION_ROAMING); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); @@ -288,7 +282,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { @Test public void testCreateInfo_noSubscriptions() { reset(mCarrierTextCallback); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn( + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn( new ArrayList<>()); ArgumentCaptor captor = @@ -312,7 +306,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { list.add(TEST_SUBSCRIPTION); list.add(TEST_SUBSCRIPTION); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); @@ -337,7 +331,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())) .thenReturn(IccCardConstants.State.READY) .thenReturn(IccCardConstants.State.NOT_READY); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); @@ -362,7 +356,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { when(mKeyguardUpdateMonitor.getSimState(anyInt())) .thenReturn(IccCardConstants.State.NOT_READY) .thenReturn(IccCardConstants.State.READY); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); @@ -389,7 +383,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { .thenReturn(IccCardConstants.State.READY) .thenReturn(IccCardConstants.State.NOT_READY) .thenReturn(IccCardConstants.State.READY); - when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list); + when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list); mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); ArgumentCaptor captor = @@ -404,30 +398,6 @@ public class CarrierTextControllerTest extends SysuiTestCase { captor.getValue().carrierText); } - @Test - public void testCarrierText_GroupedSubWithOpportunisticCarrierText() { - reset(mCarrierTextCallback); - List list = new ArrayList<>(); - list.add(TEST_SUBSCRIPTION); - list.add(TEST_SUBSCRIPTION_2); - when(mKeyguardUpdateMonitor.getSimState(anyInt())) - .thenReturn(IccCardConstants.State.READY); - - mKeyguardUpdateMonitor.mServiceStates = new HashMap<>(); - mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText(true); - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); - - ArgumentCaptor captor = - ArgumentCaptor.forClass( - CarrierTextController.CarrierTextCallbackInfo.class); - - mCarrierTextController.updateCarrierText(); - mTestableLooper.processAllMessages(); - verify(mCarrierTextCallback).updateCarrierInfo(captor.capture()); - - assertEquals(TEST_CARRIER_2, captor.getValue().carrierText); - } - public static class TestCarrierTextController extends CarrierTextController { private KeyguardUpdateMonitor mKUM; diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index db6177a63f96..a3cb6c05ca7a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -16,15 +16,18 @@ package com.android.keyguard; +import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; +import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -42,6 +45,7 @@ import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.os.UserManager; import android.telephony.ServiceState; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -62,6 +66,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @SmallTest @@ -73,7 +79,18 @@ import java.util.concurrent.atomic.AtomicBoolean; // new tests. @RunWithLooper(setAsMainLooper = true) public class KeyguardUpdateMonitorTest extends SysuiTestCase { - + private static final String TEST_CARRIER = "TEST_CARRIER"; + private static final String TEST_CARRIER_2 = "TEST_CARRIER_2"; + private static final int TEST_CARRIER_ID = 1; + private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24"; + private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "", 0, + TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", + DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID, + TEST_CARRIER_ID, 0); + private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(2, "", 0, + TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", + DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID, + TEST_CARRIER_ID, 0); @Mock private KeyguardUpdateMonitor.StrongAuthTracker mStrongAuthTracker; @Mock @@ -92,6 +109,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { private DevicePolicyManager mDevicePolicyManager; @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock + private SubscriptionManager mSubscriptionManager; private TestableLooper mTestableLooper; private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -119,6 +138,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { context.addMockSystemService(FaceManager.class, mFaceManager); context.addMockSystemService(UserManager.class, mUserManager); context.addMockSystemService(DevicePolicyManager.class, mDevicePolicyManager); + context.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); mTestableLooper = TestableLooper.get(this); mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(context); @@ -441,6 +461,22 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue(); } + @Test + public void testGetSubscriptionInfo_whenInGroupedSubWithOpportunistic() { + List list = new ArrayList<>(); + list.add(TEST_SUBSCRIPTION); + list.add(TEST_SUBSCRIPTION_2); + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged( + TEST_SUBSCRIPTION_2.getSubscriptionId()); + mTestableLooper.processAllMessages(); + + List listToVerify = mKeyguardUpdateMonitor + .getFilteredSubscriptionInfo(false); + assertThat(listToVerify.size()).isEqualTo(1); + assertThat(listToVerify.get(0)).isEqualTo(TEST_SUBSCRIPTION_2); + } + private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) { int subscription = simInited ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE; -- GitLab