diff options
28 files changed, 337 insertions, 143 deletions
diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java index 345895b794a3..834658da8ccc 100644 --- a/cmds/bu/src/com/android/commands/bu/Backup.java +++ b/cmds/bu/src/com/android/commands/bu/Backup.java @@ -136,7 +136,9 @@ public final class Backup { if (fd != null) { try { fd.close(); - } catch (IOException e) {} + } catch (IOException e) { + Log.e(TAG, "IO error closing output for backup: " + e.getMessage()); + } } } } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index ba5ea21847bc..0d5cd0214f37 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -1380,8 +1380,13 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate @Override public void onAnimationEnd(Animator anim) { container.endViewTransition(view); - if (fragment.getAnimatingAway() != null) { - fragment.setAnimatingAway(null); + Animator animator = f.getAnimatingAway(); + f.setAnimatingAway(null); + // If the animation finished immediately, the fragment's + // view will still be there. If so, we can just pretend + // there was no animation and skip the moveToState() + if (container.indexOfChild(view) == -1 + && animator != null) { moveToState(fragment, fragment.getStateAfterAnimating(), 0, 0, false); } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index b38be6626e50..0f9a3d71313a 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -625,17 +625,29 @@ public final class LoadedApk { final List<String> zipPaths = new ArrayList<>(10); final List<String> libPaths = new ArrayList<>(10); - final boolean isBundledApp = mApplicationInfo.isSystemApp() + boolean isBundledApp = mApplicationInfo.isSystemApp() && !mApplicationInfo.isUpdatedSystemApp(); + // Vendor apks are treated as bundled only when /vendor/lib is in the default search + // paths. If not, they are treated as unbundled; access to system libs is limited. + // Having /vendor/lib in the default search paths means that all system processes + // are allowed to use any vendor library, which in turn means that system is dependent + // on vendor partition. In the contrary, not having /vendor/lib in the default search + // paths mean that the two partitions are separated and thus we can treat vendor apks + // as unbundled. + final String defaultSearchPaths = System.getProperty("java.library.path"); + final boolean treatVendorApkAsUnbundled = !defaultSearchPaths.contains("/vendor/lib"); + if (mApplicationInfo.getCodePath().startsWith("/vendor/") && treatVendorApkAsUnbundled) { + isBundledApp = false; + } + makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths); String libraryPermittedPath = mDataDir; if (isBundledApp) { // This is necessary to grant bundled apps access to // libraries located in subdirectories of /system/lib - libraryPermittedPath += File.pathSeparator + - System.getProperty("java.library.path"); + libraryPermittedPath += File.pathSeparator + defaultSearchPaths; } final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths); diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 678159b71296..b596dd6b2c93 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -42,7 +42,7 @@ public final class BluetoothGatt implements BluetoothProfile { private static final boolean VDBG = false; private IBluetoothGatt mService; - private BluetoothGattCallback mCallback; + private volatile BluetoothGattCallback mCallback; private Handler mHandler; private int mClientIf; private BluetoothDevice mDevice; @@ -159,8 +159,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE, + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE, BluetoothProfile.STATE_DISCONNECTED); } } @@ -194,8 +195,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status); } } }); @@ -216,8 +218,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status); } } }); @@ -241,8 +244,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onConnectionStateChange(BluetoothGatt.this, status, + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onConnectionStateChange(BluetoothGatt.this, status, profileState); } } @@ -303,8 +307,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onServicesDiscovered(BluetoothGatt.this, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onServicesDiscovered(BluetoothGatt.this, status); } } }); @@ -350,13 +355,13 @@ public final class BluetoothGatt implements BluetoothProfile { return; } - if (status == 0) characteristic.setValue(value); - runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + if (status == 0) characteristic.setValue(value); + callback.onCharacteristicRead(BluetoothGatt.this, characteristic, status); } } @@ -404,8 +409,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status); } } @@ -428,13 +434,13 @@ public final class BluetoothGatt implements BluetoothProfile { BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice, handle); if (characteristic == null) return; - characteristic.setValue(value); - runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + characteristic.setValue(value); + callback.onCharacteristicChanged(BluetoothGatt.this, characteristic); } } }); @@ -459,7 +465,6 @@ public final class BluetoothGatt implements BluetoothProfile { BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle); if (descriptor == null) return; - if (status == 0) descriptor.setValue(value); if ((status == GATT_INSUFFICIENT_AUTHENTICATION || status == GATT_INSUFFICIENT_ENCRYPTION) @@ -480,8 +485,10 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + if (status == 0) descriptor.setValue(value); + callback.onDescriptorRead(BluetoothGatt.this, descriptor, status); } } }); @@ -526,8 +533,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onDescriptorWrite(BluetoothGatt.this, descriptor, status); } } }); @@ -552,8 +560,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onReliableWriteCompleted(BluetoothGatt.this, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onReliableWriteCompleted(BluetoothGatt.this, status); } } }); @@ -573,8 +582,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onReadRemoteRssi(BluetoothGatt.this, rssi, status); } } }); @@ -595,8 +605,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onMtuChanged(BluetoothGatt.this, mtu, status); + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onMtuChanged(BluetoothGatt.this, mtu, status); } } }); @@ -619,8 +630,9 @@ public final class BluetoothGatt implements BluetoothProfile { runOrQueueCallback(new Runnable() { @Override public void run() { - if (mCallback != null) { - mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency, + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onConnectionUpdated(BluetoothGatt.this, interval, latency, timeout, status); } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 586631e4b6e7..507edc4f1205 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5159,17 +5159,39 @@ public final class Settings { public static final String ALLOW_MOCK_LOCATION = "mock_location"; /** - * A 64-bit number (as a hex string) that is randomly + * On Android 8.0 (API level 26) and higher versions of the platform, + * a 64-bit number (expressed as a hexadecimal string), unique to + * each combination of app-signing key, user, and device. + * Values of {@code ANDROID_ID} are scoped by signing key and user. + * The value may change if a factory reset is performed on the + * device or if an APK signing key changes. + * + * For more information about how the platform handles {@code ANDROID_ID} + * in Android 8.0 (API level 26) and higher, see <a + * href="{@docRoot}preview/behavior-changes.html#privacy-all"> + * Android 8.0 Behavior Changes</a>. + * + * <p class="note"><strong>Note:</strong> For apps that were installed + * prior to updating the device to a version of Android 8.0 + * (API level 26) or higher, the value of {@code ANDROID_ID} changes + * if the app is uninstalled and then reinstalled after the OTA. + * To preserve values across uninstalls after an OTA to Android 8.0 + * or higher, developers can use + * <a href="{@docRoot}guide/topics/data/keyvaluebackup.html"> + * Key/Value Backup</a>.</p> + * + * <p>In versions of the platform lower than Android 8.0 (API level 26), + * a 64-bit number (expressed as a hexadecimal string) that is randomly * generated when the user first sets up the device and should remain - * constant for the lifetime of the user's device. The value may - * change if a factory reset is performed on the device. - * <p class="note"><strong>Note:</strong> When a device has <a - * href="{@docRoot}about/versions/android-4.2.html#MultipleUsers">multiple users</a> - * (available on certain devices running Android 4.2 or higher), each user appears as a - * completely separate device, so the {@code ANDROID_ID} value is unique to each - * user.</p> - * - * <p class="note"><strong>Note:</strong> If the caller is an Instant App the id is scoped + * constant for the lifetime of the user's device. + * + * On devices that have + * <a href="{@docRoot}about/versions/android-4.2.html#MultipleUsers"> + * multiple users</a>, each user appears as a + * completely separate device, so the {@code ANDROID_ID} value is + * unique to each user.</p> + * + * <p class="note"><strong>Note:</strong> If the caller is an Instant App the ID is scoped * to the Instant App, it is generated when the Instant App is first installed and reset if * the user clears the Instant App. */ @@ -8532,6 +8554,16 @@ public final class Settings { public static final String NETWORK_SCORING_UI_ENABLED = "network_scoring_ui_enabled"; /** + * Value to specify how long in milliseconds to retain seen score cache curves to be used + * when generating SSID only bases score curves. + * + * Type: long + * @hide + */ + public static final String SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS = + "speed_label_cache_eviction_age_millis"; + + /** * Value to specify if network recommendations from * {@link com.android.server.NetworkScoreService} are enabled. * diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java index 77aea2345304..d9fb4cc7a3f5 100644 --- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java +++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java @@ -211,8 +211,9 @@ public final class SmartSelectionEventTracker { return (clamp(mSmartIndices[0] - mOrigStart) << 16) | (clamp(mSmartIndices[1] - mOrigStart) & 0xffff); } - // If no smart selection, return start selection indices (i.e. [0, 1]) - return /* (0 << 16) | */ (1 & 0xffff); + // If the smart selection model was not run, return invalid selection indices [0,0]. This + // allows us to tell from the terminal event alone whether the model was run. + return 0; } private int getEventDelta(SelectionEvent event) { diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java index b2b769ee2fec..387857f0c997 100644 --- a/core/java/com/android/internal/os/ClassLoaderFactory.java +++ b/core/java/com/android/internal/os/ClassLoaderFactory.java @@ -88,12 +88,20 @@ public class ClassLoaderFactory { final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent, classloaderName); + boolean isForVendor = false; + for (String path : dexPath.split(":")) { + if (path.startsWith("/vendor/")) { + isForVendor = true; + break; + } + } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "createClassloaderNamespace"); String errorMessage = createClassloaderNamespace(classLoader, targetSdkVersion, librarySearchPath, libraryPermittedPath, - isNamespaceShared); + isNamespaceShared, + isForVendor); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (errorMessage != null) { @@ -108,5 +116,6 @@ public class ClassLoaderFactory { int targetSdkVersion, String librarySearchPath, String libraryPermittedPath, - boolean isNamespaceShared); + boolean isNamespaceShared, + boolean isForVendor); } diff --git a/core/jni/com_android_internal_os_ClassLoaderFactory.cpp b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp index 7052e5f3ce4b..9ce328948ca8 100644 --- a/core/jni/com_android_internal_os_ClassLoaderFactory.cpp +++ b/core/jni/com_android_internal_os_ClassLoaderFactory.cpp @@ -27,15 +27,17 @@ static jstring createClassloaderNamespace_native(JNIEnv* env, jint targetSdkVersion, jstring librarySearchPath, jstring libraryPermittedPath, - jboolean isShared) { + jboolean isShared, + jboolean isForVendor) { return android::CreateClassLoaderNamespace(env, targetSdkVersion, classLoader, isShared == JNI_TRUE, + isForVendor == JNI_TRUE, librarySearchPath, libraryPermittedPath); } static const JNINativeMethod g_methods[] = { { "createClassloaderNamespace", - "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;", + "(Ljava/lang/ClassLoader;ILjava/lang/String;Ljava/lang/String;ZZ)Ljava/lang/String;", reinterpret_cast<void*>(createClassloaderNamespace_native) }, }; diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml index 50ff50f19564..63675ab03916 100644 --- a/core/res/res/layout/autofill_save.xml +++ b/core/res/res/layout/autofill_save.xml @@ -44,8 +44,14 @@ android:layout_height="wrap_content" android:orientation="horizontal"> + <ImageView + android:id="@+id/autofill_save_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView android:id="@+id/autofill_save_title" + android:paddingLeft="8dp" android:layout_width="0dp" android:layout_height="wrap_content" android:text="@string/autofill_save_title" diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 9b1ebc877384..9be00f788d9c 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -604,4 +604,7 @@ <!-- Max height of the the autofill save custom subtitle as a fraction of the screen width/height --> <dimen name="autofill_save_custom_subtitle_max_height">20%</dimen> + <!-- Max (absolute) dimensions (both width and height) of autofill service icon on autofill save affordance --> + <dimen name="autofill_save_icon_max_size">100dp</dimen> + </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 8c10a8db891c..09d8c752a811 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2900,8 +2900,9 @@ <java-symbol type="id" name="autofill_dataset_list"/> <java-symbol type="id" name="autofill" /> <java-symbol type="id" name="autofill_save_custom_subtitle" /> - <java-symbol type="id" name="autofill_save_title" /> + <java-symbol type="id" name="autofill_save_icon" /> <java-symbol type="id" name="autofill_save_no" /> + <java-symbol type="id" name="autofill_save_title" /> <java-symbol type="id" name="autofill_save_yes" /> <java-symbol type="string" name="autofill_error_cannot_autofill" /> <java-symbol type="string" name="autofill_picker_no_suggestions" /> @@ -2925,6 +2926,7 @@ <java-symbol type="style" name="AutofillSaveAnimation" /> <java-symbol type="dimen" name="autofill_dataset_picker_max_size"/> <java-symbol type="dimen" name="autofill_save_custom_subtitle_max_height"/> + <java-symbol type="dimen" name="autofill_save_icon_max_size"/> <java-symbol type="dimen" name="notification_big_picture_max_height"/> <java-symbol type="dimen" name="notification_big_picture_max_width"/> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 3b71e426085a..43e762d34967 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -328,6 +328,7 @@ public class SettingsBackupTest { Settings.Global.SMS_SHORT_CODE_RULE, Settings.Global.SMS_SHORT_CODES_UPDATE_CONTENT_URL, Settings.Global.SMS_SHORT_CODES_UPDATE_METADATA_URL, + Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS, Settings.Global.STORAGE_BENCHMARK_INTERVAL, Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD, Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS, diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java index 832b2974f53c..91e57ee073b0 100644 --- a/media/java/android/media/MediaMuxer.java +++ b/media/java/android/media/MediaMuxer.java @@ -70,7 +70,7 @@ import java.util.Map; <p> Per-frame metadata is useful in carrying extra information that correlated with video or audio to facilitate offline processing, e.g. gyro signals from the sensor could help video stabilization when - doing offline processing. Metaadata track is only supported in MP4 container. When adding a new + doing offline processing. Metadata track is only supported in MP4 container. When adding a new metadata track, track's mime format must start with prefix "application/", e.g. "applicaton/gyro". Metadata's format/layout will be defined by the application. Writing metadata is nearly the same as writing video/audio data except that the data will not be from mediacodec. Application just needs diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 0129c668ae6c..3fd7c392d77c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -51,7 +51,6 @@ import android.support.annotation.NonNull; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; -import android.text.format.DateUtils; import android.text.style.TtsSpan; import android.util.Log; @@ -133,10 +132,6 @@ public class AccessPoint implements Comparable<AccessPoint> { */ private final Map<String, TimestampedScoredNetwork> mScoredNetworkCache = new HashMap<>(); - /** Maximum age in millis of cached scored networks in {@link #mScoredNetworkCache}. */ - @VisibleForTesting static final long MAX_CACHED_SCORE_AGE_MILLIS = - 24 * DateUtils.DAY_IN_MILLIS; - /** Maximum age of scan results to hold onto while actively scanning. **/ private static final long MAX_SCAN_RESULT_AGE_MILLIS = 15000; @@ -438,13 +433,18 @@ public class AccessPoint implements Comparable<AccessPoint> { * Updates the AccessPoint rankingScore, metering, and speed, returning true if the data has * changed. * - * @param scoreCache The score cache to use to retrieve scores. - * @param scoringUiEnabled Whether to show scoring and badging UI. + * @param scoreCache The score cache to use to retrieve scores + * @param scoringUiEnabled Whether to show scoring and badging UI + * @param maxScoreCacheAgeMillis the maximum age in milliseconds of scores to consider when + * generating speed labels */ - boolean update(WifiNetworkScoreCache scoreCache, boolean scoringUiEnabled) { + boolean update( + WifiNetworkScoreCache scoreCache, + boolean scoringUiEnabled, + long maxScoreCacheAgeMillis) { boolean scoreChanged = false; if (scoringUiEnabled) { - scoreChanged = updateScores(scoreCache); + scoreChanged = updateScores(scoreCache, maxScoreCacheAgeMillis); } return updateMetered(scoreCache) || scoreChanged; } @@ -452,15 +452,18 @@ public class AccessPoint implements Comparable<AccessPoint> { /** * Updates the AccessPoint rankingScore and speed, returning true if the data has changed. * - * <p>Any cached {@link TimestampedScoredNetwork} objects older than - * {@link #MAX_CACHED_SCORE_AGE_MILLIS} will be removed when this method is invoked. + * <p>Any cached {@link TimestampedScoredNetwork} objects older than the given max age in millis + * will be removed when this method is invoked. * * <p>Precondition: {@link #mRssi} is up to date before invoking this method. * - * @param scoreCache The score cache to use to retrieve scores. + * @param scoreCache The score cache to use to retrieve scores + * @param maxScoreCacheAgeMillis the maximum age in milliseconds of scores to consider when + * generating speed labels + * * @return true if the set speed has changed */ - private boolean updateScores(WifiNetworkScoreCache scoreCache) { + private boolean updateScores(WifiNetworkScoreCache scoreCache, long maxScoreCacheAgeMillis) { long nowMillis = SystemClock.elapsedRealtime(); for (ScanResult result : mScanResultCache.values()) { ScoredNetwork score = scoreCache.getScoredNetwork(result); @@ -478,7 +481,7 @@ public class AccessPoint implements Comparable<AccessPoint> { } // Remove old cached networks - long evictionCutoff = nowMillis - MAX_CACHED_SCORE_AGE_MILLIS; + long evictionCutoff = nowMillis - maxScoreCacheAgeMillis; Iterator<TimestampedScoredNetwork> iterator = mScoredNetworkCache.values().iterator(); iterator.forEachRemaining(timestampedScoredNetwork -> { if (timestampedScoredNetwork.getUpdatedTimestampMillis() < evictionCutoff) { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index a242570d6930..6895550e5108 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -20,7 +20,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; @@ -41,6 +40,7 @@ import android.os.Looper; import android.os.Message; import android.provider.Settings; import android.support.annotation.GuardedBy; +import android.text.format.DateUtils; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; @@ -65,7 +65,11 @@ import java.util.concurrent.atomic.AtomicBoolean; * Tracks saved or available wifi networks and their state. */ public class WifiTracker { - // TODO(b/36733768): Remove flag includeSaved and includePasspoints. + /** + * Default maximum age in millis of cached scored networks in + * {@link AccessPoint#mScoredNetworkCache} to be used for speed label generation. + */ + private static final long DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS = 20 * DateUtils.MINUTE_IN_MILLIS; private static final String TAG = "WifiTracker"; private static final boolean DBG() { @@ -76,6 +80,8 @@ public class WifiTracker { * and used so as to assist with in-the-field WiFi connectivity debugging */ public static boolean sVerboseLogging; + // TODO(b/36733768): Remove flag includeSaved and includePasspoints. + // TODO: Allow control of this? // Combo scans can take 5-6s to complete - set to 10s. private static final int WIFI_RESCAN_INTERVAL_MS = 10 * 1000; @@ -138,7 +144,7 @@ public class WifiTracker { private final NetworkScoreManager mNetworkScoreManager; private final WifiNetworkScoreCache mScoreCache; private boolean mNetworkScoringUiEnabled; - private final ContentObserver mObserver; + private long mMaxSpeedLabelScoreCacheAge; @GuardedBy("mLock") private final Set<NetworkKey> mRequestedScores = new ArraySet<>(); @@ -229,16 +235,6 @@ public class WifiTracker { updateNetworkScores(); } }); - - mObserver = new ContentObserver(mWorkHandler) { - @Override - public void onChange(boolean selfChange) { - mNetworkScoringUiEnabled = - Settings.Global.getInt( - mContext.getContentResolver(), - Settings.Global.NETWORK_SCORING_UI_ENABLED, 0) == 1; - } - }; } /** Synchronously update the list of access points with the latest information. */ @@ -314,11 +310,16 @@ public class WifiTracker { synchronized (mLock) { registerScoreCache(); - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.NETWORK_SCORING_UI_ENABLED), - false /* notifyForDescendants */, - mObserver); - mObserver.onChange(false /* selfChange */); // Set mScoringUiEnabled + mNetworkScoringUiEnabled = + Settings.Global.getInt( + mContext.getContentResolver(), + Settings.Global.NETWORK_SCORING_UI_ENABLED, 0) == 1; + + mMaxSpeedLabelScoreCacheAge = + Settings.Global.getLong( + mContext.getContentResolver(), + Settings.Global.SPEED_LABEL_CACHE_EVICTION_AGE_MILLIS, + DEFAULT_MAX_CACHED_SCORE_AGE_MILLIS); resumeScanning(); if (!mRegistered) { @@ -370,7 +371,6 @@ public class WifiTracker { } unregisterScoreCache(); pauseScanning(); - mContext.getContentResolver().unregisterContentObserver(mObserver); mWorkHandler.removePendingMessages(); mMainHandler.removePendingMessages(); @@ -609,7 +609,7 @@ public class WifiTracker { requestScoresForNetworkKeys(scoresToRequest); for (AccessPoint ap : accessPoints) { - ap.update(mScoreCache, mNetworkScoringUiEnabled); + ap.update(mScoreCache, mNetworkScoringUiEnabled, mMaxSpeedLabelScoreCacheAge); } // Pre-sort accessPoints to speed preference insertion @@ -710,7 +710,7 @@ public class WifiTracker { updated = true; if (previouslyConnected != ap.isActive()) reorder = true; } - if (ap.update(mScoreCache, mNetworkScoringUiEnabled)) { + if (ap.update(mScoreCache, mNetworkScoringUiEnabled, mMaxSpeedLabelScoreCacheAge)) { reorder = true; updated = true; } @@ -744,7 +744,8 @@ public class WifiTracker { synchronized (mLock) { boolean updated = false; for (int i = 0; i < mInternalAccessPoints.size(); i++) { - if (mInternalAccessPoints.get(i).update(mScoreCache, mNetworkScoringUiEnabled)) { + if (mInternalAccessPoints.get(i).update( + mScoreCache, mNetworkScoringUiEnabled, mMaxSpeedLabelScoreCacheAge)) { updated = true; } } diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index b678b3aa31af..b99584f17e88 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -45,6 +45,7 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.SpannableString; +import android.text.format.DateUtils; import android.text.style.TtsSpan; import com.android.settingslib.R; @@ -72,6 +73,8 @@ public class AccessPointTest { private static final RssiCurve FAST_BADGE_CURVE = new RssiCurve(-150, 10, new byte[]{Speed.FAST}); public static final String TEST_BSSID = "00:00:00:00:00:00"; + private static final long MAX_SCORE_CACHE_AGE_MILLIS = + 20 * DateUtils.MINUTE_IN_MILLIS;; private Context mContext; @Mock private RssiCurve mockBadgeCurve; @@ -335,7 +338,8 @@ public class AccessPointTest { null /* NetworkKey */, null /* rssiCurve */, true /* metered */)); - ap.update(mockWifiNetworkScoreCache, false /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, false /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.isMetered()).isTrue(); } @@ -364,7 +368,8 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.VERY_FAST); assertThat(ap.getSpeedLabel()) @@ -379,7 +384,9 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.FAST); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); + assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.FAST); assertThat(ap.getSpeedLabel()) @@ -394,7 +401,8 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.MODERATE); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.MODERATE); assertThat(ap.getSpeedLabel()) @@ -409,7 +417,8 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.SLOW); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(AccessPoint.Speed.SLOW); assertThat(ap.getSpeedLabel()) @@ -424,7 +433,8 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSummary()).isEqualTo(mContext.getString(R.string.speed_label_very_fast)); } @@ -442,7 +452,8 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); String summary = ap.verboseScanResultSummary(scanResults.get(0), null); assertThat(summary.contains(mContext.getString(R.string.speed_label_very_fast))).isTrue(); @@ -457,7 +468,8 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) AccessPoint.Speed.VERY_FAST); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); String expectedString = mContext.getString(R.string.speed_label_very_fast) + " / " + mContext.getString(R.string.wifi_remembered); @@ -864,7 +876,8 @@ public class AccessPointTest { int expectedSpeed = (speed1 + speed2) / 2; - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(expectedSpeed); } @@ -884,7 +897,8 @@ public class AccessPointTest { when(mockWifiNetworkScoreCache.getScoredNetwork(SCAN_RESULTS.get(1))) .thenReturn(buildScoredNetworkWithGivenBadgeCurve(badgeCurve2)); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update( + mockWifiNetworkScoreCache, true /* scoringUiEnabled */, MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(speed1); } @@ -925,7 +939,8 @@ public class AccessPointTest { when(mockWifiNetworkScoreCache.getScoredNetwork(scanResultConnected)) .thenReturn(null); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(fallbackSpeed); } @@ -952,7 +967,8 @@ public class AccessPointTest { AccessPoint ap = createApWithFastTimestampedScoredNetworkCache(SystemClock.elapsedRealtime()); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(Speed.FAST); } @@ -960,11 +976,12 @@ public class AccessPointTest { @Test public void testNetworkScoresAreUsedForSpeedLabelGenerationWhenWithinAgeRange() { long withinRangeTimeMillis = - SystemClock.elapsedRealtime() - (AccessPoint.MAX_CACHED_SCORE_AGE_MILLIS - 10000); + SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS - 10000); AccessPoint ap = createApWithFastTimestampedScoredNetworkCache(withinRangeTimeMillis); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(Speed.FAST); } @@ -972,11 +989,12 @@ public class AccessPointTest { @Test public void testOldNetworkScoresAreNotUsedForSpeedLabelGeneration() { long tooOldTimeMillis = - SystemClock.elapsedRealtime() - (AccessPoint.MAX_CACHED_SCORE_AGE_MILLIS + 1); + SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1); AccessPoint ap = createApWithFastTimestampedScoredNetworkCache(tooOldTimeMillis); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); assertThat(ap.getSpeed()).isEqualTo(Speed.NONE); } @@ -984,7 +1002,7 @@ public class AccessPointTest { @Test public void testUpdateScoresRefreshesScoredNetworkCacheTimestamps () { long tooOldTimeMillis = - SystemClock.elapsedRealtime() - (AccessPoint.MAX_CACHED_SCORE_AGE_MILLIS + 1); + SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1); ScoredNetwork scoredNetwork = buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE); TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork( @@ -1002,7 +1020,8 @@ public class AccessPointTest { when(mockWifiNetworkScoreCache.getScoredNetwork(any(ScanResult.class))) .thenReturn(scoredNetwork); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); // Fast should still be returned since cache was updated with recent time assertThat(ap.getSpeed()).isEqualTo(Speed.FAST); @@ -1011,7 +1030,7 @@ public class AccessPointTest { @Test public void testUpdateScoresRefreshesScoredNetworkCacheWithNewSpeed () { long tooOldTimeMillis = - SystemClock.elapsedRealtime() - (AccessPoint.MAX_CACHED_SCORE_AGE_MILLIS + 1); + SystemClock.elapsedRealtime() - (MAX_SCORE_CACHE_AGE_MILLIS + 1); ScoredNetwork scoredNetwork = buildScoredNetworkWithGivenBadgeCurve(FAST_BADGE_CURVE); TimestampedScoredNetwork recentScore = new TimestampedScoredNetwork( @@ -1031,7 +1050,8 @@ public class AccessPointTest { .thenReturn(buildScoredNetworkWithMockBadgeCurve()); when(mockBadgeCurve.lookupScore(anyInt())).thenReturn((byte) newSpeed); - ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */); + ap.update(mockWifiNetworkScoreCache, true /* scoringUiEnabled */, + MAX_SCORE_CACHE_AGE_MILLIS); // Fast should still be returned since cache was updated with recent time assertThat(ap.getSpeed()).isEqualTo(newSpeed); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 165ed78996b2..99debee2dad3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -70,6 +70,7 @@ public class KeyguardBouncer { } }; private final Runnable mRemoveViewRunnable = this::removeView; + private int mStatusBarHeight; public KeyguardBouncer(Context context, ViewMediatorCallback callback, LockPatternUtils lockPatternUtils, ViewGroup container, @@ -129,7 +130,9 @@ public class KeyguardBouncer { mRoot.setVisibility(View.VISIBLE); mKeyguardView.onResume(); showPromptReason(mBouncerPromptReason); - if (mKeyguardView.getHeight() != 0) { + // We might still be collapsed and the view didn't have time to layout yet or still + // be small, let's wait on the predraw to do the animation in that case. + if (mKeyguardView.getHeight() != 0 && mKeyguardView.getHeight() != mStatusBarHeight) { mKeyguardView.startAppearAnimation(); } else { mKeyguardView.getViewTreeObserver().addOnPreDrawListener( @@ -252,6 +255,8 @@ public class KeyguardBouncer { mKeyguardView.setLockPatternUtils(mLockPatternUtils); mKeyguardView.setViewMediatorCallback(mCallback); mContainer.addView(mRoot, mContainer.getChildCount()); + mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset( + com.android.systemui.R.dimen.status_bar_height); mRoot.setVisibility(View.INVISIBLE); final WindowInsets rootInsets = mRoot.getRootWindowInsets(); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 512e1288d861..2b7a671fc99d 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -34,6 +34,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Binder; import android.os.Bundle; @@ -481,10 +482,16 @@ final class AutofillManagerServiceImpl { sendStateToClients(true); } + @NonNull CharSequence getServiceLabel() { return mInfo.getServiceInfo().loadLabel(mContext.getPackageManager()); } + @NonNull + Drawable getServiceIcon() { + return mInfo.getServiceInfo().loadIcon(mContext.getPackageManager()); + } + /** * Initializes the last fill selection after an autofill service returned a new * {@link FillResponse}. diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index e0e379f46309..dd0c874530dd 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -970,8 +970,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mService.logSaveShown(id); final IAutoFillManagerClient client = getClient(); mPendingSaveUi = new PendingUi(mActivityToken, id, client); - getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, - valueFinder, mPackageName, this, mPendingSaveUi); + getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(), + saveInfo, valueFinder, mPackageName, this, mPendingSaveUi); if (client != null) { try { client.setSaveUiState(id, true); @@ -1774,7 +1774,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState /** * Checks whether this session is hiding the Save UI to handle a custom description link for - * a specific {@code token} created by {@link PendingUi#PendingUi(IBinder)}. + * a specific {@code token} created by + * {@link PendingUi#PendingUi(IBinder, int, IAutoFillManagerClient)}. */ boolean isSaveUiPendingForToken(@NonNull IBinder token) { return isSaveUiPending() && token.equals(mPendingSaveUi.getToken()); diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index a6f6713476cf..cac2bff579ed 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.IntentSender; +import android.graphics.drawable.Drawable; import android.metrics.LogMaker; import android.os.Bundle; import android.os.Handler; @@ -244,8 +245,8 @@ public final class AutoFillUI { /** * Shows the UI asking the user to save for autofill. */ - public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info, - @NonNull ValueFinder valueFinder, @NonNull String packageName, + public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, + @NonNull SaveInfo info,@NonNull ValueFinder valueFinder, @NonNull String packageName, @NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi) { if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info); int numIds = 0; @@ -261,8 +262,8 @@ public final class AutoFillUI { return; } hideAllUiThread(callback); - mSaveUi = new SaveUi(mContext, pendingSaveUi, providerLabel, info, valueFinder, - mOverlayControl, new SaveUi.OnSaveListener() { + mSaveUi = new SaveUi(mContext, pendingSaveUi, serviceLabel, serviceIcon, info, + valueFinder, mOverlayControl, new SaveUi.OnSaveListener() { @Override public void onSave() { log.setType(MetricsProto.MetricsEvent.TYPE_ACTION); diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 160c84cbeffd..d0b2e9240b58 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -22,10 +22,14 @@ import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; import android.app.Dialog; import android.app.PendingIntent; -import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -43,7 +47,7 @@ import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.autofill.AutofillManager; -import android.view.autofill.IAutoFillManagerClient; +import android.widget.ImageView; import android.widget.RemoteViews; import android.widget.ScrollView; import android.widget.TextView; @@ -121,9 +125,9 @@ final class SaveUi { private boolean mDestroyed; SaveUi(@NonNull Context context, @NonNull PendingUi pendingUi, - @NonNull CharSequence providerLabel, @NonNull SaveInfo info, - @NonNull ValueFinder valueFinder, @NonNull OverlayControl overlayControl, - @NonNull OnSaveListener listener) { + @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon, + @NonNull SaveInfo info, @NonNull ValueFinder valueFinder, + @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener) { mPendingUi= pendingUi; mListener = new OneTimeListener(listener); mOverlayControl = overlayControl; @@ -155,24 +159,25 @@ final class SaveUi { switch (types.size()) { case 1: mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type, - types.valueAt(0), providerLabel), 0); + types.valueAt(0), serviceLabel), 0); break; case 2: mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_2types, - types.valueAt(0), types.valueAt(1), providerLabel), 0); + types.valueAt(0), types.valueAt(1), serviceLabel), 0); break; case 3: mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_3types, - types.valueAt(0), types.valueAt(1), types.valueAt(2), providerLabel), 0); + types.valueAt(0), types.valueAt(1), types.valueAt(2), serviceLabel), 0); break; default: // Use generic if more than 3 or invalid type (size 0). mTitle = Html.fromHtml( - context.getString(R.string.autofill_save_title, providerLabel), 0); + context.getString(R.string.autofill_save_title, serviceLabel), 0); } - titleView.setText(mTitle); + setServiceIcon(context, view, serviceIcon); + ScrollView subtitleContainer = null; final CustomDescription customDescription = info.getCustomDescription(); if (customDescription != null) { @@ -284,6 +289,30 @@ final class SaveUi { show(); } + private void setServiceIcon(Context context, View view, Drawable serviceIcon) { + final ImageView iconView = view.findViewById(R.id.autofill_save_icon); + final Resources res = context.getResources(); + + final int maxWidth = res.getDimensionPixelSize(R.dimen.autofill_save_icon_max_size); + final int maxHeight = maxWidth; + final int actualWidth = serviceIcon.getMinimumWidth(); + final int actualHeight = serviceIcon.getMinimumHeight(); + + if (actualWidth <= maxWidth && actualHeight <= maxHeight) { + if (sDebug) { + Slog.d(TAG, "Addingservice icon " + + "(" + actualWidth + "x" + actualHeight + ") as it's less than maximum " + + "(" + maxWidth + "x" + maxHeight + ")."); + } + iconView.setImageDrawable(serviceIcon); + } else { + Slog.w(TAG, "Not adding service icon of size " + + "(" + actualWidth + "x" + actualHeight + ") because maximum is " + + "(" + maxWidth + "x" + maxHeight + ")."); + iconView.setVisibility(View.INVISIBLE); + } + } + /** * Update the pending UI, if any. * diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 92d3d39166a6..edcd4b7ba99b 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -4535,7 +4535,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { } mOutputFile.close(); } catch (IOException e) { - /* nothing we can do about this */ + Slog.e(TAG, "IO error closing adb backup file: " + e.getMessage()); } synchronized (mLatch) { mLatch.set(true); @@ -10112,7 +10112,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF try { fd.close(); } catch (IOException e) { - // just eat it + Slog.e(TAG, "IO error closing output for adb backup: " + e.getMessage()); } Binder.restoreCallingIdentity(oldId); Slog.d(TAG, "Adb backup processing complete."); diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java index e8c505800f1e..74859777ae1e 100644 --- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java @@ -2486,7 +2486,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter try { fd.close(); } catch (IOException e) { - // just eat it + Slog.e(TAG, "IO error closing output for adb backup: " + e.getMessage()); } Binder.restoreCallingIdentity(oldId); Slog.d(TAG, "Adb backup processing complete."); diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java index 804e92c88eb7..4085f63afa8c 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java @@ -459,7 +459,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor } mOutputFile.close(); } catch (IOException e) { - /* nothing we can do about this */ + Slog.e(TAG, "IO error closing adb backup file: " + e.getMessage()); } synchronized (mLatch) { mLatch.set(true); diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index efc930ebf8ea..e6228d46e15c 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -435,9 +435,14 @@ public class ClipboardService extends SystemService { } private boolean isDeviceLocked() { - final KeyguardManager keyguardManager = getContext().getSystemService( + final long token = Binder.clearCallingIdentity(); + try { + final KeyguardManager keyguardManager = getContext().getSystemService( KeyguardManager.class); - return keyguardManager != null && keyguardManager.isDeviceLocked(); + return keyguardManager != null && keyguardManager.isDeviceLocked(); + } finally { + Binder.restoreCallingIdentity(token); + } } private final void checkUriOwnerLocked(Uri uri, int uid) { diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 018b5fa45a5a..11043bd16648 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -1142,12 +1142,13 @@ public class LockSettingsService extends ILockSettings.Stub { continue; } try { - result.put(userId, getDecryptedPasswordForTiedProfile(userId)); + result.put(managedUserId, getDecryptedPasswordForTiedProfile(managedUserId)); } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | CertificateException | IOException e) { - // ignore + Slog.e(TAG, "getDecryptedPasswordsForAllTiedProfiles failed for user " + + managedUserId, e); } } return result; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 07ab41765824..9fd54ec4f789 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -113,16 +113,20 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkQuotaInfo; +import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkTemplate; import android.net.TrafficStats; @@ -444,6 +448,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") final SparseIntArray mUidState = new SparseIntArray(); + /** Map from network ID to last observed meteredness state */ + @GuardedBy("mNetworkPoliciesSecondLock") + private final SparseBooleanArray mNetworkMetered = new SparseBooleanArray(); + private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<>(); @@ -782,6 +790,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { ACTION_CARRIER_CONFIG_CHANGED); mContext.registerReceiver(mCarrierConfigReceiver, carrierConfigFilter, null, mHandler); + // listen for meteredness changes + mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback( + new NetworkRequest.Builder().build(), mNetworkCallback); + mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener()); // tell systemReady() that the service has been initialized initCompleteSignal.countDown(); @@ -981,6 +993,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { upgradeWifiMeteredOverrideAL(); + } + } + // Only need to perform upgrade logic once + mContext.unregisterReceiver(this); + } + }; + + private final NetworkCallback mNetworkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, + NetworkCapabilities networkCapabilities) { + if (network == null || networkCapabilities == null) return; + + synchronized (mNetworkPoliciesSecondLock) { + final boolean oldMetered = mNetworkMetered.get(network.netId, false); + final boolean newMetered = !networkCapabilities + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + + if ((oldMetered != newMetered) || mNetworkMetered.indexOfKey(network.netId) < 0) { + mNetworkMetered.put(network.netId, newMetered); updateNetworkRulesNL(); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e5784851dba3..79a8dd87ad48 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -756,9 +756,11 @@ public class NotificationManagerService extends SystemService { if (r != null) { r.stats.onExpansionChanged(userAction, expanded); final long now = System.currentTimeMillis(); - MetricsLogger.action(r.getLogMaker(now) - .setCategory(MetricsEvent.NOTIFICATION_ITEM) - .setType(MetricsEvent.TYPE_DETAIL)); + if (userAction && expanded) { + MetricsLogger.action(r.getLogMaker(now) + .setCategory(MetricsEvent.NOTIFICATION_ITEM) + .setType(MetricsEvent.TYPE_DETAIL)); + } EventLogTags.writeNotificationExpansion(key, userAction ? 1 : 0, expanded ? 1 : 0, r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now)); |