Merge "[rvc-dev] explicitly set android:exported to false" into rvc-dev
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index cc06a71..8ba52ef 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -440,6 +440,7 @@
273 [(module) = "permissioncontroller"];
EvsUsageStatsReported evs_usage_stats_reported = 274 [(module) = "evs"];
AudioPowerUsageDataReported audio_power_usage_data_reported = 275;
+ TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"];
SdkExtensionStatus sdk_extension_status = 354;
// StatsdStats tracks platform atoms with ids upto 500.
@@ -447,7 +448,7 @@
}
// Pulled events will start at field 10000.
- // Next: 10083
+ // Next: 10084
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -540,6 +541,8 @@
SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
DisplayWakeReason display_wake_reason = 10081 [(module) = "framework"];
DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"];
+ BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered =
+ 10083 [(module) = "framework"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -6029,6 +6032,12 @@
optional int32 user_locked_fields = 6;
// Indicates if the channel was deleted by the app.
optional bool is_deleted = 7;
+ // Indicates if the channel was marked as a conversation by the app.
+ optional bool is_conversation = 8;
+ // Indicates if the channel is a conversation that was demoted by the user.
+ optional bool is_demoted_conversation = 9;
+ // Indicates if the channel is a conversation that was marked as important by the user.
+ optional bool is_important_conversation = 10;
}
/**
@@ -9168,6 +9177,28 @@
}
/**
+ * Logs when a tune occurs through device's Frontend.
+ * This is atom ID 276.
+ *
+ * Logged from:
+ * frameworks/base/media/java/android/media/tv/tuner/Tuner.java
+ */
+message TvTunerStateChanged {
+ enum State {
+ UNKNOWN = 0;
+ TUNING = 1; // Signal is tuned
+ LOCKED = 2; // the signal is locked
+ NOT_LOCKED = 3; // the signal isn’t locked.
+ SIGNAL_LOST = 4; // the signal was locked, but is lost now.
+ SCANNING = 5; // the signal is scanned
+ SCAN_STOPPED = 6; // the scan is stopped.
+ }
+ // The uid of the application that sent this custom atom.
+ optional int32 uid = 1 [(is_uid) = true];
+ // new state
+ optional State state = 2;
+}
+/**
* Logs when an app is frozen or unfrozen.
*
* Logged from:
@@ -9803,3 +9834,25 @@
}
optional AudioType type = 4;
}
+
+/**
+ * Pulls bytes transferred over WiFi and mobile networks sliced by uid, is_metered, and tag.
+ *
+ * Pulled from:
+ * StatsPullAtomService, which uses NetworkStatsService to query NetworkStats.
+ */
+message BytesTransferByTagAndMetered {
+ optional int32 uid = 1 [(is_uid) = true];
+
+ optional bool is_metered = 2;
+
+ optional int32 tag = 3;
+
+ optional int64 rx_bytes = 4;
+
+ optional int64 rx_packets = 5;
+
+ optional int64 tx_bytes = 6;
+
+ optional int64 tx_packets = 7;
+}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 3ce7689..be1681b 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -229,7 +229,16 @@
void unregisterTaskStackListener(in ITaskStackListener listener);
void setTaskResizeable(int taskId, int resizeableMode);
void toggleFreeformWindowingMode(in IBinder token);
- void resizeTask(int taskId, in Rect bounds, int resizeMode);
+
+ /**
+ * Resize the task with given bounds
+ *
+ * @param taskId The id of the task to set the bounds for.
+ * @param bounds The new bounds.
+ * @param resizeMode Resize mode defined as {@code ActivityTaskManager#RESIZE_MODE_*} constants.
+ * @return Return true on success. Otherwise false.
+ */
+ boolean resizeTask(int taskId, in Rect bounds, int resizeMode);
void moveStackToDisplay(int stackId, int displayId);
void removeStack(int stackId);
diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java
index cf7ed9b..da7503d 100644
--- a/core/java/android/util/AtomicFile.java
+++ b/core/java/android/util/AtomicFile.java
@@ -29,31 +29,32 @@
import java.util.function.Consumer;
/**
- * Helper class for performing atomic operations on a file by creating a
- * backup file until a write has successfully completed. If you need this
- * on older versions of the platform you can use
- * {@link android.support.v4.util.AtomicFile} in the v4 support library.
+ * Helper class for performing atomic operations on a file by writing to a new file and renaming it
+ * into the place of the original file after the write has successfully completed. If you need this
+ * on older versions of the platform you can use {@link androidx.core.util.AtomicFile} in AndroidX.
* <p>
- * Atomic file guarantees file integrity by ensuring that a file has
- * been completely written and sync'd to disk before removing its backup.
- * As long as the backup file exists, the original file is considered
- * to be invalid (left over from a previous attempt to write the file).
- * </p><p>
- * Atomic file does not confer any file locking semantics.
- * Do not use this class when the file may be accessed or modified concurrently
- * by multiple threads or processes. The caller is responsible for ensuring
- * appropriate mutual exclusion invariants whenever it accesses the file.
- * </p>
+ * Atomic file guarantees file integrity by ensuring that a file has been completely written and
+ * sync'd to disk before renaming it to the original file. Previously this is done by renaming the
+ * original file to a backup file beforehand, but this approach couldn't handle the case where the
+ * file is created for the first time. This class will also handle the backup file created by the
+ * old implementation properly.
+ * <p>
+ * Atomic file does not confer any file locking semantics. Do not use this class when the file may
+ * be accessed or modified concurrently by multiple threads or processes. The caller is responsible
+ * for ensuring appropriate mutual exclusion invariants whenever it accesses the file.
*/
public class AtomicFile {
+ private static final String LOG_TAG = "AtomicFile";
+
private final File mBaseName;
- private final File mBackupName;
+ private final File mNewName;
+ private final File mLegacyBackupName;
private final String mCommitTag;
private long mStartTime;
/**
* Create a new AtomicFile for a file located at the given File path.
- * The secondary backup file will be the same file path with ".bak" appended.
+ * The new file created when writing will be the same file path with ".new" appended.
*/
public AtomicFile(File baseName) {
this(baseName, null);
@@ -65,7 +66,8 @@
*/
public AtomicFile(File baseName, String commitTag) {
mBaseName = baseName;
- mBackupName = new File(baseName.getPath() + ".bak");
+ mNewName = new File(baseName.getPath() + ".new");
+ mLegacyBackupName = new File(baseName.getPath() + ".bak");
mCommitTag = commitTag;
}
@@ -78,11 +80,12 @@
}
/**
- * Delete the atomic file. This deletes both the base and backup files.
+ * Delete the atomic file. This deletes both the base and new files.
*/
public void delete() {
mBaseName.delete();
- mBackupName.delete();
+ mNewName.delete();
+ mLegacyBackupName.delete();
}
/**
@@ -112,36 +115,28 @@
public FileOutputStream startWrite(long startTime) throws IOException {
mStartTime = startTime;
- // Rename the current file so it may be used as a backup during the next read
- if (mBaseName.exists()) {
- if (!mBackupName.exists()) {
- if (!mBaseName.renameTo(mBackupName)) {
- Log.w("AtomicFile", "Couldn't rename file " + mBaseName
- + " to backup file " + mBackupName);
- }
- } else {
- mBaseName.delete();
+ if (mLegacyBackupName.exists()) {
+ if (!mLegacyBackupName.renameTo(mBaseName)) {
+ Log.e(LOG_TAG, "Failed to rename legacy backup file " + mLegacyBackupName
+ + " to base file " + mBaseName);
}
}
- FileOutputStream str = null;
+
try {
- str = new FileOutputStream(mBaseName);
+ return new FileOutputStream(mNewName);
} catch (FileNotFoundException e) {
- File parent = mBaseName.getParentFile();
+ File parent = mNewName.getParentFile();
if (!parent.mkdirs()) {
- throw new IOException("Couldn't create directory " + mBaseName);
+ throw new IOException("Failed to create directory for " + mNewName);
}
- FileUtils.setPermissions(
- parent.getPath(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
- -1, -1);
+ FileUtils.setPermissions(parent.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IXOTH, -1, -1);
try {
- str = new FileOutputStream(mBaseName);
+ return new FileOutputStream(mNewName);
} catch (FileNotFoundException e2) {
- throw new IOException("Couldn't create " + mBaseName);
+ throw new IOException("Failed to create new file " + mNewName, e2);
}
}
- return str;
}
/**
@@ -151,36 +146,45 @@
* will return the new file stream.
*/
public void finishWrite(FileOutputStream str) {
- if (str != null) {
- FileUtils.sync(str);
- try {
- str.close();
- mBackupName.delete();
- } catch (IOException e) {
- Log.w("AtomicFile", "finishWrite: Got exception:", e);
- }
- if (mCommitTag != null) {
- com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
- mCommitTag, SystemClock.uptimeMillis() - mStartTime);
- }
+ if (str == null) {
+ return;
+ }
+ if (!FileUtils.sync(str)) {
+ Log.e(LOG_TAG, "Failed to sync file output stream");
+ }
+ try {
+ str.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Failed to close file output stream", e);
+ }
+ if (!mNewName.renameTo(mBaseName)) {
+ Log.e(LOG_TAG, "Failed to rename new file " + mNewName + " to base file " + mBaseName);
+ }
+ if (mCommitTag != null) {
+ com.android.internal.logging.EventLogTags.writeCommitSysConfigFile(
+ mCommitTag, SystemClock.uptimeMillis() - mStartTime);
}
}
/**
* Call when you have failed for some reason at writing to the stream
* returned by {@link #startWrite()}. This will close the current
- * write stream, and roll back to the previous state of the file.
+ * write stream, and delete the new file.
*/
public void failWrite(FileOutputStream str) {
- if (str != null) {
- FileUtils.sync(str);
- try {
- str.close();
- mBaseName.delete();
- mBackupName.renameTo(mBaseName);
- } catch (IOException e) {
- Log.w("AtomicFile", "failWrite: Got exception:", e);
- }
+ if (str == null) {
+ return;
+ }
+ if (!FileUtils.sync(str)) {
+ Log.e(LOG_TAG, "Failed to sync file output stream");
+ }
+ try {
+ str.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Failed to close file output stream", e);
+ }
+ if (!mNewName.delete()) {
+ Log.e(LOG_TAG, "Failed to delete new file " + mNewName);
}
}
@@ -210,32 +214,34 @@
}
/**
- * Open the atomic file for reading. If there previously was an
- * incomplete write, this will roll back to the last good data before
- * opening for read. You should call close() on the FileInputStream when
- * you are done reading from it.
- *
- * <p>Note that if another thread is currently performing
- * a write, this will incorrectly consider it to be in the state of a bad
- * write and roll back, causing the new data currently being written to
- * be dropped. You must do your own threading protection for access to
- * AtomicFile.
+ * Open the atomic file for reading. You should call close() on the FileInputStream when you are
+ * done reading from it.
+ * <p>
+ * You must do your own threading protection for access to AtomicFile.
*/
public FileInputStream openRead() throws FileNotFoundException {
- if (mBackupName.exists()) {
- mBaseName.delete();
- mBackupName.renameTo(mBaseName);
+ if (mLegacyBackupName.exists()) {
+ if (!mLegacyBackupName.renameTo(mBaseName)) {
+ Log.e(LOG_TAG, "Failed to rename legacy backup file " + mLegacyBackupName
+ + " to base file " + mBaseName);
+ }
+ }
+
+ if (mNewName.exists()) {
+ if (!mNewName.delete()) {
+ Log.e(LOG_TAG, "Failed to delete outdated new file " + mNewName);
+ }
}
return new FileInputStream(mBaseName);
}
/**
* @hide
- * Checks if the original or backup file exists.
- * @return whether the original or backup file exists.
+ * Checks if the original or legacy backup file exists.
+ * @return whether the original or legacy backup file exists.
*/
public boolean exists() {
- return mBaseName.exists() || mBackupName.exists();
+ return mBaseName.exists() || mLegacyBackupName.exists();
}
/**
@@ -246,8 +252,8 @@
* the file does not exist or an I/O error is encountered.
*/
public long getLastModifiedTime() {
- if (mBackupName.exists()) {
- return mBackupName.lastModified();
+ if (mLegacyBackupName.exists()) {
+ return mLegacyBackupName.lastModified();
}
return mBaseName.lastModified();
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3730f05..fe7b0ae 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3329,6 +3329,17 @@
<!-- Controls the size of the back gesture inset. -->
<dimen name="config_backGestureInset">0dp</dimen>
+ <!-- Array of values used in Gesture Navigation settings page to reduce/increase the back
+ gesture's inset size. These values will be multiplied into the default width, read from the
+ gesture navigation overlay package, in order to create 4 different sizes which are selectable
+ via a slider component. -->
+ <array name="config_backGestureInsetScales">
+ <item>0.75</item>
+ <item>1.00</item>
+ <item>1.33</item>
+ <item>1.66</item>
+ </array>
+
<!-- Controls whether the navbar needs a scrim with
{@link Window#setEnsuringNavigationBarContrastWhenTransparent}. -->
<bool name="config_navBarNeedsScrim">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a9e0b58..7744e9e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2818,6 +2818,7 @@
<java-symbol type="bool" name="config_navBarNeedsScrim" />
<java-symbol type="bool" name="config_allowSeamlessRotationDespiteNavBarMoving" />
<java-symbol type="dimen" name="config_backGestureInset" />
+ <java-symbol type="array" name="config_backGestureInsetScales" />
<java-symbol type="color" name="system_bar_background_semi_transparent" />
<java-symbol type="bool" name="config_showGesturalNavigationHints" />
diff --git a/core/tests/utiltests/src/android/util/AtomicFileTest.java b/core/tests/utiltests/src/android/util/AtomicFileTest.java
new file mode 100644
index 0000000..547d4d8
--- /dev/null
+++ b/core/tests/utiltests/src/android/util/AtomicFileTest.java
@@ -0,0 +1,245 @@
+/*
+ * 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.util;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import android.app.Instrumentation;
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+@RunWith(Parameterized.class)
+public class AtomicFileTest {
+ private static final String BASE_NAME = "base";
+ private static final String NEW_NAME = BASE_NAME + ".new";
+ private static final String LEGACY_BACKUP_NAME = BASE_NAME + ".bak";
+
+ private enum WriteAction {
+ FINISH,
+ FAIL,
+ ABORT
+ }
+
+ private static final byte[] BASE_BYTES = "base".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] EXISTING_NEW_BYTES = "unnew".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] NEW_BYTES = "new".getBytes(StandardCharsets.UTF_8);
+ private static final byte[] LEGACY_BACKUP_BYTES = "bak".getBytes(StandardCharsets.UTF_8);
+
+ // JUnit wants every parameter to be used so make it happy.
+ @Parameterized.Parameter()
+ public String mUnusedTestName;
+ @Nullable
+ @Parameterized.Parameter(1)
+ public String[] mExistingFileNames;
+ @Nullable
+ @Parameterized.Parameter(2)
+ public WriteAction mWriteAction;
+ @Nullable
+ @Parameterized.Parameter(3)
+ public byte[] mExpectedBytes;
+
+ private final Instrumentation mInstrumentation =
+ InstrumentationRegistry.getInstrumentation();
+ private final Context mContext = mInstrumentation.getContext();
+
+ private final File mDirectory = mContext.getFilesDir();
+ private final File mBaseFile = new File(mDirectory, BASE_NAME);
+ private final File mNewFile = new File(mDirectory, NEW_NAME);
+ private final File mLegacyBackupFile = new File(mDirectory, LEGACY_BACKUP_NAME);
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Object[][] data() {
+ return new Object[][] {
+ { "none + none = none", null, null, null },
+ { "none + finish = new", null, WriteAction.FINISH, NEW_BYTES },
+ { "none + fail = none", null, WriteAction.FAIL, null },
+ { "none + abort = none", null, WriteAction.ABORT, null },
+ { "base + none = base", new String[] { BASE_NAME }, null, BASE_BYTES },
+ { "base + finish = new", new String[] { BASE_NAME }, WriteAction.FINISH,
+ NEW_BYTES },
+ { "base + fail = base", new String[] { BASE_NAME }, WriteAction.FAIL, BASE_BYTES },
+ { "base + abort = base", new String[] { BASE_NAME }, WriteAction.ABORT,
+ BASE_BYTES },
+ { "new + none = none", new String[] { NEW_NAME }, null, null },
+ { "new + finish = new", new String[] { NEW_NAME }, WriteAction.FINISH, NEW_BYTES },
+ { "new + fail = none", new String[] { NEW_NAME }, WriteAction.FAIL, null },
+ { "new + abort = none", new String[] { NEW_NAME }, WriteAction.ABORT, null },
+ { "bak + none = bak", new String[] { LEGACY_BACKUP_NAME }, null,
+ LEGACY_BACKUP_BYTES },
+ { "bak + finish = new", new String[] { LEGACY_BACKUP_NAME }, WriteAction.FINISH,
+ NEW_BYTES },
+ { "bak + fail = bak", new String[] { LEGACY_BACKUP_NAME }, WriteAction.FAIL,
+ LEGACY_BACKUP_BYTES },
+ { "bak + abort = bak", new String[] { LEGACY_BACKUP_NAME }, WriteAction.ABORT,
+ LEGACY_BACKUP_BYTES },
+ { "base & new + none = base", new String[] { BASE_NAME, NEW_NAME }, null,
+ BASE_BYTES },
+ { "base & new + finish = new", new String[] { BASE_NAME, NEW_NAME },
+ WriteAction.FINISH, NEW_BYTES },
+ { "base & new + fail = base", new String[] { BASE_NAME, NEW_NAME },
+ WriteAction.FAIL, BASE_BYTES },
+ { "base & new + abort = base", new String[] { BASE_NAME, NEW_NAME },
+ WriteAction.ABORT, BASE_BYTES },
+ { "base & bak + none = bak", new String[] { BASE_NAME, LEGACY_BACKUP_NAME }, null,
+ LEGACY_BACKUP_BYTES },
+ { "base & bak + finish = new", new String[] { BASE_NAME, LEGACY_BACKUP_NAME },
+ WriteAction.FINISH, NEW_BYTES },
+ { "base & bak + fail = bak", new String[] { BASE_NAME, LEGACY_BACKUP_NAME },
+ WriteAction.FAIL, LEGACY_BACKUP_BYTES },
+ { "base & bak + abort = bak", new String[] { BASE_NAME, LEGACY_BACKUP_NAME },
+ WriteAction.ABORT, LEGACY_BACKUP_BYTES },
+ { "new & bak + none = bak", new String[] { NEW_NAME, LEGACY_BACKUP_NAME }, null,
+ LEGACY_BACKUP_BYTES },
+ { "new & bak + finish = new", new String[] { NEW_NAME, LEGACY_BACKUP_NAME },
+ WriteAction.FINISH, NEW_BYTES },
+ { "new & bak + fail = bak", new String[] { NEW_NAME, LEGACY_BACKUP_NAME },
+ WriteAction.FAIL, LEGACY_BACKUP_BYTES },
+ { "new & bak + abort = bak", new String[] { NEW_NAME, LEGACY_BACKUP_NAME },
+ WriteAction.ABORT, LEGACY_BACKUP_BYTES },
+ { "base & new & bak + none = bak",
+ new String[] { BASE_NAME, NEW_NAME, LEGACY_BACKUP_NAME }, null,
+ LEGACY_BACKUP_BYTES },
+ { "base & new & bak + finish = new",
+ new String[] { BASE_NAME, NEW_NAME, LEGACY_BACKUP_NAME },
+ WriteAction.FINISH, NEW_BYTES },
+ { "base & new & bak + fail = bak",
+ new String[] { BASE_NAME, NEW_NAME, LEGACY_BACKUP_NAME }, WriteAction.FAIL,
+ LEGACY_BACKUP_BYTES },
+ { "base & new & bak + abort = bak",
+ new String[] { BASE_NAME, NEW_NAME, LEGACY_BACKUP_NAME }, WriteAction.ABORT,
+ LEGACY_BACKUP_BYTES },
+ };
+ }
+
+ @Before
+ @After
+ public void deleteFiles() {
+ mBaseFile.delete();
+ mNewFile.delete();
+ mLegacyBackupFile.delete();
+ }
+
+ @Test
+ public void testAtomicFile() throws Exception {
+ if (mExistingFileNames != null) {
+ for (String fileName : mExistingFileNames) {
+ switch (fileName) {
+ case BASE_NAME:
+ writeBytes(mBaseFile, BASE_BYTES);
+ break;
+ case NEW_NAME:
+ writeBytes(mNewFile, EXISTING_NEW_BYTES);
+ break;
+ case LEGACY_BACKUP_NAME:
+ writeBytes(mLegacyBackupFile, LEGACY_BACKUP_BYTES);
+ break;
+ default:
+ throw new AssertionError(fileName);
+ }
+ }
+ }
+
+ AtomicFile atomicFile = new AtomicFile(mBaseFile);
+ if (mWriteAction != null) {
+ try (FileOutputStream outputStream = atomicFile.startWrite()) {
+ outputStream.write(NEW_BYTES);
+ switch (mWriteAction) {
+ case FINISH:
+ atomicFile.finishWrite(outputStream);
+ break;
+ case FAIL:
+ atomicFile.failWrite(outputStream);
+ break;
+ case ABORT:
+ // Neither finishing nor failing is called upon abort.
+ break;
+ default:
+ throw new AssertionError(mWriteAction);
+ }
+ }
+ }
+
+ if (mExpectedBytes != null) {
+ try (FileInputStream inputStream = atomicFile.openRead()) {
+ assertArrayEquals(mExpectedBytes, readAllBytes(inputStream));
+ }
+ } else {
+ assertThrows(FileNotFoundException.class, () -> atomicFile.openRead());
+ }
+ }
+
+ private static void writeBytes(@NonNull File file, @NonNull byte[] bytes) throws IOException {
+ try (FileOutputStream outputStream = new FileOutputStream(file)) {
+ outputStream.write(bytes);
+ }
+ }
+
+ // InputStream.readAllBytes() is introduced in Java 9. Our files are small enough so that a
+ // naive implementation is okay.
+ private static byte[] readAllBytes(@NonNull InputStream inputStream) throws IOException {
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ int b;
+ while ((b = inputStream.read()) != -1) {
+ outputStream.write(b);
+ }
+ return outputStream.toByteArray();
+ }
+ }
+
+ @NonNull
+ public static <T extends Throwable> T assertThrows(@NonNull Class<T> expectedType,
+ @NonNull ThrowingRunnable runnable) {
+ try {
+ runnable.run();
+ } catch (Throwable t) {
+ if (!expectedType.isInstance(t)) {
+ sneakyThrow(t);
+ }
+ //noinspection unchecked
+ return (T) t;
+ }
+ throw new AssertionError(String.format("Expected %s wasn't thrown",
+ expectedType.getSimpleName()));
+ }
+
+ private static <T extends Throwable> void sneakyThrow(@NonNull Throwable throwable) throws T {
+ //noinspection unchecked
+ throw (T) throwable;
+ }
+
+ private interface ThrowingRunnable {
+ void run() throws Throwable;
+ }
+}
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index bbd7399..54675d0 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -321,6 +321,21 @@
@UnsupportedAppUsage
private long mNativeObject;
+ private String convertMuxerStateCodeToString(int aState) {
+ switch (aState) {
+ case MUXER_STATE_UNINITIALIZED:
+ return "UNINITIALIZED";
+ case MUXER_STATE_INITIALIZED:
+ return "INITIALIZED";
+ case MUXER_STATE_STARTED:
+ return "STARTED";
+ case MUXER_STATE_STOPPED:
+ return "STOPPED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
/**
* Constructor.
* Creates a media muxer that writes to the specified path.
@@ -397,7 +412,7 @@
nativeSetOrientationHint(mNativeObject, degrees);
} else {
throw new IllegalStateException("Can't set rotation degrees due" +
- " to wrong state.");
+ " to wrong state(" + convertMuxerStateCodeToString(mState) + ")");
}
}
@@ -432,7 +447,8 @@
if (mState == MUXER_STATE_INITIALIZED && mNativeObject != 0) {
nativeSetLocation(mNativeObject, latitudex10000, longitudex10000);
} else {
- throw new IllegalStateException("Can't set location due to wrong state.");
+ throw new IllegalStateException("Can't set location due to wrong state("
+ + convertMuxerStateCodeToString(mState) + ")");
}
}
@@ -451,7 +467,8 @@
nativeStart(mNativeObject);
mState = MUXER_STATE_STARTED;
} else {
- throw new IllegalStateException("Can't start due to wrong state.");
+ throw new IllegalStateException("Can't start due to wrong state("
+ + convertMuxerStateCodeToString(mState) + ")");
}
}
@@ -462,10 +479,16 @@
*/
public void stop() {
if (mState == MUXER_STATE_STARTED) {
- nativeStop(mNativeObject);
- mState = MUXER_STATE_STOPPED;
+ try {
+ nativeStop(mNativeObject);
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ mState = MUXER_STATE_STOPPED;
+ }
} else {
- throw new IllegalStateException("Can't stop due to wrong state.");
+ throw new IllegalStateException("Can't stop due to wrong state("
+ + convertMuxerStateCodeToString(mState) + ")");
}
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 50af60a..a458b16 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.app.ActivityManager;
import android.content.Context;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.TvInputService;
@@ -55,6 +56,8 @@
import android.os.Message;
import android.util.Log;
+import com.android.internal.util.FrameworkStatsLog;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -208,7 +211,7 @@
private FrontendInfo mFrontendInfo;
private Integer mFrontendHandle;
private int mFrontendType = FrontendSettings.TYPE_UNDEFINED;
-
+ private int mUserId;
private Lnb mLnb;
private Integer mLnbHandle;
@Nullable
@@ -232,6 +235,11 @@
new TunerResourceManager.ResourcesReclaimListener() {
@Override
public void onReclaimResources() {
+ if (mFrontend != null) {
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
+ }
mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST));
}
};
@@ -261,6 +269,8 @@
profile, new HandlerExecutor(mHandler), mResourceListener, clientId);
mClientId = clientId[0];
+ mUserId = ActivityManager.getCurrentUser();
+
setFrontendInfoList();
setLnbIds();
}
@@ -358,6 +368,9 @@
TunerUtils.throwExceptionForResult(res, "failed to close frontend");
}
mTunerResourceManager.releaseFrontend(mFrontendHandle, mClientId);
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__UNKNOWN);
mFrontendHandle = null;
mFrontend = null;
}
@@ -557,9 +570,14 @@
*/
@Result
public int tune(@NonNull FrontendSettings settings) {
+ Log.d(TAG, "Tune to " + settings.getFrequency());
mFrontendType = settings.getType();
if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
mFrontendInfo = null;
+ Log.d(TAG, "Write Stats Log for tuning.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__TUNING);
return nativeTune(settings.getType(), settings);
}
return RESULT_UNAVAILABLE;
@@ -602,6 +620,9 @@
mScanCallback = scanCallback;
mScanCallbackExecutor = executor;
mFrontendInfo = null;
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCANNING);
return nativeScan(settings.getType(), settings, scanType);
}
return RESULT_UNAVAILABLE;
@@ -620,6 +641,10 @@
*/
@Result
public int cancelScanning() {
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCAN_STOPPED);
+
int retVal = nativeStopScan();
mScanCallback = null;
mScanCallbackExecutor = null;
@@ -779,12 +804,33 @@
}
private void onFrontendEvent(int eventType) {
+ Log.d(TAG, "Got event from tuning. Event type: " + eventType);
if (mOnTunerEventExecutor != null && mOnTuneEventListener != null) {
mOnTunerEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
}
+
+ Log.d(TAG, "Wrote Stats Log for the events from tuning.");
+ if (eventType == OnTuneEventListener.SIGNAL_LOCKED) {
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
+ } else if (eventType == OnTuneEventListener.SIGNAL_NO_SIGNAL) {
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__NOT_LOCKED);
+ } else if (eventType == OnTuneEventListener.SIGNAL_LOST_LOCK) {
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SIGNAL_LOST);
+ }
}
private void onLocked() {
+ Log.d(TAG, "Wrote Stats Log for locked event from scanning.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
+ FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
+
if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
}
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 0c1e9a2..262ec76 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -26,15 +26,11 @@
#include <unistd.h>
#include <fcntl.h>
-#include <android/api-level.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaMuxer.h>
-extern "C" int android_get_application_target_sdk_version();
-
namespace android {
struct fields_t {
@@ -233,31 +229,11 @@
status_t err = muxer->stop();
- if (android_get_application_target_sdk_version() >= __ANDROID_API_R__) {
- switch (err) {
- case OK:
- break;
- case ERROR_IO: {
- jniThrowException(env, "java/lang/UncheckedIOException",
- "Muxer stopped unexpectedly");
- return;
- }
- case ERROR_MALFORMED: {
- jniThrowException(env, "java/io/IOError",
- "Failure of reading or writing operation");
- return;
- }
- default: {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to stop the muxer");
- return;
- }
- }
- } else {
- if (err != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", "Failed to stop the muxer");
- return;
- }
+ if (err != OK) {
+ ALOGE("Error during stop:%d", err);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Error during stop(), muxer would have stopped already");
+ return;
}
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e42e438..3dbf5a4 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1376,4 +1376,7 @@
<!-- A content description for work profile app [CHAR LIMIT=35] -->
<string name="accessibility_work_profile_app_description">Work <xliff:g id="app_name" example="Camera">%s</xliff:g></string>
+
+ <!-- Name of the 3.5mm and usb audio device. [CHAR LIMIT=40] -->
+ <string name="media_transfer_wired_usb_device_name">Wired headphone</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 8ea5ff1..9a3ae1b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -61,11 +61,11 @@
switch (mRouteInfo.getType()) {
case TYPE_WIRED_HEADSET:
case TYPE_WIRED_HEADPHONES:
- name = mContext.getString(R.string.media_transfer_wired_device_name);
- break;
case TYPE_USB_DEVICE:
case TYPE_USB_HEADSET:
case TYPE_USB_ACCESSORY:
+ name = mContext.getString(R.string.media_transfer_wired_usb_device_name);
+ break;
case TYPE_DOCK:
case TYPE_HDMI:
name = mRouteInfo.getName();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 47f6fe3..421e5c0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -100,12 +100,12 @@
when(mInfo.getName()).thenReturn(deviceName);
assertThat(mPhoneMediaDevice.getName())
- .isEqualTo(mContext.getString(R.string.media_transfer_wired_device_name));
+ .isEqualTo(mContext.getString(R.string.media_transfer_wired_usb_device_name));
when(mInfo.getType()).thenReturn(TYPE_USB_DEVICE);
assertThat(mPhoneMediaDevice.getName())
- .isEqualTo(deviceName);
+ .isEqualTo(mContext.getString(R.string.media_transfer_wired_usb_device_name));
when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
index e4ae7c1..46396e3 100644
--- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
@@ -20,23 +20,29 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screenshot_action_chip_margin_right"
+ android:paddingVertical="@dimen/screenshot_action_chip_margin_vertical"
android:layout_gravity="center"
- android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
- android:background="@drawable/action_chip_background"
- android:alpha="0.0"
- android:gravity="center">
- <ImageView
- android:id="@+id/screenshot_action_chip_icon"
- android:layout_width="@dimen/screenshot_action_chip_icon_size"
- android:layout_height="@dimen/screenshot_action_chip_icon_size"
- android:layout_marginStart="@dimen/screenshot_action_chip_padding_start"
- android:layout_marginEnd="@dimen/screenshot_action_chip_padding_middle"/>
- <TextView
- android:id="@+id/screenshot_action_chip_text"
+ android:gravity="center"
+ android:alpha="0.0">
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/screenshot_action_chip_padding_end"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textSize="@dimen/screenshot_action_chip_text_size"
- android:textColor="@color/global_screenshot_button_text"/>
+ android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
+ android:background="@drawable/action_chip_background"
+ android:gravity="center">
+ <ImageView
+ android:id="@+id/screenshot_action_chip_icon"
+ android:layout_width="@dimen/screenshot_action_chip_icon_size"
+ android:layout_height="@dimen/screenshot_action_chip_icon_size"
+ android:layout_marginStart="@dimen/screenshot_action_chip_padding_start"
+ android:layout_marginEnd="@dimen/screenshot_action_chip_padding_middle"/>
+ <TextView
+ android:id="@+id/screenshot_action_chip_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/screenshot_action_chip_padding_end"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textSize="@dimen/screenshot_action_chip_text_size"
+ android:textColor="@color/global_screenshot_button_text"/>
+ </LinearLayout>
</com.android.systemui.screenshot.ScreenshotActionChip>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a3d32c1..31edcf6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -314,13 +314,14 @@
<dimen name="screenshot_dismiss_button_margin">8dp</dimen>
<dimen name="screenshot_action_container_offset_y">32dp</dimen>
<dimen name="screenshot_action_container_corner_radius">10dp</dimen>
- <dimen name="screenshot_action_container_padding_vertical">16dp</dimen>
+ <dimen name="screenshot_action_container_padding_vertical">6dp</dimen>
<dimen name="screenshot_action_container_margin_horizontal">8dp</dimen>
<dimen name="screenshot_action_container_padding_left">96dp</dimen>
<dimen name="screenshot_action_container_padding_right">8dp</dimen>
<!-- Radius of the chip background on global screenshot actions -->
<dimen name="screenshot_button_corner_radius">20dp</dimen>
<dimen name="screenshot_action_chip_margin_right">8dp</dimen>
+ <dimen name="screenshot_action_chip_margin_vertical">10dp</dimen>
<dimen name="screenshot_action_chip_padding_vertical">7dp</dimen>
<dimen name="screenshot_action_chip_icon_size">18dp</dimen>
<dimen name="screenshot_action_chip_padding_start">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index 236fa2d..f970152 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -18,7 +18,6 @@
import android.app.ActivityView
import android.app.Dialog
-import android.content.ComponentName
import android.content.Intent
import android.provider.Settings
import android.view.View
@@ -58,17 +57,13 @@
launchIntent.putExtra(EXTRA_USE_PANEL, true)
// Apply flags to make behaviour match documentLaunchMode=always.
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
view.startActivity(launchIntent)
}
override fun onActivityViewDestroyed(view: ActivityView) {}
-
- override fun onTaskCreated(taskId: Int, componentName: ComponentName) {}
-
- override fun onTaskRemovalStarted(taskId: Int) {}
}
init {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 5e36704..6572937 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -34,6 +34,7 @@
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -56,6 +57,7 @@
private final ProximitySensor mProximitySensor;
private final DelayedWakeLock.Builder mDelayedWakeLockBuilder;
private final Handler mHandler;
+ private final DelayableExecutor mDelayableExecutor;
private final BiometricUnlockController mBiometricUnlockController;
private final BroadcastDispatcher mBroadcastDispatcher;
private final DozeHost mDozeHost;
@@ -68,6 +70,7 @@
DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
ProximitySensor proximitySensor,
DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler,
+ DelayableExecutor delayableExecutor,
BiometricUnlockController biometricUnlockController,
BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
mFalsingManager = falsingManager;
@@ -83,6 +86,7 @@
mProximitySensor = proximitySensor;
mDelayedWakeLockBuilder = delayedWakeLockBuilder;
mHandler = handler;
+ mDelayableExecutor = delayableExecutor;
mBiometricUnlockController = biometricUnlockController;
mBroadcastDispatcher = broadcastDispatcher;
mDozeHost = dozeHost;
@@ -107,8 +111,8 @@
new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
new DozeFalsingManagerAdapter(mFalsingManager),
createDozeTriggers(dozeService, mAsyncSensorManager, mDozeHost,
- mAlarmManager, config, mDozeParameters, mHandler, wakeLock, machine,
- mDockManager, mDozeLog),
+ mAlarmManager, config, mDozeParameters, mDelayableExecutor, wakeLock,
+ machine, mDockManager, mDozeLog),
createDozeUi(dozeService, mDozeHost, wakeLock, machine, mHandler,
mAlarmManager, mDozeParameters, mDozeLog),
new DozeScreenState(wrappedService, mHandler, mDozeHost, mDozeParameters,
@@ -135,11 +139,11 @@
private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager,
DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config,
- DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine,
- DockManager dockManager, DozeLog dozeLog) {
+ DozeParameters params, DelayableExecutor delayableExecutor, WakeLock wakeLock,
+ DozeMachine machine, DockManager dockManager, DozeLog dozeLog) {
boolean allowPulseTriggers = true;
return new DozeTriggers(context, machine, host, alarmManager, config, params,
- sensorManager, handler, wakeLock, allowPulseTriggers, dockManager,
+ sensorManager, delayableExecutor, wakeLock, allowPulseTriggers, dockManager,
mProximitySensor, dozeLog, mBroadcastDispatcher);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index e1081cd..78f8f67 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -101,7 +101,8 @@
public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
- Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog) {
+ Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog,
+ ProximitySensor proximitySensor) {
mContext = context;
mAlarmManager = alarmManager;
mSensorManager = sensorManager;
@@ -111,6 +112,7 @@
mProxCallback = proxCallback;
mResolver = mContext.getContentResolver();
mCallback = callback;
+ mProximitySensor = proximitySensor;
boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT);
mSensors = new TriggerSensor[] {
@@ -173,7 +175,6 @@
dozeLog),
};
- mProximitySensor = new ProximitySensor(context.getResources(), sensorManager);
setProxListening(false); // Don't immediately start listening when we register.
mProximitySensor.register(
proximityEvent -> {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 3510e07..6a55014 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -26,7 +26,6 @@
import android.content.res.Configuration;
import android.hardware.display.AmbientDisplayConfiguration;
import android.metrics.LogMaker;
-import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.Formatter;
@@ -43,6 +42,7 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.wakelock.WakeLock;
@@ -152,9 +152,9 @@
public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
AlarmManager alarmManager, AmbientDisplayConfiguration config,
- DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler,
- WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
- ProximitySensor proximitySensor,
+ DozeParameters dozeParameters, AsyncSensorManager sensorManager,
+ DelayableExecutor delayableExecutor, WakeLock wakeLock, boolean allowPulseTriggers,
+ DockManager dockManager, ProximitySensor proximitySensor,
DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher) {
mContext = context;
mMachine = machine;
@@ -165,10 +165,10 @@
mWakeLock = wakeLock;
mAllowPulseTriggers = allowPulseTriggers;
mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
- config, wakeLock, this::onSensor, this::onProximityFar, dozeLog);
+ config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
mDockManager = dockManager;
- mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, handler);
+ mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, delayableExecutor);
mDozeLog = dozeLog;
mBroadcastDispatcher = broadcastDispatcher;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 13516a9..7f7e108 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -170,9 +170,9 @@
private final @AnimationType int mAnimationType;
private final Rect mDestinationBounds = new Rect();
- private T mStartValue;
+ protected T mCurrentValue;
+ protected T mStartValue;
private T mEndValue;
- private T mCurrentValue;
private PipAnimationCallback mPipAnimationCallback;
private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@@ -288,7 +288,6 @@
*/
void updateEndValue(T endValue) {
mEndValue = endValue;
- mStartValue = mCurrentValue;
}
SurfaceControl.Transaction newSurfaceControlTransaction() {
@@ -337,6 +336,12 @@
tx.show(leash);
tx.apply();
}
+
+ @Override
+ void updateEndValue(Float endValue) {
+ super.updateEndValue(endValue);
+ mStartValue = mCurrentValue;
+ }
};
}
@@ -392,6 +397,14 @@
getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds())
.crop(tx, leash, getDestinationBounds());
}
+
+ @Override
+ void updateEndValue(Rect endValue) {
+ super.updateEndValue(endValue);
+ if (mStartValue != null && mCurrentValue != null) {
+ mStartValue.set(mCurrentValue);
+ }
+ }
};
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index d0ff2ff9..af9dd57 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -431,13 +431,21 @@
} else {
final float offsetBufferPx = BOTTOM_OFFSET_BUFFER_DP
* mContext.getResources().getDisplayMetrics().density;
- final Rect toMovementBounds = mMenuState == MENU_STATE_FULL && willResizeMenu()
+ final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
+ final Rect toMovementBounds = isExpanded
? new Rect(expandedMovementBounds)
: new Rect(normalMovementBounds);
final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
final int toBottom = toMovementBounds.bottom < toMovementBounds.top
? toMovementBounds.bottom
: toMovementBounds.bottom - extraOffset;
+
+ if (isExpanded) {
+ curBounds.set(mExpandedBounds);
+ mSnapAlgorithm.applySnapFraction(curBounds, toMovementBounds,
+ mSavedSnapFraction);
+ }
+
if ((Math.min(prevBottom, toBottom) - offsetBufferPx) <= curBounds.top
&& curBounds.top <= (Math.max(prevBottom, toBottom) + offsetBufferPx)) {
mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 6f68ee8..f2d2eb3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -703,9 +703,7 @@
mScreenshotPreview.buildLayer();
mScreenshotAnimation.start();
});
-
});
-
}
private AnimatorSet createScreenshotDropInAnimation(int width, int height, Rect bounds) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
index 44b20e5..b5209bb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
@@ -22,8 +22,8 @@
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.util.Log;
+import android.widget.FrameLayout;
import android.widget.ImageView;
-import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.R;
@@ -31,7 +31,7 @@
/**
* View for a chip with an icon and text.
*/
-public class ScreenshotActionChip extends LinearLayout {
+public class ScreenshotActionChip extends FrameLayout {
private static final String TAG = "ScreenshotActionChip";
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index 378dde2..708b5a7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -21,16 +21,17 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-import android.os.Handler;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -49,8 +50,9 @@
private String mTag = null;
@VisibleForTesting ProximityEvent mLastEvent;
private int mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL;
- private boolean mPaused;
+ @VisibleForTesting protected boolean mPaused;
private boolean mRegistered;
+ private final AtomicBoolean mAlerting = new AtomicBoolean();
private SensorEventListener mSensorEventListener = new SensorEventListener() {
@Override
@@ -217,8 +219,12 @@
/** Update all listeners with the last value this class received from the sensor. */
public void alertListeners() {
+ if (mAlerting.getAndSet(true)) {
+ return;
+ }
mListeners.forEach(proximitySensorListener ->
proximitySensorListener.onSensorEvent(mLastEvent));
+ mAlerting.set(false);
}
private void onSensorEvent(SensorEvent event) {
@@ -239,14 +245,14 @@
public static class ProximityCheck implements Runnable {
private final ProximitySensor mSensor;
- private final Handler mHandler;
+ private final DelayableExecutor mDelayableExecutor;
private List<Consumer<Boolean>> mCallbacks = new ArrayList<>();
@Inject
- public ProximityCheck(ProximitySensor sensor, Handler handler) {
+ public ProximityCheck(ProximitySensor sensor, DelayableExecutor delayableExecutor) {
mSensor = sensor;
mSensor.setTag("prox_check");
- mHandler = handler;
+ mDelayableExecutor = delayableExecutor;
mSensor.pause();
ProximitySensorListener listener = proximityEvent -> {
mCallbacks.forEach(
@@ -280,7 +286,7 @@
mCallbacks.add(callback);
if (!mSensor.isRegistered()) {
mSensor.resume();
- mHandler.postDelayed(this, timeoutMs);
+ mDelayableExecutor.executeDelayed(this, timeoutMs);
}
}
}
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 50b7af2..e0049d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -19,6 +19,7 @@
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -29,9 +30,8 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static java.lang.Thread.sleep;
-
import android.app.AppOpsManager;
+import android.os.Looper;
import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -229,12 +229,7 @@
@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);
- }
- };
+ TestHandler testHandler = new TestHandler(mTestableLooper.getLooper());
mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback);
mController.setBGHandler(testHandler);
@@ -245,6 +240,10 @@
mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
AppOpsManager.MODE_ALLOWED);
+ // Check that we "scheduled" the removal. Don't actually schedule until we are ready to
+ // process messages at a later time.
+ assertNotNull(testHandler.mDelayScheduled);
+
mTestableLooper.processAllMessages();
List<AppOpItem> list = mController.getActiveAppOps();
verify(mCallback).onActiveStateChanged(
@@ -253,8 +252,8 @@
// Duplicates are not removed between active and noted
assertEquals(2, list.size());
- sleep(10L);
-
+ // Now is later, so we can schedule delayed messages.
+ testHandler.scheduleDelayed();
mTestableLooper.processAllMessages();
verify(mCallback, never()).onActiveStateChanged(
@@ -321,4 +320,24 @@
verify(mCallback).onActiveStateChanged(
AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true);
}
+
+ private class TestHandler extends AppOpsControllerImpl.H {
+ TestHandler(Looper looper) {
+ mController.super(looper);
+ }
+
+ Runnable mDelayScheduled;
+
+ void scheduleDelayed() {
+ if (mDelayScheduled != null) {
+ mDelayScheduled.run();
+ mDelayScheduled = null;
+ }
+ }
+
+ @Override
+ public void scheduleRemoval(AppOpItem item, long timeToRemoval) {
+ mDelayScheduled = () -> super.scheduleRemoval(item, 0L);
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 317500c..a567536 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -18,6 +18,7 @@
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -46,6 +47,7 @@
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.util.sensors.ProximitySensor;
import com.android.systemui.util.wakelock.WakeLock;
import org.junit.Before;
@@ -82,7 +84,7 @@
@Mock
private DozeLog mDozeLog;
@Mock
- private Sensor mProximitySensor;
+ private ProximitySensor mProximitySensor;
private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
private TestableLooper mTestableLooper;
private DozeSensors mDozeSensors;
@@ -93,7 +95,6 @@
mTestableLooper = TestableLooper.get(this);
when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
- when(mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)).thenReturn(mProximitySensor);
doAnswer(invocation -> {
((Runnable) invocation.getArgument(0)).run();
return null;
@@ -103,10 +104,9 @@
@Test
public void testRegisterProx() {
- // We should not register with the sensor manager initially.
- verify(mSensorManager, never()).registerListener(any(), any(Sensor.class), anyInt());
+ assertFalse(mProximitySensor.isRegistered());
mDozeSensors.setProxListening(true);
- verify(mSensorManager).registerListener(any(), any(Sensor.class), anyInt());
+ verify(mProximitySensor).resume();
}
@Test
@@ -169,7 +169,8 @@
TestableDozeSensors() {
super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
- mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog);
+ mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog,
+ mProximitySensor);
for (TriggerSensor sensor : mSensors) {
if (sensor instanceof PluginSensor
&& ((PluginSensor) sensor).mPluginSensor.getType()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index debc9d6..73aaeff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -31,7 +31,6 @@
import android.hardware.Sensor;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
-import android.os.Looper;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -42,10 +41,12 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.sensors.FakeProximitySensor;
import com.android.systemui.util.sensors.FakeSensorManager;
import com.android.systemui.util.sensors.ProximitySensor;
+import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.util.wakelock.WakeLockFake;
@@ -75,6 +76,7 @@
private FakeSensorManager mSensors;
private Sensor mTapSensor;
private FakeProximitySensor mProximitySensor;
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
@Before
public void setUp() throws Exception {
@@ -89,7 +91,7 @@
mProximitySensor = new FakeProximitySensor(getContext().getResources(), asyncSensorManager);
mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
- asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
+ asyncSensorManager, mFakeExecutor, wakeLock, true,
mDockManager, mProximitySensor, mock(DozeLog.class), mBroadcastDispatcher);
waitForSensorManager();
}
@@ -111,9 +113,8 @@
verify(mMachine, never()).requestState(any());
verify(mMachine, never()).requestPulse(anyInt());
- captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
- waitForSensorManager();
mProximitySensor.setLastEvent(new ProximitySensor.ProximityEvent(false, 2));
+ captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
mProximitySensor.alertListeners();
verify(mMachine).requestPulse(anyInt());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
index 31d884c..bd697fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeProximitySensor.java
@@ -20,6 +20,7 @@
public class FakeProximitySensor extends ProximitySensor {
private boolean mAvailable;
+ private boolean mRegistered;
public FakeProximitySensor(Resources resources, AsyncSensorManager sensorManager) {
super(resources, sensorManager);
@@ -35,17 +36,22 @@
}
@Override
+ public boolean isRegistered() {
+ return mRegistered;
+ }
+
+ @Override
public boolean getSensorAvailable() {
return mAvailable;
}
@Override
protected void registerInternal() {
- // no-op
+ mRegistered = !mPaused;
}
@Override
protected void unregisterInternal() {
- // no-op
+ mRegistered = false;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
new file mode 100644
index 0000000..7221095
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximityCheckTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.util.sensors;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Handler;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Consumer;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class ProximityCheckTest extends SysuiTestCase {
+
+ private FakeProximitySensor mFakeProximitySensor;
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ private TestableCallback mTestableCallback = new TestableCallback();
+
+ private ProximitySensor.ProximityCheck mProximityCheck;
+
+ @Before
+ public void setUp() throws Exception {
+ AsyncSensorManager asyncSensorManager =
+ new AsyncSensorManager(new FakeSensorManager(mContext), null, new Handler());
+ mFakeProximitySensor = new FakeProximitySensor(mContext.getResources(), asyncSensorManager);
+
+ mProximityCheck = new ProximitySensor.ProximityCheck(mFakeProximitySensor, mFakeExecutor);
+ }
+
+ @Test
+ public void testCheck() {
+ mProximityCheck.check(100, mTestableCallback);
+
+ assertNull(mTestableCallback.mLastResult);
+
+ mFakeProximitySensor.setLastEvent(new ProximitySensor.ProximityEvent(true, 0));
+ mFakeProximitySensor.alertListeners();
+
+ assertTrue(mTestableCallback.mLastResult);
+ }
+
+ @Test
+ public void testTimeout() {
+ mProximityCheck.check(100, mTestableCallback);
+
+ assertTrue(mFakeProximitySensor.isRegistered());
+
+ mFakeExecutor.advanceClockToNext();
+ mFakeExecutor.runAllReady();
+
+ assertFalse(mFakeProximitySensor.isRegistered());
+ }
+
+ private static class TestableCallback implements Consumer<Boolean> {
+ Boolean mLastResult;
+ @Override
+ public void accept(Boolean result) {
+ mLastResult = result;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java
index 526fba7..914790b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorTest.java
@@ -219,6 +219,26 @@
waitForSensorManager();
}
+ @Test
+ public void testPreventRecursiveAlert() {
+ TestableListener listenerA = new TestableListener() {
+ @Override
+ public void onSensorEvent(ProximitySensor.ProximityEvent proximityEvent) {
+ super.onSensorEvent(proximityEvent);
+ if (mCallCount < 2) {
+ mProximitySensor.alertListeners();
+ }
+ }
+ };
+
+ mProximitySensor.register(listenerA);
+
+ mProximitySensor.alertListeners();
+
+ assertEquals(1, listenerA.mCallCount);
+ }
+
+
class TestableListener implements ProximitySensor.ProximitySensorListener {
ProximitySensor.ProximityEvent mLastEvent;
int mCallCount = 0;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37f1ad1..4ace676 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -337,6 +337,7 @@
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.QuadFunction;
import com.android.internal.util.function.TriFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AlarmManagerInternal;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleInternal;
@@ -18831,28 +18832,39 @@
@Override
public int checkContentProviderUriPermission(Uri uri, int userId,
int callingUid, int modeFlags) {
- // We can find ourselves needing to check Uri permissions while
- // already holding the WM lock, which means reaching back here for
- // the AM lock would cause an inversion. The WM team has requested
- // that we use the strategy below instead of shifting where Uri
- // grants are calculated.
+ final Object wmLock = mActivityTaskManager.getGlobalLock();
+ if (Thread.currentThread().holdsLock(wmLock)
+ && !Thread.currentThread().holdsLock(ActivityManagerService.this)) {
+ // We can find ourselves needing to check Uri permissions while already holding the
+ // WM lock, which means reaching back here for the AM lock would cause an inversion.
+ // The WM team has requested that we use the strategy below instead of shifting
+ // where Uri grants are calculated.
+ synchronized (wmLock) {
+ final int[] result = new int[1];
+ final Message msg = PooledLambda.obtainMessage(
+ LocalService::checkContentProviderUriPermission,
+ this, uri, userId, callingUid, modeFlags, wmLock, result);
+ mHandler.sendMessage(msg);
+ try {
+ wmLock.wait();
+ } catch (InterruptedException ignore) {
- // Since we could also arrive here while holding the AM lock, we
- // can't always delegate the call through the handler, and we need
- // to delicately dance between the deadlocks.
- if (Thread.currentThread().holdsLock(ActivityManagerService.this)) {
+ }
+ return result[0];
+ }
+ } else {
return ActivityManagerService.this.checkContentProviderUriPermission(uri,
userId, callingUid, modeFlags);
- } else {
- final CompletableFuture<Integer> res = new CompletableFuture<>();
- mHandler.post(() -> {
- res.complete(ActivityManagerService.this.checkContentProviderUriPermission(uri,
- userId, callingUid, modeFlags));
- });
- try {
- return res.get();
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
+ }
+ }
+
+ void checkContentProviderUriPermission(
+ Uri uri, int userId, int callingUid, int modeFlags, Object wmLock, int[] result) {
+ synchronized (ActivityManagerService.this) {
+ synchronized (wmLock) {
+ result[0] = ActivityManagerService.this.checkContentProviderUriPermission(
+ uri, userId, callingUid, modeFlags);
+ wmLock.notify();
}
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index f9d204f..43e3a04 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -45,6 +45,7 @@
import java.io.FileOutputStream;
import java.io.FileReader;
+import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -114,6 +115,14 @@
}
private PropertyChangedCallbackForTest mTestCallback;
+ // This interface is for functions related to the Process object that need a different
+ // implementation in the tests as we are not creating real processes when testing compaction.
+ @VisibleForTesting
+ interface ProcessDependencies {
+ long[] getRss(int pid);
+ void performCompaction(String action, int pid) throws IOException;
+ }
+
// Handler constants.
static final int COMPACT_PROCESS_SOME = 1;
static final int COMPACT_PROCESS_FULL = 2;
@@ -215,13 +224,16 @@
@VisibleForTesting final Set<Integer> mProcStateThrottle;
// Handler on which compaction runs.
- private Handler mCompactionHandler;
+ @VisibleForTesting
+ Handler mCompactionHandler;
private Handler mFreezeHandler;
// Maps process ID to last compaction statistics for processes that we've fully compacted. Used
// when evaluating throttles that we only consider for "full" compaction, so we don't store
- // data for "some" compactions.
- private Map<Integer, LastCompactionStats> mLastCompactionStats =
+ // data for "some" compactions. Uses LinkedHashMap to ensure insertion order is kept and
+ // facilitate removal of the oldest entry.
+ @VisibleForTesting
+ LinkedHashMap<Integer, LastCompactionStats> mLastCompactionStats =
new LinkedHashMap<Integer, LastCompactionStats>() {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
@@ -233,17 +245,20 @@
private int mFullCompactionCount;
private int mPersistentCompactionCount;
private int mBfgsCompactionCount;
+ private final ProcessDependencies mProcessDependencies;
public CachedAppOptimizer(ActivityManagerService am) {
- mAm = am;
- mCachedAppOptimizerThread = new ServiceThread("CachedAppOptimizerThread",
- THREAD_PRIORITY_FOREGROUND, true);
- mProcStateThrottle = new HashSet<>();
+ this(am, null, new DefaultProcessDependencies());
}
@VisibleForTesting
- CachedAppOptimizer(ActivityManagerService am, PropertyChangedCallbackForTest callback) {
- this(am);
+ CachedAppOptimizer(ActivityManagerService am, PropertyChangedCallbackForTest callback,
+ ProcessDependencies processDependencies) {
+ mAm = am;
+ mCachedAppOptimizerThread = new ServiceThread("CachedAppOptimizerThread",
+ THREAD_PRIORITY_FOREGROUND, true);
+ mProcStateThrottle = new HashSet<>();
+ mProcessDependencies = processDependencies;
mTestCallback = callback;
}
@@ -659,7 +674,8 @@
}
}
- private static final class LastCompactionStats {
+ @VisibleForTesting
+ static final class LastCompactionStats {
private final long[] mRssAfterCompaction;
LastCompactionStats(long[] rss) {
@@ -712,9 +728,7 @@
lastCompactAction = proc.lastCompactAction;
lastCompactTime = proc.lastCompactTime;
- // remove rather than get so that insertion order will be updated when we
- // put the post-compaction stats back into the map.
- lastCompactionStats = mLastCompactionStats.remove(pid);
+ lastCompactionStats = mLastCompactionStats.get(pid);
}
if (pid == 0) {
@@ -806,7 +820,7 @@
return;
}
- long[] rssBefore = Process.getRss(pid);
+ long[] rssBefore = mProcessDependencies.getRss(pid);
long anonRssBefore = rssBefore[2];
if (rssBefore[0] == 0 && rssBefore[1] == 0 && rssBefore[2] == 0
@@ -863,16 +877,13 @@
default:
break;
}
-
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact "
+ ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full")
+ ": " + name);
long zramFreeKbBefore = Debug.getZramFreeKb();
- FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
- fos.write(action.getBytes());
- fos.close();
- long[] rssAfter = Process.getRss(pid);
+ mProcessDependencies.performCompaction(action, pid);
+ long[] rssAfter = mProcessDependencies.getRss(pid);
long end = SystemClock.uptimeMillis();
long time = end - start;
long zramFreeKbAfter = Debug.getZramFreeKb();
@@ -882,7 +893,6 @@
rssAfter[2] - rssBefore[2], rssAfter[3] - rssBefore[3], time,
lastCompactAction, lastCompactTime, lastOomAdj, procState,
zramFreeKbBefore, zramFreeKbAfter - zramFreeKbBefore);
-
// Note that as above not taking mPhenoTypeFlagLock here to avoid locking
// on every single compaction for a flag that will seldom change and the
// impact of reading the wrong value here is low.
@@ -894,14 +904,14 @@
lastOomAdj, ActivityManager.processStateAmToProto(procState),
zramFreeKbBefore, zramFreeKbAfter);
}
-
synchronized (mAm) {
proc.lastCompactTime = end;
proc.lastCompactAction = pendingAction;
}
-
if (action.equals(COMPACT_ACTION_FULL)
|| action.equals(COMPACT_ACTION_ANON)) {
+ // Remove entry and insert again to update insertion order.
+ mLastCompactionStats.remove(pid);
mLastCompactionStats.put(pid, new LastCompactionStats(rssAfter));
}
} catch (Exception e) {
@@ -1018,4 +1028,23 @@
}
}
}
+
+ /**
+ * Default implementation for ProcessDependencies, public vor visibility to OomAdjuster class.
+ */
+ private static final class DefaultProcessDependencies implements ProcessDependencies {
+ // Get memory RSS from process.
+ @Override
+ public long[] getRss(int pid) {
+ return Process.getRss(pid);
+ }
+
+ // Compact process.
+ @Override
+ public void performCompaction(String action, int pid) throws IOException {
+ try (FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim")) {
+ fos.write(action.getBytes());
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index a099606..b9cd43d 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -51,6 +51,11 @@
private static final float MAX_GRAD = 1.0f;
private static final float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f;
+ // Constant that ensures that each step of the curve can increase by up to at least
+ // MIN_PERMISSABLE_INCREASE. Otherwise when the brightness is set to 0, the curve will never
+ // increase and will always be 0.
+ private static final float MIN_PERMISSABLE_INCREASE = 0.004f;
+
protected boolean mLoggingEnabled;
private static final Plog PLOG = Plog.createSystemPlog(TAG);
@@ -400,7 +405,9 @@
for (int i = idx+1; i < lux.length; i++) {
float currLux = lux[i];
float currBrightness = brightness[i];
- float maxBrightness = prevBrightness * permissibleRatio(currLux, prevLux);
+ float maxBrightness = MathUtils.max(
+ prevBrightness * permissibleRatio(currLux, prevLux),
+ prevBrightness + MIN_PERMISSABLE_INCREASE);
float newBrightness = MathUtils.constrain(
currBrightness, prevBrightness, maxBrightness);
if (newBrightness == currBrightness) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index a435f1e..53205ad 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -60,7 +60,7 @@
private Connection mActiveConnection;
private boolean mConnectionReady;
- private RouteDiscoveryPreference mPendingDiscoveryPreference = null;
+ private RouteDiscoveryPreference mLastDiscoveryPreference = null;
MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
int userId) {
@@ -98,11 +98,10 @@
@Override
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
+ mLastDiscoveryPreference = discoveryPreference;
if (mConnectionReady) {
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
updateBinding();
- } else {
- mPendingDiscoveryPreference = discoveryPreference;
}
}
@@ -277,9 +276,8 @@
private void onConnectionReady(Connection connection) {
if (mActiveConnection == connection) {
mConnectionReady = true;
- if (mPendingDiscoveryPreference != null) {
- updateDiscoveryPreference(mPendingDiscoveryPreference);
- mPendingDiscoveryPreference = null;
+ if (mLastDiscoveryPreference != null) {
+ updateDiscoveryPreference(mLastDiscoveryPreference);
}
}
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index fdee9f8..d7e7247 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -45,7 +45,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
-import android.util.Log;
+import android.util.Slog;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -58,7 +58,8 @@
// TODO: check thread safety. We may need to use lock to protect variables.
class SystemMediaRoute2Provider extends MediaRoute2Provider {
private static final String TAG = "MR2SystemProvider";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ // TODO(b/156996903): Revert it when releasing the framework.
+ private static final boolean DEBUG = true;
static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE";
@@ -269,7 +270,11 @@
builder.addRoute(route);
}
}
- setProviderState(builder.build());
+ MediaRoute2ProviderInfo providerInfo = builder.build();
+ setProviderState(providerInfo);
+ if (DEBUG) {
+ Slog.d(TAG, "Updating system provider info : " + providerInfo);
+ }
}
/**
@@ -327,6 +332,9 @@
if (Objects.equals(oldSessionInfo, newSessionInfo)) {
return false;
} else {
+ if (DEBUG) {
+ Slog.d(TAG, "Updating system routing session info : " + newSessionInfo);
+ }
mSessionInfos.clear();
mSessionInfos.add(newSessionInfo);
mDefaultSessionInfo = new RoutingSessionInfo.Builder(
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 38c65f1..9d56d81 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1936,6 +1936,9 @@
event.writeInt(channel.getImportance());
event.writeInt(channel.getUserLockedFields());
event.writeBoolean(channel.isDeleted());
+ event.writeBoolean(channel.getConversationId() != null);
+ event.writeBoolean(channel.isDemoted());
+ event.writeBoolean(channel.isImportantConversation());
events.add(event.build());
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3e587bf..d73d872 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13221,7 +13221,9 @@
private void enforceCanSetPackagesSuspendedAsUser(String callingPackage, int callingUid,
int userId, String callingMethod) {
- if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID) {
+ if (callingUid == Process.ROOT_UID
+ // Need to compare app-id to allow system dialogs access on secondary users
+ || UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
return;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 7d49f78..163504c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -124,6 +124,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.RoSystemProperties;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DumpUtils;
import com.android.internal.util.IntPair;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -421,6 +422,10 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
+ return;
+ }
+
mContext.getSystemService(PermissionControllerManager.class).dump(fd, args);
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 3336697..f075790 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -301,10 +301,7 @@
}
if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
String packageName = intent.getData().getSchemeSpecificPart();
- if (LOCAL_LOGV) {
- Slog.v(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED"
- + " pkg=" + packageName);
- }
+ Slog.i(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED pkg=" + packageName);
onPackageFullyRemoved(packageName);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0598680..b5b82d3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3589,7 +3589,7 @@
@Override
ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
- WindowContainer boundary) {
+ ActivityRecord boundary) {
return callback.test(this) ? this : null;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 2f868d9..9b9b613 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2708,7 +2708,9 @@
*/
@Nullable
private ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
- return getActivity((ar) -> ar.occludesParent(), true /* traverseTopToBottom */, activity);
+ ActivityRecord top = getActivity((ar) -> ar.occludesParent(),
+ true /* traverseTopToBottom */, activity);
+ return top != activity ? top : null;
}
boolean willActivityBeVisible(IBinder token) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index dfa3fe0..c28d47c 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -19,7 +19,6 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
@@ -193,9 +192,7 @@
final ActivityStack homeStack;
try {
// Make sure home stack exists on display area.
- // TODO(b/153624902): Replace with TaskDisplayArea#getOrCreateRootHomeTask()
- homeStack = taskDisplayArea.getOrCreateStack(WINDOWING_MODE_UNDEFINED,
- ACTIVITY_TYPE_HOME, ON_TOP);
+ homeStack = taskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
} finally {
mSupervisor.endDeferResume();
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 78e4237..fdbb2b2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3319,7 +3319,7 @@
}
@Override
- public void resizeTask(int taskId, Rect bounds, int resizeMode) {
+ public boolean resizeTask(int taskId, Rect bounds, int resizeMode) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
long ident = Binder.clearCallingIdentity();
try {
@@ -3328,10 +3328,11 @@
MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
- return;
+ return false;
}
if (!task.getWindowConfiguration().canResizeTask()) {
- throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
+ Slog.w(TAG, "resizeTask not allowed on task=" + task);
+ return false;
}
// Reparent the task to the right stack if necessary
@@ -3339,7 +3340,7 @@
// After reparenting (which only resizes the task to the stack bounds), resize the
// task to the actual bounds provided
- task.resize(bounds, resizeMode, preserveWindow);
+ return task.resize(bounds, resizeMode, preserveWindow);
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0b2bd81..85c439c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4700,9 +4700,11 @@
boolean supportsSystemDecorations() {
return (mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this)
|| (mDisplay.getFlags() & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0
- || (mWmService.mForceDesktopModeOnExternalDisplays && !isUntrustedVirtualDisplay()))
+ || mWmService.mForceDesktopModeOnExternalDisplays)
// VR virtual display will be used to run and render 2D app within a VR experience.
- && mDisplayId != mWmService.mVr2dDisplayId;
+ && mDisplayId != mWmService.mVr2dDisplayId
+ // Do not show system decorations on untrusted virtual display.
+ && !isUntrustedVirtualDisplay();
}
/**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 888a6e9..0ecde72 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1369,7 +1369,7 @@
calculateDefaultMinimalSizeOfResizeableTasks();
final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea();
- defaultTaskDisplayArea.getOrCreateRootHomeTask();
+ defaultTaskDisplayArea.getOrCreateRootHomeTask(ON_TOP);
positionChildAt(POSITION_TOP, defaultTaskDisplayArea.mDisplayContent,
false /* includingParents */);
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 37a4c1f..6ce36f1 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1461,16 +1461,23 @@
return mChildren.get(index);
}
+ @Nullable
+ ActivityStack getOrCreateRootHomeTask() {
+ return getOrCreateRootHomeTask(false /* onTop */);
+ }
+
/**
* Returns the existing home stack or creates and returns a new one if it should exist for the
* display.
+ * @param onTop Only be used when there is no existing home stack. If true the home stack will
+ * be created at the top of the display, else at the bottom.
*/
@Nullable
- ActivityStack getOrCreateRootHomeTask() {
+ ActivityStack getOrCreateRootHomeTask(boolean onTop) {
ActivityStack homeTask = getRootHomeTask();
if (homeTask == null && mDisplayContent.supportsSystemDecorations()
&& !mDisplayContent.isUntrustedVirtualDisplay()) {
- homeTask = createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, false /* onTop */);
+ homeTask = createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, onTop);
}
return homeTask;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 7bfddd7..e2023ae 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1415,11 +1415,12 @@
}
ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom,
- WindowContainer boundary) {
+ ActivityRecord boundary) {
if (traverseTopToBottom) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
- if (wc == boundary) return null;
+ // TODO(b/156986561): Improve the correctness of the boundary check.
+ if (wc == boundary) return boundary;
final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary);
if (r != null) {
@@ -1430,7 +1431,8 @@
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
final WindowContainer wc = mChildren.get(i);
- if (wc == boundary) return null;
+ // TODO(b/156986561): Improve the correctness of the boundary check.
+ if (wc == boundary) return boundary;
final ActivityRecord r = wc.getActivity(callback, traverseTopToBottom, boundary);
if (r != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index e5ec1f7..96a44a4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -16,14 +16,23 @@
package com.android.server.am;
+import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+
import static com.android.server.am.ActivityManagerService.Injector;
import static com.android.server.am.CachedAppOptimizer.compactActionIntToString;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.MessageQueue;
import android.os.Process;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
@@ -31,9 +40,11 @@
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.appop.AppOpsService;
import com.android.server.testables.TestableDeviceConfig;
+import com.android.server.wm.ActivityTaskManagerService;
import org.junit.After;
import org.junit.Assume;
@@ -45,6 +56,7 @@
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
+import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -68,25 +80,36 @@
private HandlerThread mHandlerThread;
private Handler mHandler;
private CountDownLatch mCountDown;
+ private ActivityManagerService mAms;
+ private Context mContext;
+ private TestInjector mInjector;
+ private TestProcessDependencies mProcessDependencies;
+
+ @Mock
+ private PackageManagerInternal mPackageManagerInt;
@Rule
- public TestableDeviceConfig.TestableDeviceConfigRule
+ public final TestableDeviceConfig.TestableDeviceConfigRule
mDeviceConfigRule = new TestableDeviceConfig.TestableDeviceConfigRule();
+ @Rule
+ public final ApplicationExitInfoTest.ServiceThreadRule
+ mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule();
@Before
public void setUp() {
mHandlerThread = new HandlerThread("");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
-
mThread = new ServiceThread("TestServiceThread", Process.THREAD_PRIORITY_DEFAULT,
true /* allowIo */);
mThread.start();
-
- ActivityManagerService ams = new ActivityManagerService(
- new TestInjector(InstrumentationRegistry.getInstrumentation().getContext()),
- mThread);
- mCachedAppOptimizerUnderTest = new CachedAppOptimizer(ams,
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ mInjector = new TestInjector(mContext);
+ mAms = new ActivityManagerService(
+ new TestInjector(mContext), mServiceThreadRule.getThread());
+ doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+ mProcessDependencies = new TestProcessDependencies();
+ mCachedAppOptimizerUnderTest = new CachedAppOptimizer(mAms,
new CachedAppOptimizer.PropertyChangedCallbackForTest() {
@Override
public void onPropertyChanged() {
@@ -94,7 +117,9 @@
mCountDown.countDown();
}
}
- });
+ }, mProcessDependencies);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
}
@After
@@ -104,6 +129,19 @@
mCountDown = null;
}
+ private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, String processName,
+ String packageName) {
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = packageName;
+ ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid);
+ app.pid = pid;
+ app.info.uid = packageUid;
+ // Exact value does not mater, it can be any state for which compaction is allowed.
+ app.setProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ app.setAdj = 905;
+ return app;
+ }
+
@Test
public void init_setsDefaults() {
mCachedAppOptimizerUnderTest.init();
@@ -197,7 +235,7 @@
CachedAppOptimizer.DEFAULT_USE_FREEZER);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_USE_FREEZER, CachedAppOptimizer.DEFAULT_USE_FREEZER
- ? "false" : "true" , false);
+ ? "false" : "true", false);
// Then calling init will read and set that flag.
mCachedAppOptimizerUnderTest.init();
@@ -790,6 +828,174 @@
.containsExactlyElementsIn(expected);
}
+ @Test
+ public void processWithDeltaRSSTooSmall_notFullCompacted() throws Exception {
+ // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS
+ // throttle to 12000.
+ mCachedAppOptimizerUnderTest.init();
+ setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
+ setFlag(CachedAppOptimizer.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "12000", false);
+ initActivityManagerService();
+
+ // Simulate RSS anon memory larger than throttle.
+ long[] rssBefore1 =
+ new long[]{/*totalRSS*/ 10000, /*fileRSS*/ 10000, /*anonRSS*/ 12000, /*swap*/
+ 10000};
+ long[] rssAfter1 =
+ new long[]{/*totalRSS*/ 9000, /*fileRSS*/ 9000, /*anonRSS*/ 11000, /*swap*/9000};
+ // Delta between rssAfter1 and rssBefore2 is below threshold (500).
+ long[] rssBefore2 =
+ new long[]{/*totalRSS*/ 9500, /*fileRSS*/ 9500, /*anonRSS*/ 11500, /*swap*/9500};
+ long[] rssAfter2 =
+ new long[]{/*totalRSS*/ 8000, /*fileRSS*/ 8000, /*anonRSS*/ 9000, /*swap*/8000};
+ // Delta between rssAfter1 and rssBefore3 is above threshold (13000).
+ long[] rssBefore3 =
+ new long[]{/*totalRSS*/ 10000, /*fileRSS*/ 18000, /*anonRSS*/ 13000, /*swap*/ 7000};
+ long[] rssAfter3 =
+ new long[]{/*totalRSS*/ 10000, /*fileRSS*/ 11000, /*anonRSS*/ 10000, /*swap*/ 6000};
+ long[] valuesAfter = {};
+ // Process that passes properties.
+ int pid = 1;
+ ProcessRecord processRecord = makeProcessRecord(pid, 2, 3, "p1", "app1");
+
+ // GIVEN we simulate RSS memory before above thresholds and it is the first time 'p1' is
+ // compacted.
+ mProcessDependencies.setRss(rssBefore1);
+ mProcessDependencies.setRssAfterCompaction(rssAfter1); //
+ // WHEN we try to run compaction
+ mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
+ waitForHandler();
+ // THEN process IS compacted.
+ assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
+ valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
+ pid).getRssAfterCompaction();
+ assertThat(valuesAfter).isEqualTo(rssAfter1);
+
+ // WHEN delta is below threshold (500).
+ mProcessDependencies.setRss(rssBefore2);
+ mProcessDependencies.setRssAfterCompaction(rssAfter2);
+ // This is to avoid throttle of compacting too soon.
+ processRecord.lastCompactTime = processRecord.lastCompactTime - 10_000;
+ // WHEN we try to run compaction.
+ mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
+ waitForHandler();
+ // THEN process IS NOT compacted - values after compaction for process 1 should remain the
+ // same as from the last compaction.
+ assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
+ valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
+ pid).getRssAfterCompaction();
+ assertThat(valuesAfter).isEqualTo(rssAfter1);
+
+ // WHEN delta is above threshold (13000).
+ mProcessDependencies.setRss(rssBefore3);
+ mProcessDependencies.setRssAfterCompaction(rssAfter3);
+ // This is to avoid throttle of compacting too soon.
+ processRecord.lastCompactTime = processRecord.lastCompactTime - 10_000;
+ // WHEN we try to run compaction
+ mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
+ waitForHandler();
+ // THEN process IS compacted - values after compaction for process 1 should be updated.
+ assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
+ valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
+ pid).getRssAfterCompaction();
+ assertThat(valuesAfter).isEqualTo(rssAfter3);
+
+ }
+
+ @Test
+ public void processWithAnonRSSTooSmall_notFullCompacted() throws Exception {
+ // Initialize CachedAppOptimizer and set flags to (1) enable compaction, (2) set RSS
+ // throttle to 8000.
+ mCachedAppOptimizerUnderTest.init();
+ setFlag(CachedAppOptimizer.KEY_USE_COMPACTION, "true", true);
+ setFlag(CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "8000", false);
+ initActivityManagerService();
+
+ // Simulate RSS anon memory larger than throttle.
+ long[] rssBelowThreshold =
+ new long[]{/*Total RSS*/ 10000, /*File RSS*/ 10000, /*Anon RSS*/ 7000, /*Swap*/
+ 10000};
+ long[] rssBelowThresholdAfter =
+ new long[]{/*Total RSS*/ 9000, /*File RSS*/ 7000, /*Anon RSS*/ 4000, /*Swap*/
+ 8000};
+ long[] rssAboveThreshold =
+ new long[]{/*Total RSS*/ 10000, /*File RSS*/ 10000, /*Anon RSS*/ 9000, /*Swap*/
+ 10000};
+ long[] rssAboveThresholdAfter =
+ new long[]{/*Total RSS*/ 8000, /*File RSS*/ 9000, /*Anon RSS*/ 6000, /*Swap*/5000};
+ // Process that passes properties.
+ int pid = 1;
+ ProcessRecord processRecord =
+ makeProcessRecord(pid, 2, 3, "p1",
+ "app1");
+
+ // GIVEN we simulate RSS memory before below threshold.
+ mProcessDependencies.setRss(rssBelowThreshold);
+ mProcessDependencies.setRssAfterCompaction(rssBelowThresholdAfter);
+ // WHEN we try to run compaction
+ mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
+ waitForHandler();
+ // THEN process IS NOT compacted.
+ assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNull();
+
+ // GIVEN we simulate RSS memory before above threshold.
+ mProcessDependencies.setRss(rssAboveThreshold);
+ mProcessDependencies.setRssAfterCompaction(rssAboveThresholdAfter);
+ // WHEN we try to run compaction
+ mCachedAppOptimizerUnderTest.compactAppFull(processRecord);
+ waitForHandler();
+ // THEN process IS compacted.
+ assertThat(mCachedAppOptimizerUnderTest.mLastCompactionStats.get(pid)).isNotNull();
+ long[] valuesAfter = mCachedAppOptimizerUnderTest.mLastCompactionStats.get(
+ pid).getRssAfterCompaction();
+ assertThat(valuesAfter).isEqualTo(rssAboveThresholdAfter);
+ }
+
+
+ private void setFlag(String key, String value, boolean defaultValue) throws Exception {
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, key, value, defaultValue);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ }
+
+ private void waitForHandler() {
+ Idle idle = new Idle();
+ mCachedAppOptimizerUnderTest.mCompactionHandler.getLooper().getQueue().addIdleHandler(idle);
+ mCachedAppOptimizerUnderTest.mCompactionHandler.post(() -> { });
+ idle.waitForIdle();
+ }
+
+ private void initActivityManagerService() {
+ mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread());
+ mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+ mAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
+ mAms.mAtmInternal = spy(mAms.mActivityTaskManager.getAtmInternal());
+ mAms.mPackageManagerInt = mPackageManagerInt;
+ }
+
+ private static final class Idle implements MessageQueue.IdleHandler {
+ private boolean mIdle;
+
+ @Override
+ public boolean queueIdle() {
+ synchronized (this) {
+ mIdle = true;
+ notifyAll();
+ }
+ return false;
+ }
+
+ public synchronized void waitForIdle() {
+ while (!mIdle) {
+ try {
+ // Wait with a timeout of 10s.
+ wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
private class TestInjector extends Injector {
TestInjector(Context context) {
@@ -806,4 +1012,29 @@
return mHandler;
}
}
+
+ // Test implementation for ProcessDependencies.
+ private static final class TestProcessDependencies
+ implements CachedAppOptimizer.ProcessDependencies {
+ private long[] mRss;
+ private long[] mRssAfterCompaction;
+
+ @Override
+ public long[] getRss(int pid) {
+ return mRss;
+ }
+
+ @Override
+ public void performCompaction(String action, int pid) throws IOException {
+ mRss = mRssAfterCompaction;
+ }
+
+ public void setRss(long[] newValues) {
+ mRss = newValues;
+ }
+
+ public void setRssAfterCompaction(long[] newValues) {
+ mRssAfterCompaction = newValues;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index efa25bd..320dacf 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -1582,6 +1582,41 @@
"s2");
}
+ public void testCachedShortcuts_canPassShortcutLimit() {
+ // Change the max number of shortcuts.
+ mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=4");
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"),
+ makeLongLivedShortcut("s4"))));
+ });
+
+ // Cache All
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
+ HANDLE_USER_0);
+ });
+
+ setCaller(CALLING_PACKAGE_1);
+
+ // Get dynamic shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
+ "s1", "s2", "s3", "s4");
+ // Get cached shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s1", "s2", "s3", "s4");
+
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("sx1", "sx2", "sx3", "sx4")));
+
+ // Get dynamic shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_DYNAMIC),
+ "sx1", "sx2", "sx3", "sx4");
+ // Get cached shortcuts
+ assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED),
+ "s1", "s2", "s3", "s4");
+ }
+
// === Test for launcher side APIs ===
public void testGetShortcuts() {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index f4e5d56..078c21e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -81,6 +81,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
+import android.util.StatsEvent;
import android.util.Xml;
import androidx.test.InstrumentationRegistry;
@@ -89,6 +90,7 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
+
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
@@ -2996,6 +2998,31 @@
PKG_O, UID_O, parent.getId(), conversationId, false, false), conversationId);
}
+
+ @Test
+ public void testPullConversationNotificationChannel() {
+ String conversationId = "friend";
+
+ NotificationChannel parent =
+ new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+
+ String channelId = String.format(
+ CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId);
+ NotificationChannel friend = new NotificationChannel(channelId,
+ "messages", IMPORTANCE_DEFAULT);
+ friend.setConversationId(parent.getId(), conversationId);
+ mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
+ ArrayList<StatsEvent> events = new ArrayList<>();
+ mHelper.pullPackageChannelPreferencesStats(events);
+ boolean found = false;
+ for (StatsEvent event : events) {
+ // TODO(b/153195691): inspect the content once it is possible to do so
+ found = true;
+ }
+ assertTrue("conversation was not in the pull", found);
+ }
+
@Test
public void testGetNotificationChannel_conversationProvidedByNotCustomizedYet() {
String conversationId = "friend";
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index bb6f154..b35b323 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -536,13 +536,16 @@
// Assign permission to special system apps
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- PHONE_PACKAGE_NAME);
+ PHONE_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- BLUETOOTH_PACKAGE_NAME);
+ BLUETOOTH_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- MMS_SERVICE_PACKAGE_NAME);
+ MMS_SERVICE_PACKAGE_NAME, true);
assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
- TELEPHONY_PROVIDER_PACKAGE_NAME);
+ TELEPHONY_PROVIDER_PACKAGE_NAME, true);
+ // CellbroadcastReceiver is a mainline module thus skip signature match.
+ assignExclusiveSmsPermissionsToSystemApp(context, packageManager, appOps,
+ CellBroadcastUtils.getDefaultCellBroadcastReceiverPackageName(context), false);
// Give AppOps permission to UID 1001 which contains multiple
// apps, all of them should be able to write to telephony provider.
@@ -744,17 +747,23 @@
* @param packageManager The package manager instance
* @param appOps The AppOps manager instance
* @param packageName The package name of the system app
+ * @param sigatureMatch whether to check signature match
*/
private static void assignExclusiveSmsPermissionsToSystemApp(Context context,
- PackageManager packageManager, AppOpsManager appOps, String packageName) {
+ PackageManager packageManager, AppOpsManager appOps, String packageName,
+ boolean sigatureMatch) {
// First check package signature matches the caller's package signature.
// Since this class is only used internally by the system, this check makes sure
// the package signature matches system signature.
- final int result = packageManager.checkSignatures(context.getPackageName(), packageName);
- if (result != PackageManager.SIGNATURE_MATCH) {
- Log.e(LOG_TAG, packageName + " does not have system signature");
- return;
+ if (sigatureMatch) {
+ final int result = packageManager.checkSignatures(context.getPackageName(),
+ packageName);
+ if (result != PackageManager.SIGNATURE_MATCH) {
+ Log.e(LOG_TAG, packageName + " does not have system signature");
+ return;
+ }
}
+
try {
PackageInfo info = packageManager.getPackageInfo(packageName, 0);
int mode = appOps.unsafeCheckOp(AppOpsManager.OPSTR_WRITE_SMS, info.applicationInfo.uid,