summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java4
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/Ledger.java241
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/Scribe.java111
-rw-r--r--apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java11
-rw-r--r--core/java/android/app/ActivityThread.java45
-rw-r--r--core/java/android/app/ClientTransactionHandler.java4
-rw-r--r--core/java/android/app/IApplicationThread.aidl5
-rw-r--r--core/java/android/app/servertransaction/LaunchActivityItem.java19
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java7
-rw-r--r--core/java/android/os/INetworkManagementService.aidl3
-rw-r--r--core/java/android/view/AttachedSurfaceControl.java5
-rw-r--r--core/java/android/view/inputmethod/InputMethodSubtype.java4
-rw-r--r--core/java/android/window/SurfaceSyncGroup.java6
-rw-r--r--core/java/com/android/internal/app/procstats/IProcessStats.aidl3
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java4
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TestUtils.java9
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java7
-rw-r--r--core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java4
-rw-r--r--keystore/java/android/security/keystore/KeyProtection.java35
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt9
-rw-r--r--media/java/android/media/MediaRouter2Manager.java118
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java11
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java88
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java125
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java109
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java294
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalControllerFactory.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileStatusTrackerFactory.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserCreator.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserCreator.kt81
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java19
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt73
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java6
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java7
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java2
-rw-r--r--services/core/java/com/android/server/am/ProcessStatsService.java9
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java34
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java2
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java23
-rw-r--r--services/core/java/com/android/server/pm/ApexPackageInfo.java205
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java70
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/ScanPackageUtils.java4
-rw-r--r--services/core/java/com/android/server/pm/UserSystemPackageInstaller.java45
-rw-r--r--services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java8
-rw-r--r--services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java4
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java2
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java8
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java1
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java87
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java68
-rw-r--r--services/tests/servicestests/src/com/android/server/tare/LedgerTest.java280
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java19
-rw-r--r--tests/Camera2Tests/CameraToo/Android.bp28
-rw-r--r--tests/Camera2Tests/CameraToo/Android.mk26
-rw-r--r--tests/backup/Android.bp54
-rw-r--r--tests/backup/Android.mk53
82 files changed, 2174 insertions, 979 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index d401373c0066..aeb6abc3ce1b 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -306,6 +306,10 @@ public abstract class EconomicPolicy {
return eventId & MASK_TYPE;
}
+ static boolean isReward(int eventId) {
+ return getEventType(eventId) == TYPE_REWARD;
+ }
+
@NonNull
static String eventToString(int eventId) {
switch (eventId & MASK_TYPE) {
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
index 2e2a9b56d3df..e91ed1287e1b 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Ledger.java
@@ -17,15 +17,19 @@
package com.android.server.tare;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.util.TimeUtils.dumpTime;
import static com.android.server.tare.TareUtils.cakeToString;
-import static com.android.server.tare.TareUtils.dumpTime;
import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.IndentingPrintWriter;
import android.util.SparseLongArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
@@ -34,6 +38,21 @@ import java.util.List;
* Ledger to track the last recorded balance and recent activities of an app.
*/
class Ledger {
+ /** The window size within which rewards will be counted and used towards reward limiting. */
+ private static final long TOTAL_REWARD_WINDOW_MS = 24 * HOUR_IN_MILLIS;
+ /** The number of buckets to split {@link #TOTAL_REWARD_WINDOW_MS} into. */
+ @VisibleForTesting
+ static final int NUM_REWARD_BUCKET_WINDOWS = 4;
+ /**
+ * The duration size of each bucket resulting from splitting {@link #TOTAL_REWARD_WINDOW_MS}
+ * into smaller buckets.
+ */
+ private static final long REWARD_BUCKET_WINDOW_SIZE_MS =
+ TOTAL_REWARD_WINDOW_MS / NUM_REWARD_BUCKET_WINDOWS;
+ /** The maximum number of transactions to retain in memory at any one time. */
+ @VisibleForTesting
+ static final int MAX_TRANSACTION_COUNT = 50;
+
static class Transaction {
public final long startTimeMs;
public final long endTimeMs;
@@ -54,18 +73,47 @@ class Ledger {
}
}
+ static class RewardBucket {
+ @CurrentTimeMillisLong
+ public long startTimeMs;
+ public final SparseLongArray cumulativeDelta = new SparseLongArray();
+
+ private void reset() {
+ startTimeMs = 0;
+ cumulativeDelta.clear();
+ }
+ }
+
/** Last saved balance. This doesn't take currently ongoing events into account. */
private long mCurrentBalance = 0;
- private final List<Transaction> mTransactions = new ArrayList<>();
- private final SparseLongArray mCumulativeDeltaPerReason = new SparseLongArray();
- private long mEarliestSumTime;
+ private final Transaction[] mTransactions = new Transaction[MAX_TRANSACTION_COUNT];
+ /** Index within {@link #mTransactions} where the next transaction should be placed. */
+ private int mTransactionIndex = 0;
+ private final RewardBucket[] mRewardBuckets = new RewardBucket[NUM_REWARD_BUCKET_WINDOWS];
+ /** Index within {@link #mRewardBuckets} of the current active bucket. */
+ private int mRewardBucketIndex = 0;
Ledger() {
}
- Ledger(long currentBalance, @NonNull List<Transaction> transactions) {
+ Ledger(long currentBalance, @NonNull List<Transaction> transactions,
+ @NonNull List<RewardBucket> rewardBuckets) {
mCurrentBalance = currentBalance;
- mTransactions.addAll(transactions);
+
+ final int numTxs = transactions.size();
+ for (int i = Math.max(0, numTxs - MAX_TRANSACTION_COUNT); i < numTxs; ++i) {
+ mTransactions[mTransactionIndex++] = transactions.get(i);
+ }
+ mTransactionIndex %= MAX_TRANSACTION_COUNT;
+
+ final int numBuckets = rewardBuckets.size();
+ if (numBuckets > 0) {
+ // Set the index to -1 so that we put the first bucket in index 0.
+ mRewardBucketIndex = -1;
+ for (int i = Math.max(0, numBuckets - NUM_REWARD_BUCKET_WINDOWS); i < numBuckets; ++i) {
+ mRewardBuckets[++mRewardBucketIndex] = rewardBuckets.get(i);
+ }
+ }
}
long getCurrentBalance() {
@@ -74,66 +122,142 @@ class Ledger {
@Nullable
Transaction getEarliestTransaction() {
- if (mTransactions.size() > 0) {
- return mTransactions.get(0);
+ for (int t = 0; t < mTransactions.length; ++t) {
+ final Transaction transaction =
+ mTransactions[(mTransactionIndex + t) % mTransactions.length];
+ if (transaction != null) {
+ return transaction;
+ }
}
return null;
}
@NonNull
+ List<RewardBucket> getRewardBuckets() {
+ final long cutoffMs = getCurrentTimeMillis() - TOTAL_REWARD_WINDOW_MS;
+ final List<RewardBucket> list = new ArrayList<>(NUM_REWARD_BUCKET_WINDOWS);
+ for (int i = 1; i <= NUM_REWARD_BUCKET_WINDOWS; ++i) {
+ final int idx = (mRewardBucketIndex + i) % NUM_REWARD_BUCKET_WINDOWS;
+ final RewardBucket rewardBucket = mRewardBuckets[idx];
+ if (rewardBucket != null) {
+ if (cutoffMs <= rewardBucket.startTimeMs) {
+ list.add(rewardBucket);
+ } else {
+ rewardBucket.reset();
+ }
+ }
+ }
+ return list;
+ }
+
+ @NonNull
List<Transaction> getTransactions() {
- return mTransactions;
+ final List<Transaction> list = new ArrayList<>(MAX_TRANSACTION_COUNT);
+ for (int i = 0; i < MAX_TRANSACTION_COUNT; ++i) {
+ final int idx = (mTransactionIndex + i) % MAX_TRANSACTION_COUNT;
+ final Transaction transaction = mTransactions[idx];
+ if (transaction != null) {
+ list.add(transaction);
+ }
+ }
+ return list;
}
void recordTransaction(@NonNull Transaction transaction) {
- mTransactions.add(transaction);
+ mTransactions[mTransactionIndex] = transaction;
mCurrentBalance += transaction.delta;
+ mTransactionIndex = (mTransactionIndex + 1) % MAX_TRANSACTION_COUNT;
- final long sum = mCumulativeDeltaPerReason.get(transaction.eventId);
- mCumulativeDeltaPerReason.put(transaction.eventId, sum + transaction.delta);
- mEarliestSumTime = Math.min(mEarliestSumTime, transaction.startTimeMs);
+ if (EconomicPolicy.isReward(transaction.eventId)) {
+ final RewardBucket bucket = getCurrentRewardBucket();
+ bucket.cumulativeDelta.put(transaction.eventId,
+ bucket.cumulativeDelta.get(transaction.eventId, 0) + transaction.delta);
+ }
+ }
+
+ @NonNull
+ private RewardBucket getCurrentRewardBucket() {
+ RewardBucket bucket = mRewardBuckets[mRewardBucketIndex];
+ final long now = getCurrentTimeMillis();
+ if (bucket == null) {
+ bucket = new RewardBucket();
+ bucket.startTimeMs = now;
+ mRewardBuckets[mRewardBucketIndex] = bucket;
+ return bucket;
+ }
+
+ if (now - bucket.startTimeMs < REWARD_BUCKET_WINDOW_SIZE_MS) {
+ return bucket;
+ }
+
+ mRewardBucketIndex = (mRewardBucketIndex + 1) % NUM_REWARD_BUCKET_WINDOWS;
+ bucket = mRewardBuckets[mRewardBucketIndex];
+ if (bucket == null) {
+ bucket = new RewardBucket();
+ mRewardBuckets[mRewardBucketIndex] = bucket;
+ }
+ bucket.reset();
+ // Using now as the start time means there will be some gaps between sequential buckets,
+ // but makes processing of large gaps between events easier.
+ bucket.startTimeMs = now;
+ return bucket;
}
long get24HourSum(int eventId, final long now) {
final long windowStartTime = now - 24 * HOUR_IN_MILLIS;
- if (mEarliestSumTime < windowStartTime) {
- // Need to redo sums
- mCumulativeDeltaPerReason.clear();
- for (int i = mTransactions.size() - 1; i >= 0; --i) {
- final Transaction transaction = mTransactions.get(i);
- if (transaction.endTimeMs <= windowStartTime) {
- break;
- }
- long sum = mCumulativeDeltaPerReason.get(transaction.eventId);
- if (transaction.startTimeMs >= windowStartTime) {
- sum += transaction.delta;
- } else {
- // Pro-rate durationed deltas. Intentionally floor the result.
- sum += (long) (1.0 * (transaction.endTimeMs - windowStartTime)
- * transaction.delta)
- / (transaction.endTimeMs - transaction.startTimeMs);
- }
- mCumulativeDeltaPerReason.put(transaction.eventId, sum);
+ long sum = 0;
+ for (int i = 0; i < mRewardBuckets.length; ++i) {
+ final RewardBucket bucket = mRewardBuckets[i];
+ if (bucket != null
+ && bucket.startTimeMs >= windowStartTime && bucket.startTimeMs < now) {
+ sum += bucket.cumulativeDelta.get(eventId, 0);
}
- mEarliestSumTime = windowStartTime;
}
- return mCumulativeDeltaPerReason.get(eventId);
+ return sum;
}
- /** Deletes transactions that are older than {@code minAgeMs}. */
- void removeOldTransactions(long minAgeMs) {
+ /**
+ * Deletes transactions that are older than {@code minAgeMs}.
+ * @return The earliest transaction in the ledger, or {@code null} if there are no more
+ * transactions.
+ */
+ @Nullable
+ Transaction removeOldTransactions(long minAgeMs) {
final long cutoff = getCurrentTimeMillis() - minAgeMs;
- while (mTransactions.size() > 0 && mTransactions.get(0).endTimeMs <= cutoff) {
- mTransactions.remove(0);
+ for (int t = 0; t < mTransactions.length; ++t) {
+ final int idx = (mTransactionIndex + t) % mTransactions.length;
+ final Transaction transaction = mTransactions[idx];
+ if (transaction == null) {
+ continue;
+ }
+ if (transaction.endTimeMs <= cutoff) {
+ mTransactions[idx] = null;
+ } else {
+ // Everything we look at after this transaction will also be within the window,
+ // so no need to go further.
+ return transaction;
+ }
}
+ return null;
}
void dump(IndentingPrintWriter pw, int numRecentTransactions) {
pw.print("Current balance", cakeToString(getCurrentBalance())).println();
+ pw.println();
- final int size = mTransactions.size();
- for (int i = Math.max(0, size - numRecentTransactions); i < size; ++i) {
- final Transaction transaction = mTransactions.get(i);
+ boolean printedTransactionTitle = false;
+ for (int t = 0; t < Math.min(MAX_TRANSACTION_COUNT, numRecentTransactions); ++t) {
+ final int idx = (mTransactionIndex - t + MAX_TRANSACTION_COUNT) % MAX_TRANSACTION_COUNT;
+ final Transaction transaction = mTransactions[idx];
+ if (transaction == null) {
+ continue;
+ }
+
+ if (!printedTransactionTitle) {
+ pw.println("Transactions:");
+ pw.increaseIndent();
+ printedTransactionTitle = true;
+ }
dumpTime(pw, transaction.startTimeMs);
pw.print("--");
@@ -151,5 +275,42 @@ class Ledger {
pw.print(cakeToString(transaction.ctp));
pw.println(")");
}
+ if (printedTransactionTitle) {
+ pw.decreaseIndent();
+ pw.println();
+ }
+
+ final long now = getCurrentTimeMillis();
+ boolean printedBucketTitle = false;
+ for (int b = 0; b < NUM_REWARD_BUCKET_WINDOWS; ++b) {
+ final int idx = (mRewardBucketIndex - b + NUM_REWARD_BUCKET_WINDOWS)
+ % NUM_REWARD_BUCKET_WINDOWS;
+ final RewardBucket rewardBucket = mRewardBuckets[idx];
+ if (rewardBucket == null) {
+ continue;
+ }
+
+ if (!printedBucketTitle) {
+ pw.println("Reward buckets:");
+ pw.increaseIndent();
+ printedBucketTitle = true;
+ }
+
+ dumpTime(pw, rewardBucket.startTimeMs);
+ pw.print(" (");
+ TimeUtils.formatDuration(now - rewardBucket.startTimeMs, pw);
+ pw.println(" ago):");
+ pw.increaseIndent();
+ for (int r = 0; r < rewardBucket.cumulativeDelta.size(); ++r) {
+ pw.print(EconomicPolicy.eventToString(rewardBucket.cumulativeDelta.keyAt(r)));
+ pw.print(": ");
+ pw.println(cakeToString(rewardBucket.cumulativeDelta.valueAt(r)));
+ }
+ pw.decreaseIndent();
+ }
+ if (printedBucketTitle) {
+ pw.decreaseIndent();
+ pw.println();
+ }
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index 941cc39f2d97..8f7657e6c414 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -62,15 +62,14 @@ public class Scribe {
private static final int MAX_NUM_TRANSACTION_DUMP = 25;
/**
* The maximum amount of time we'll keep a transaction around for.
- * For now, only keep transactions we actually have a use for. We can increase it if we want
- * to use older transactions or provide older transactions to apps.
*/
- private static final long MAX_TRANSACTION_AGE_MS = 24 * HOUR_IN_MILLIS;
+ private static final long MAX_TRANSACTION_AGE_MS = 8 * 24 * HOUR_IN_MILLIS;
private static final String XML_TAG_HIGH_LEVEL_STATE = "irs-state";
private static final String XML_TAG_LEDGER = "ledger";
private static final String XML_TAG_TARE = "tare";
private static final String XML_TAG_TRANSACTION = "transaction";
+ private static final String XML_TAG_REWARD_BUCKET = "rewardBucket";
private static final String XML_TAG_USER = "user";
private static final String XML_TAG_PERIOD_REPORT = "report";
@@ -346,8 +345,8 @@ public class Scribe {
for (int pIdx = mLedgers.numElementsForKey(userId) - 1; pIdx >= 0; --pIdx) {
final String pkgName = mLedgers.keyAt(uIdx, pIdx);
final Ledger ledger = mLedgers.get(userId, pkgName);
- ledger.removeOldTransactions(MAX_TRANSACTION_AGE_MS);
- Ledger.Transaction transaction = ledger.getEarliestTransaction();
+ final Ledger.Transaction transaction =
+ ledger.removeOldTransactions(MAX_TRANSACTION_AGE_MS);
if (transaction != null) {
earliestEndTime = Math.min(earliestEndTime, transaction.endTimeMs);
}
@@ -370,6 +369,7 @@ public class Scribe {
final String pkgName;
final long curBalance;
final List<Ledger.Transaction> transactions = new ArrayList<>();
+ final List<Ledger.RewardBucket> rewardBuckets = new ArrayList<>();
pkgName = parser.getAttributeValue(null, XML_ATTR_PACKAGE_NAME);
curBalance = parser.getAttributeLong(null, XML_ATTR_CURRENT_BALANCE);
@@ -391,8 +391,7 @@ public class Scribe {
}
continue;
}
- if (eventType != XmlPullParser.START_TAG || !XML_TAG_TRANSACTION.equals(tagName)) {
- // Expecting only "transaction" tags.
+ if (eventType != XmlPullParser.START_TAG || tagName == null) {
Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
return null;
}
@@ -402,25 +401,37 @@ public class Scribe {
if (DEBUG) {
Slog.d(TAG, "Starting ledger tag: " + tagName);
}
- final String tag = parser.getAttributeValue(null, XML_ATTR_TAG);
- final long startTime = parser.getAttributeLong(null, XML_ATTR_START_TIME);
- final long endTime = parser.getAttributeLong(null, XML_ATTR_END_TIME);
- final int eventId = parser.getAttributeInt(null, XML_ATTR_EVENT_ID);
- final long delta = parser.getAttributeLong(null, XML_ATTR_DELTA);
- final long ctp = parser.getAttributeLong(null, XML_ATTR_CTP);
- if (endTime <= endTimeCutoff) {
- if (DEBUG) {
- Slog.d(TAG, "Skipping event because it's too old.");
- }
- continue;
+ switch (tagName) {
+ case XML_TAG_TRANSACTION:
+ final long endTime = parser.getAttributeLong(null, XML_ATTR_END_TIME);
+ if (endTime <= endTimeCutoff) {
+ if (DEBUG) {
+ Slog.d(TAG, "Skipping event because it's too old.");
+ }
+ continue;
+ }
+ final String tag = parser.getAttributeValue(null, XML_ATTR_TAG);
+ final long startTime = parser.getAttributeLong(null, XML_ATTR_START_TIME);
+ final int eventId = parser.getAttributeInt(null, XML_ATTR_EVENT_ID);
+ final long delta = parser.getAttributeLong(null, XML_ATTR_DELTA);
+ final long ctp = parser.getAttributeLong(null, XML_ATTR_CTP);
+ transactions.add(
+ new Ledger.Transaction(startTime, endTime, eventId, tag, delta, ctp));
+ break;
+ case XML_TAG_REWARD_BUCKET:
+ rewardBuckets.add(readRewardBucketFromXml(parser));
+ break;
+ default:
+ // Expecting only "transaction" and "rewardBucket" tags.
+ Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
+ return null;
}
- transactions.add(new Ledger.Transaction(startTime, endTime, eventId, tag, delta, ctp));
}
if (!isInstalled) {
return null;
}
- return Pair.create(pkgName, new Ledger(curBalance, transactions));
+ return Pair.create(pkgName, new Ledger(curBalance, transactions, rewardBuckets));
}
/**
@@ -508,6 +519,44 @@ public class Scribe {
return report;
}
+ /**
+ * @param parser Xml parser at the beginning of a {@value #XML_TAG_REWARD_BUCKET} tag. The next
+ * "parser.next()" call will take the parser into the body of the tag.
+ * @return Newly instantiated {@link Ledger.RewardBucket} holding all the information we just
+ * read out of the xml tag.
+ */
+ @Nullable
+ private static Ledger.RewardBucket readRewardBucketFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException {
+
+ final Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
+
+ rewardBucket.startTimeMs = parser.getAttributeLong(null, XML_ATTR_START_TIME);
+
+ for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
+ eventType = parser.next()) {
+ final String tagName = parser.getName();
+ if (eventType == XmlPullParser.END_TAG) {
+ if (XML_TAG_REWARD_BUCKET.equals(tagName)) {
+ // We've reached the end of the rewardBucket tag.
+ break;
+ }
+ continue;
+ }
+ if (eventType != XmlPullParser.START_TAG || !XML_ATTR_DELTA.equals(tagName)) {
+ // Expecting only delta tags.
+ Slog.e(TAG, "Unexpected event: (" + eventType + ") " + tagName);
+ return null;
+ }
+
+ final int eventId = parser.getAttributeInt(null, XML_ATTR_EVENT_ID);
+ final long delta = parser.getAttributeLong(null, XML_ATTR_DELTA);
+ rewardBucket.cumulativeDelta.put(eventId, delta);
+ }
+
+ return rewardBucket;
+ }
+
private void scheduleCleanup(long earliestEndTime) {
if (earliestEndTime == Long.MAX_VALUE) {
return;
@@ -595,6 +644,11 @@ public class Scribe {
}
writeTransaction(out, transaction);
}
+
+ final List<Ledger.RewardBucket> rewardBuckets = ledger.getRewardBuckets();
+ for (int r = 0; r < rewardBuckets.size(); ++r) {
+ writeRewardBucket(out, rewardBuckets.get(r));
+ }
out.endTag(null, XML_TAG_LEDGER);
}
out.endTag(null, XML_TAG_USER);
@@ -616,6 +670,23 @@ public class Scribe {
out.endTag(null, XML_TAG_TRANSACTION);
}
+ private static void writeRewardBucket(@NonNull TypedXmlSerializer out,
+ @NonNull Ledger.RewardBucket rewardBucket) throws IOException {
+ final int numEvents = rewardBucket.cumulativeDelta.size();
+ if (numEvents == 0) {
+ return;
+ }
+ out.startTag(null, XML_TAG_REWARD_BUCKET);
+ out.attributeLong(null, XML_ATTR_START_TIME, rewardBucket.startTimeMs);
+ for (int i = 0; i < numEvents; ++i) {
+ out.startTag(null, XML_ATTR_DELTA);
+ out.attributeInt(null, XML_ATTR_EVENT_ID, rewardBucket.cumulativeDelta.keyAt(i));
+ out.attributeLong(null, XML_ATTR_DELTA, rewardBucket.cumulativeDelta.valueAt(i));
+ out.endTag(null, XML_ATTR_DELTA);
+ }
+ out.endTag(null, XML_TAG_REWARD_BUCKET);
+ }
+
private static void writeReport(@NonNull TypedXmlSerializer out,
@NonNull Analyst.Report report) throws IOException {
out.startTag(null, XML_TAG_PERIOD_REPORT);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
index 6b6984f6ac17..aa4c75a0be80 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java
@@ -19,26 +19,15 @@ package com.android.server.tare;
import static android.app.tare.EconomyManager.CAKE_IN_ARC;
import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.util.IndentingPrintWriter;
import com.android.internal.annotations.VisibleForTesting;
-import java.text.SimpleDateFormat;
import java.time.Clock;
class TareUtils {
- @SuppressLint("SimpleDateFormat")
- private static final SimpleDateFormat sDumpDateFormat =
- new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-
@VisibleForTesting
static Clock sSystemClock = Clock.systemUTC();
- static void dumpTime(IndentingPrintWriter pw, long time) {
- pw.print(sDumpDateFormat.format(time));
- }
-
static long getCurrentTimeMillis() {
return sSystemClock.millis();
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2a83cbddd3dc..b383d7daafd0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -374,6 +374,7 @@ public final class ActivityThread extends ClientTransactionHandler
int mCurDefaultDisplayDpi;
@UnsupportedAppUsage
boolean mDensityCompatMode;
+ private CompatibilityInfo mCompatibilityInfo;
@UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.")
Configuration mConfiguration;
@@ -612,7 +613,7 @@ public final class ActivityThread extends ClientTransactionHandler
}
public ActivityClientRecord(IBinder token, Intent intent, int ident,
- ActivityInfo info, Configuration overrideConfig, CompatibilityInfo compatInfo,
+ ActivityInfo info, Configuration overrideConfig,
String referrer, IVoiceInteractor voiceInteractor, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
@@ -627,7 +628,6 @@ public final class ActivityThread extends ClientTransactionHandler
this.referrer = referrer;
this.voiceInteractor = voiceInteractor;
this.activityInfo = info;
- this.compatInfo = compatInfo;
this.state = state;
this.persistentState = persistentState;
this.pendingResults = pendingResults;
@@ -635,8 +635,7 @@ public final class ActivityThread extends ClientTransactionHandler
this.isForward = isForward;
this.profilerInfo = profilerInfo;
this.overrideConfig = overrideConfig;
- this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo,
- compatInfo);
+ this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo);
mActivityOptions = activityOptions;
mLaunchedFromBubble = launchedFromBubble;
mInitialTaskFragmentToken = initialTaskFragmentToken;
@@ -804,7 +803,6 @@ public final class ActivityThread extends ClientTransactionHandler
static final class CreateBackupAgentData {
ApplicationInfo appInfo;
- CompatibilityInfo compatInfo;
int backupMode;
int userId;
int operationType;
@@ -1038,15 +1036,13 @@ public final class ActivityThread extends ClientTransactionHandler
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
r.info = info;
- r.compatInfo = compatInfo;
sendMessage(H.RECEIVER, r);
}
public final void scheduleCreateBackupAgent(ApplicationInfo app,
- CompatibilityInfo compatInfo, int backupMode, int userId, int operationType) {
+ int backupMode, int userId, int operationType) {
CreateBackupAgentData d = new CreateBackupAgentData();
d.appInfo = app;
- d.compatInfo = compatInfo;
d.backupMode = backupMode;
d.userId = userId;
d.operationType = operationType;
@@ -1054,11 +1050,9 @@ public final class ActivityThread extends ClientTransactionHandler
sendMessage(H.CREATE_BACKUP_AGENT, d);
}
- public final void scheduleDestroyBackupAgent(ApplicationInfo app,
- CompatibilityInfo compatInfo, int userId) {
+ public final void scheduleDestroyBackupAgent(ApplicationInfo app, int userId) {
CreateBackupAgentData d = new CreateBackupAgentData();
d.appInfo = app;
- d.compatInfo = compatInfo;
d.userId = userId;
sendMessage(H.DESTROY_BACKUP_AGENT, d);
@@ -1070,7 +1064,6 @@ public final class ActivityThread extends ClientTransactionHandler
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
- s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
@@ -2577,16 +2570,16 @@ public final class ActivityThread extends ClientTransactionHandler
registerPackage);
}
- @Override
@UnsupportedAppUsage
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
}
- private LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, CompatibilityInfo compatInfo,
- boolean isSdkSandbox) {
- return getPackageInfo(ai, compatInfo, null, false, true, false, isSdkSandbox);
+ @Override
+ public LoadedApk getPackageInfoNoCheck(ApplicationInfo ai) {
+ return getPackageInfo(ai, mCompatibilityInfo, null /* baseLoader */,
+ false /* securityViolation */, true /* includeCode */, false /* registerPackage */);
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -3538,7 +3531,7 @@ public final class ActivityThread extends ClientTransactionHandler
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
- r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
+ r.packageInfo = getPackageInfo(aInfo.applicationInfo, mCompatibilityInfo,
Context.CONTEXT_INCLUDE_CODE);
}
@@ -4279,8 +4272,7 @@ public final class ActivityThread extends ClientTransactionHandler
String component = data.intent.getComponent().getClassName();
- LoadedApk packageInfo = getPackageInfoNoCheck(
- data.info.applicationInfo, data.compatInfo);
+ final LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo);
IActivityManager mgr = ActivityManager.getService();
@@ -4366,7 +4358,7 @@ public final class ActivityThread extends ClientTransactionHandler
unscheduleGcIdler();
// instantiate the BackupAgent class named in the manifest
- LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
+ final LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo);
String packageName = packageInfo.mPackageName;
if (packageName == null) {
Slog.d(TAG, "Asked to create backup agent for nonexistent package");
@@ -4439,7 +4431,7 @@ public final class ActivityThread extends ClientTransactionHandler
private void handleDestroyBackupAgent(CreateBackupAgentData data) {
if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data);
- LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
+ final LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo);
String packageName = packageInfo.mPackageName;
ArrayMap<String, BackupAgent> backupAgents = getBackupAgentsForUser(data.userId);
BackupAgent agent = backupAgents.get(packageName);
@@ -4471,8 +4463,7 @@ public final class ActivityThread extends ClientTransactionHandler
// we are back active so skip it.
unscheduleGcIdler();
- LoadedApk packageInfo = getPackageInfoNoCheck(
- data.info.applicationInfo, data.compatInfo);
+ final LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
@@ -5306,6 +5297,7 @@ public final class ActivityThread extends ClientTransactionHandler
}
private void handleUpdatePackageCompatibilityInfo(UpdateCompatibilityData data) {
+ mCompatibilityInfo = data.info;
LoadedApk apk = peekPackageInfo(data.pkg, false);
if (apk != null) {
apk.setCompatibilityInfo(data.info);
@@ -6486,6 +6478,7 @@ public final class ActivityThread extends ClientTransactionHandler
mConfigurationController.setConfiguration(data.config);
mConfigurationController.setCompatConfiguration(data.config);
mConfiguration = mConfigurationController.getConfiguration();
+ mCompatibilityInfo = data.compatInfo;
mProfiler = new Profiler();
String agent = null;
@@ -6569,7 +6562,9 @@ public final class ActivityThread extends ClientTransactionHandler
}
final boolean isSdkSandbox = data.sdkSandboxClientAppPackage != null;
- data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo, isSdkSandbox);
+ data.info = getPackageInfo(data.appInfo, mCompatibilityInfo, null /* baseLoader */,
+ false /* securityViolation */, true /* includeCode */,
+ false /* registerPackage */, isSdkSandbox);
if (isSdkSandbox) {
data.info.setSdkSandboxStorage(data.sdkSandboxClientAppVolumeUuid,
data.sdkSandboxClientAppPackage);
@@ -6844,7 +6839,7 @@ public final class ActivityThread extends ClientTransactionHandler
private void handleInstrumentWithoutRestart(AppBindData data) {
try {
data.compatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
- data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
+ data.info = getPackageInfoNoCheck(data.appInfo);
mInstrumentingWithoutRestart = true;
final InstrumentationInfo ii = prepareInstrumentation(data);
final ContextImpl appContext =
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 65e6ab7a2137..389da2d094d5 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -23,7 +23,6 @@ import android.app.servertransaction.PendingTransactionActions;
import android.app.servertransaction.TransactionExecutor;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.IBinder;
import android.util.MergedConfiguration;
@@ -180,8 +179,7 @@ public abstract class ClientTransactionHandler {
PendingTransactionActions pendingActions, ActivityOptions activityOptions);
/** Get package info. */
- public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
- CompatibilityInfo compatInfo);
+ public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai);
/** Deliver app configuration change notification. */
public abstract void handleConfigurationChanged(Configuration config);
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 75ad363a2668..843b6846d053 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -102,10 +102,9 @@ oneway interface IApplicationThread {
void scheduleLowMemory();
void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType);
void setSchedulingGroup(int group);
- void scheduleCreateBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo,
+ void scheduleCreateBackupAgent(in ApplicationInfo app,
int backupMode, int userId, int operationType);
- void scheduleDestroyBackupAgent(in ApplicationInfo app,
- in CompatibilityInfo compatInfo, int userId);
+ void scheduleDestroyBackupAgent(in ApplicationInfo app, int userId);
void scheduleOnNewActivityOptions(IBinder token, in Bundle options);
void scheduleSuicide();
void dispatchPackageBroadcast(int cmd, in String[] packages);
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 076dbef9ebc4..03d6e27d6a8d 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -30,7 +30,6 @@ import android.app.ResultInfo;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.BaseBundle;
import android.os.Bundle;
@@ -58,7 +57,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
private ActivityInfo mInfo;
private Configuration mCurConfig;
private Configuration mOverrideConfig;
- private CompatibilityInfo mCompatInfo;
private String mReferrer;
private IVoiceInteractor mVoiceInteractor;
private int mProcState;
@@ -94,7 +92,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
- mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
+ mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
mTaskFragmentToken);
@@ -115,7 +113,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
/** Obtain an instance initialized with provided params. */
public static LaunchActivityItem obtain(Intent intent, int ident, ActivityInfo info,
- Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo,
+ Configuration curConfig, Configuration overrideConfig,
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
@@ -126,7 +124,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
if (instance == null) {
instance = new LaunchActivityItem();
}
- setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
+ setValues(instance, intent, ident, info, curConfig, overrideConfig, referrer,
voiceInteractor, procState, state, persistentState, pendingResults,
pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
activityClientController, shareableActivityToken,
@@ -137,7 +135,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
@Override
public void recycle() {
- setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
+ setValues(this, null, 0, null, null, null, null, null, 0, null, null, null, null,
null, false, null, null, null, null, false, null);
ObjectPool.recycle(this);
}
@@ -153,7 +151,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
dest.writeTypedObject(mInfo, flags);
dest.writeTypedObject(mCurConfig, flags);
dest.writeTypedObject(mOverrideConfig, flags);
- dest.writeTypedObject(mCompatInfo, flags);
dest.writeString(mReferrer);
dest.writeStrongInterface(mVoiceInteractor);
dest.writeInt(mProcState);
@@ -175,8 +172,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
private LaunchActivityItem(Parcel in) {
setValues(this, in.readTypedObject(Intent.CREATOR), in.readInt(),
in.readTypedObject(ActivityInfo.CREATOR), in.readTypedObject(Configuration.CREATOR),
- in.readTypedObject(Configuration.CREATOR),
- in.readTypedObject(CompatibilityInfo.CREATOR), in.readString(),
+ in.readTypedObject(Configuration.CREATOR), in.readString(),
IVoiceInteractor.Stub.asInterface(in.readStrongBinder()), in.readInt(),
in.readBundle(getClass().getClassLoader()),
in.readPersistableBundle(getClass().getClassLoader()),
@@ -216,7 +212,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
return intentsEqual && mIdent == other.mIdent
&& activityInfoEqual(other.mInfo) && Objects.equals(mCurConfig, other.mCurConfig)
&& Objects.equals(mOverrideConfig, other.mOverrideConfig)
- && Objects.equals(mCompatInfo, other.mCompatInfo)
&& Objects.equals(mReferrer, other.mReferrer)
&& mProcState == other.mProcState && areBundlesEqualRoughly(mState, other.mState)
&& areBundlesEqualRoughly(mPersistentState, other.mPersistentState)
@@ -237,7 +232,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
result = 31 * result + mIdent;
result = 31 * result + Objects.hashCode(mCurConfig);
result = 31 * result + Objects.hashCode(mOverrideConfig);
- result = 31 * result + Objects.hashCode(mCompatInfo);
result = 31 * result + Objects.hashCode(mReferrer);
result = 31 * result + Objects.hashCode(mProcState);
result = 31 * result + getRoughBundleHashCode(mState);
@@ -292,7 +286,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
// Using the same method to set and clear values to make sure we don't forget anything
private static void setValues(LaunchActivityItem instance, Intent intent, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
- CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
+ String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
@@ -303,7 +297,6 @@ public class LaunchActivityItem extends ClientTransactionItem {
instance.mInfo = info;
instance.mCurConfig = curConfig;
instance.mOverrideConfig = overrideConfig;
- instance.mCompatInfo = compatInfo;
instance.mReferrer = referrer;
instance.mVoiceInteractor = voiceInteractor;
instance.mProcState = procState;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 8db298ff8a85..861a8502c44d 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1325,8 +1325,11 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* flashlight brightness level via
* {@link android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel }.
* If this value is equal to 1, flashlight brightness control is not supported.
- * The value for this key will be null for devices with no flash unit.
- * This level must be set to a safe value to prevent any burn out issues.</p>
+ * The value for this key will be null for devices with no flash unit.</p>
+ * <p>The maximum value is guaranteed to be safe to use for an indefinite duration in
+ * terms of device flashlight lifespan, but may be too bright for comfort for many
+ * use cases. Use the default torch brightness value to avoid problems with an
+ * over-bright flashlight.</p>
* <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
*/
@PublicKey
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 91d6a9bf69cb..40f7533a2800 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -117,6 +117,7 @@ interface INetworkManagementService
/**
* Shuts down the service
*/
+ @EnforcePermission("SHUTDOWN")
void shutdown();
/**
@@ -277,6 +278,7 @@ interface INetworkManagementService
*/
void setUidOnMeteredNetworkDenylist(int uid, boolean enable);
void setUidOnMeteredNetworkAllowlist(int uid, boolean enable);
+ @EnforcePermission("NETWORK_SETTINGS")
boolean setDataSaverModeEnabled(boolean enable);
void setUidCleartextNetworkPolicy(int uid, int policy);
@@ -308,5 +310,6 @@ interface INetworkManagementService
void removeInterfaceFromLocalNetwork(String iface);
int removeRoutesFromLocalNetwork(in List<RouteInfo> routes);
+ @EnforcePermission("OBSERVE_NETWORK_POLICY")
boolean isNetworkRestricted(int uid);
}
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index 5dae31373e82..c69298192109 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -145,5 +145,8 @@ public interface AttachedSurfaceControl {
*
* @hide
*/
- SurfaceSyncGroup.SyncTarget getSyncTarget();
+ @Nullable
+ default SurfaceSyncGroup.SyncTarget getSyncTarget() {
+ return null;
+ }
}
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 9c63d56d74da..121839bc9ea6 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -666,14 +666,12 @@ public final class InputMethodSubtype implements Parcelable {
/**
* Sort the list of InputMethodSubtype
- * @param context Context will be used for getting localized strings from IME
- * @param flags Flags for the sort order
* @param imi InputMethodInfo of which subtypes are subject to be sorted
* @param subtypeList List of InputMethodSubtype which will be sorted
* @return Sorted list of subtypes
* @hide
*/
- public static List<InputMethodSubtype> sort(Context context, int flags, InputMethodInfo imi,
+ public static List<InputMethodSubtype> sort(InputMethodInfo imi,
List<InputMethodSubtype> subtypeList) {
if (imi == null) return subtypeList;
final HashSet<InputMethodSubtype> inputSubtypesSet = new HashSet<InputMethodSubtype>(
diff --git a/core/java/android/window/SurfaceSyncGroup.java b/core/java/android/window/SurfaceSyncGroup.java
index 5672697f665e..4248096f307d 100644
--- a/core/java/android/window/SurfaceSyncGroup.java
+++ b/core/java/android/window/SurfaceSyncGroup.java
@@ -186,7 +186,11 @@ public final class SurfaceSyncGroup {
if (viewRoot == null) {
return false;
}
- return addToSync(viewRoot.getSyncTarget());
+ SyncTarget syncTarget = viewRoot.getSyncTarget();
+ if (syncTarget == null) {
+ return false;
+ }
+ return addToSync(syncTarget);
}
/**
diff --git a/core/java/com/android/internal/app/procstats/IProcessStats.aidl b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
index a2eca3aee13d..84b2a354020f 100644
--- a/core/java/com/android/internal/app/procstats/IProcessStats.aidl
+++ b/core/java/com/android/internal/app/procstats/IProcessStats.aidl
@@ -21,7 +21,9 @@ import android.os.ParcelFileDescriptor;
import com.android.internal.app.procstats.ProcessStats;
interface IProcessStats {
+ @EnforcePermission("PACKAGE_USAGE_STATS")
byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
+ @EnforcePermission("PACKAGE_USAGE_STATS")
ParcelFileDescriptor getStatsOverTime(long minTime);
int getCurrentMemoryState();
@@ -43,6 +45,7 @@ interface IProcessStats {
* @param List of Files of individual commits in protobuf binary or one that is merged from them.
* @param ProcessStats object that will be used to return the full set of merged stats.
*/
+ @EnforcePermission("PACKAGE_USAGE_STATS")
long getCommittedStatsMerged(long highWaterMarkMs, int section, boolean doAggregate,
out List<ParcelFileDescriptor> committedStats, out ProcessStats mergedStats);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 50639be57f22..0a5a4d5a9adb 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -32,7 +32,6 @@ import android.app.servertransaction.TestUtils.LaunchActivityItemBuilder;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
@@ -140,7 +139,6 @@ public class ObjectPoolTests {
activityInfo.name = "name";
Configuration overrideConfig = new Configuration();
overrideConfig.assetsSeq = 5;
- CompatibilityInfo compat = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
String referrer = "referrer";
int procState = 4;
Bundle bundle = new Bundle();
@@ -152,7 +150,7 @@ public class ObjectPoolTests {
Supplier<LaunchActivityItem> itemSupplier = () -> new LaunchActivityItemBuilder()
.setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
- .setOverrideConfig(overrideConfig).setCompatInfo(compat).setReferrer(referrer)
+ .setOverrideConfig(overrideConfig).setReferrer(referrer)
.setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
.setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
.setIsForward(true).setAssistToken(assistToken)
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 26d9628ba55b..2cd890cd9d18 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -23,7 +23,6 @@ import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
@@ -96,7 +95,6 @@ class TestUtils {
private ActivityInfo mInfo;
private Configuration mCurConfig;
private Configuration mOverrideConfig;
- private CompatibilityInfo mCompatInfo;
private String mReferrer;
private IVoiceInteractor mVoiceInteractor;
private int mProcState;
@@ -137,11 +135,6 @@ class TestUtils {
return this;
}
- LaunchActivityItemBuilder setCompatInfo(CompatibilityInfo compatInfo) {
- mCompatInfo = compatInfo;
- return this;
- }
-
LaunchActivityItemBuilder setReferrer(String referrer) {
mReferrer = referrer;
return this;
@@ -214,7 +207,7 @@ class TestUtils {
LaunchActivityItem build() {
return LaunchActivityItem.obtain(mIntent, mIdent, mInfo,
- mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
+ mCurConfig, mOverrideConfig, mReferrer, mVoiceInteractor,
mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
null /* activityClientController */, mShareableActivityToken,
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 0eca0a8cb1a7..e9bbdbee576c 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -187,7 +187,6 @@ public class TransactionParcelTests {
activityInfo.name = "name";
Configuration overrideConfig = new Configuration();
overrideConfig.assetsSeq = 5;
- CompatibilityInfo compat = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
String referrer = "referrer";
int procState = 4;
Bundle bundle = new Bundle();
@@ -198,7 +197,7 @@ public class TransactionParcelTests {
LaunchActivityItem item = new LaunchActivityItemBuilder()
.setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
- .setOverrideConfig(overrideConfig).setCompatInfo(compat).setReferrer(referrer)
+ .setOverrideConfig(overrideConfig).setReferrer(referrer)
.setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
.setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic())
.setPendingNewIntents(referrerIntentList()).setIsForward(true)
@@ -489,13 +488,13 @@ public class TransactionParcelTests {
@Override
public void scheduleCreateBackupAgent(ApplicationInfo applicationInfo,
- CompatibilityInfo compatibilityInfo, int i, int userId, int operatioType)
+ int i, int userId, int operatioType)
throws RemoteException {
}
@Override
public void scheduleDestroyBackupAgent(ApplicationInfo applicationInfo,
- CompatibilityInfo compatibilityInfo, int userId) throws RemoteException {
+ int userId) throws RemoteException {
}
@Override
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 47f70ddf2d42..f4a6f025074e 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -54,7 +54,6 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.IBinder;
import android.os.UserHandle;
@@ -339,8 +338,7 @@ public class ActivityThreadClientTest {
doNothing().when(packageInfo).updateApplicationInfo(any(), any());
return new ActivityClientRecord(mock(IBinder.class), Intent.makeMainActivity(component),
- 0 /* ident */, info, new Configuration(),
- CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
+ 0 /* ident */, info, new Configuration(), null /* referrer */,
null /* voiceInteractor */, null /* state */, null /* persistentState */,
null /* pendingResults */, null /* pendingNewIntents */,
null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index c14c3c534cf4..5ab21bc5f489 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -237,6 +237,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
private final boolean mUnlockedDeviceRequired;
private final boolean mIsStrongBoxBacked;
private final int mMaxUsageCount;
+ private final boolean mRollbackResistant;
private KeyProtection(
Date keyValidityStart,
@@ -259,7 +260,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
boolean userConfirmationRequired,
boolean unlockedDeviceRequired,
boolean isStrongBoxBacked,
- int maxUsageCount) {
+ int maxUsageCount,
+ boolean rollbackResistant) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -283,6 +285,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
mUnlockedDeviceRequired = unlockedDeviceRequired;
mIsStrongBoxBacked = isStrongBoxBacked;
mMaxUsageCount = maxUsageCount;
+ mRollbackResistant = rollbackResistant;
}
/**
@@ -563,6 +566,17 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
}
/**
+ * Returns {@code true} if the key is rollback-resistant, meaning that when deleted it is
+ * guaranteed to be permanently deleted and unusable.
+ *
+ * @see Builder#setRollbackResistant(boolean)
+ * @hide
+ */
+ public boolean isRollbackResistant() {
+ return mRollbackResistant;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -591,6 +605,7 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
private boolean mIsStrongBoxBacked = false;
private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
private String mAttestKeyAlias = null;
+ private boolean mRollbackResistant = false;
/**
* Creates a new instance of the {@code Builder}.
@@ -1097,6 +1112,21 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
}
/**
+ * Sets whether the key should be rollback-resistant, meaning that when deleted it is
+ * guaranteed to be permanently deleted and unusable. Not all implementations support
+ * rollback-resistant keys. This method is hidden because implementations only support a
+ * limited number of rollback-resistant keys; currently the available space is reserved for
+ * critical system keys.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setRollbackResistant(boolean rollbackResistant) {
+ mRollbackResistant = rollbackResistant;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -1124,7 +1154,8 @@ public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
mUserConfirmationRequired,
mUnlockedDeviceRequired,
mIsStrongBoxBacked,
- mMaxUsageCount);
+ mMaxUsageCount,
+ mRollbackResistant);
}
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 33411e1ec5b9..dfda356ec35b 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -783,6 +783,12 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
params.getMaxUsageCount()
));
}
+
+ if (params.isRollbackResistant()) {
+ importArgs.add(KeyStore2ParameterUtils.makeBool(
+ KeymasterDefs.KM_TAG_ROLLBACK_RESISTANT
+ ));
+ }
} catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
index 0972cf2c032f..1636c5f73133 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -25,6 +25,7 @@ import com.android.wm.shell.bubbles.storage.BubbleXmlHelperTest.Companion.sparse
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNotNull
import junit.framework.Assert.assertTrue
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,6 +62,12 @@ class BubblePersistentRepositoryTest : ShellTestCase() {
bubbles.put(1, user1Bubbles)
}
+ @After
+ fun teardown() {
+ // Clean up the any persisted bubbles for the next run
+ repository.persistsToDisk(SparseArray())
+ }
+
@Test
fun testReadWriteOperation() {
// Verify read before write doesn't cause FileNotFoundException
@@ -71,4 +78,4 @@ class BubblePersistentRepositoryTest : ShellTestCase() {
repository.persistsToDisk(bubbles)
assertTrue(sparseArraysEqual(bubbles, repository.readFromDisk()))
}
-} \ No newline at end of file
+}
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 24c117911f7c..44c0b54546be 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -166,9 +166,8 @@ public final class MediaRouter2Manager {
*/
public void registerScanRequest() {
if (mScanRequestCount.getAndIncrement() == 0) {
- Client client = getOrCreateClient();
try {
- mMediaRouterService.startScan(client);
+ mMediaRouterService.startScan(getOrCreateClient());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -194,9 +193,8 @@ public final class MediaRouter2Manager {
}
})
== 0) {
- Client client = getOrCreateClient();
try {
- mMediaRouterService.stopScan(client);
+ mMediaRouterService.stopScan(getOrCreateClient());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -425,15 +423,11 @@ public final class MediaRouter2Manager {
*/
@NonNull
public List<RoutingSessionInfo> getRemoteSessions() {
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- return mMediaRouterService.getRemoteSessions(client);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ return mMediaRouterService.getRemoteSessions(getOrCreateClient());
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
- return Collections.emptyList();
}
/**
@@ -516,14 +510,12 @@ public final class MediaRouter2Manager {
return;
}
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- int requestId = mNextRequestId.getAndIncrement();
- mMediaRouterService.setRouteVolumeWithManager(client, requestId, route, volume);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.setRouteVolumeWithManager(
+ getOrCreateClient(), requestId, route, volume);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -545,15 +537,12 @@ public final class MediaRouter2Manager {
return;
}
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- int requestId = mNextRequestId.getAndIncrement();
- mMediaRouterService.setSessionVolumeWithManager(
- client, requestId, sessionInfo.getId(), volume);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.setSessionVolumeWithManager(
+ getOrCreateClient(), requestId, sessionInfo.getId(), volume);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -810,15 +799,12 @@ public final class MediaRouter2Manager {
return;
}
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- int requestId = mNextRequestId.getAndIncrement();
- mMediaRouterService.selectRouteWithManager(
- client, requestId, sessionInfo.getId(), route);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.selectRouteWithManager(
+ getOrCreateClient(), requestId, sessionInfo.getId(), route);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -852,15 +838,12 @@ public final class MediaRouter2Manager {
return;
}
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- int requestId = mNextRequestId.getAndIncrement();
- mMediaRouterService.deselectRouteWithManager(
- client, requestId, sessionInfo.getId(), route);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.deselectRouteWithManager(
+ getOrCreateClient(), requestId, sessionInfo.getId(), route);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -877,15 +860,12 @@ public final class MediaRouter2Manager {
public void releaseSession(@NonNull RoutingSessionInfo sessionInfo) {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- int requestId = mNextRequestId.getAndIncrement();
- mMediaRouterService.releaseSessionWithManager(
- client, requestId, sessionInfo.getId());
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ int requestId = mNextRequestId.getAndIncrement();
+ mMediaRouterService.releaseSessionWithManager(
+ getOrCreateClient(), requestId, sessionInfo.getId());
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -898,14 +878,11 @@ public final class MediaRouter2Manager {
@NonNull MediaRoute2Info route) {
int requestId = createTransferRequest(session, route);
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- mMediaRouterService.transferToRouteWithManager(
- client, requestId, session.getId(), route);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ mMediaRouterService.transferToRouteWithManager(
+ getOrCreateClient(), requestId, session.getId(), route);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -918,14 +895,11 @@ public final class MediaRouter2Manager {
int requestId = createTransferRequest(oldSession, route);
- Client client = getOrCreateClient();
- if (client != null) {
- try {
- mMediaRouterService.requestCreateSessionWithManager(
- client, requestId, oldSession, route);
- } catch (RemoteException ex) {
- throw ex.rethrowFromSystemServer();
- }
+ try {
+ mMediaRouterService.requestCreateSessionWithManager(
+ getOrCreateClient(), requestId, oldSession, route);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 281501e6043c..f4355c39819f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -84,7 +84,8 @@ public class LocalMediaManager implements BluetoothCallback {
private InfoMediaManager mInfoMediaManager;
private String mPackageName;
private MediaDevice mOnTransferBluetoothDevice;
- private AudioManager mAudioManager;
+ @VisibleForTesting
+ AudioManager mAudioManager;
@VisibleForTesting
List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
index b416738ade4a..1a08366734bc 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
@@ -44,8 +44,6 @@ public class MobileStatusTracker {
private final Handler mReceiverHandler;
private final MobileTelephonyCallback mTelephonyCallback;
- private boolean mListening = false;
-
/**
* MobileStatusTracker constructors
*
@@ -78,7 +76,6 @@ public class MobileStatusTracker {
* Config the MobileStatusTracker to start or stop monitoring platform signals.
*/
public void setListening(boolean listening) {
- mListening = listening;
if (listening) {
mPhone.registerTelephonyCallback(mReceiverHandler::post, mTelephonyCallback);
} else {
@@ -86,10 +83,6 @@ public class MobileStatusTracker {
}
}
- public boolean isListening() {
- return mListening;
- }
-
private void updateDataSim() {
int activeDataSubId = mDefaults.getActiveDataSubId();
if (SubscriptionManager.isValidSubscriptionId(activeDataSubId)) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 4332bd24e1d1..45c0d7823e99 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -57,6 +57,7 @@ public class WifiStatusTracker {
private final Handler mHandler;
private final Handler mMainThreadHandler;
private final Set<Integer> mNetworks = new HashSet<>();
+ private int mPrimaryNetworkId;
// Save the previous HISTORY_SIZE states for logging.
private final String[] mHistory = new String[HISTORY_SIZE];
// Where to copy the next state into.
@@ -106,6 +107,7 @@ public class WifiStatusTracker {
if (!mNetworks.contains(network.getNetId())) {
mNetworks.add(network.getNetId());
}
+ mPrimaryNetworkId = network.getNetId();
updateWifiInfo(wifiInfo);
updateStatusLabel();
mMainThreadHandler.post(() -> postResults());
@@ -121,10 +123,13 @@ public class WifiStatusTracker {
recordLastWifiNetwork(log);
if (mNetworks.contains(network.getNetId())) {
mNetworks.remove(network.getNetId());
- updateWifiInfo(null);
- updateStatusLabel();
- mMainThreadHandler.post(() -> postResults());
}
+ if (network.getNetId() != mPrimaryNetworkId) {
+ return;
+ }
+ updateWifiInfo(null);
+ updateStatusLabel();
+ mMainThreadHandler.post(() -> postResults());
}
};
private final NetworkCallback mDefaultNetworkCallback =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 8e850b25159c..24bb1bc9ac67 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -16,7 +16,6 @@
package com.android.settingslib.media;
-import static android.bluetooth.BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES;
import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
import static com.google.common.truth.Truth.assertThat;
@@ -29,10 +28,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioManager;
+import android.media.AudioSystem;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
import android.media.RoutingSessionInfo;
@@ -71,6 +72,7 @@ public class LocalMediaManagerTest {
private static final String TEST_CURRENT_DEVICE_ID = "currentDevice_id";
private static final String TEST_PACKAGE_NAME = "com.test.playmusic";
private static final String TEST_SESSION_ID = "session_id";
+ private static final String TEST_ADDRESS = "00:01:02:03:04:05";
@Mock
private InfoMediaManager mInfoMediaManager;
@@ -90,6 +92,8 @@ public class LocalMediaManagerTest {
private MediaRoute2Info mRouteInfo1;
@Mock
private MediaRoute2Info mRouteInfo2;
+ @Mock
+ private AudioManager mAudioManager;
private Context mContext;
private LocalMediaManager mLocalMediaManager;
@@ -118,6 +122,7 @@ public class LocalMediaManagerTest {
TEST_PACKAGE_NAME);
mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
mInfoMediaManager, "com.test.packagename");
+ mLocalMediaManager.mAudioManager = mAudioManager;
}
@Test
@@ -551,16 +556,12 @@ public class LocalMediaManagerTest {
}
@Test
- public void onDeviceListAdded_haveDisconnectedDevice_addDisconnectedDevice() {
+ public void onDeviceListAdded_haveMutingExpectedDevice_addMutingExpectedDevice() {
final List<MediaDevice> devices = new ArrayList<>();
final MediaDevice device1 = mock(MediaDevice.class);
- final MediaDevice device2 = mock(MediaDevice.class);
- final MediaDevice device3 = mock(MediaDevice.class);
mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
devices.add(device1);
- devices.add(device2);
- mLocalMediaManager.mMediaDevices.add(device3);
- mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
+ devices.add(mLocalMediaManager.mPhoneDevice);
final List<LocalBluetoothProfile> profiles = new ArrayList<>();
final A2dpProfile a2dpProfile = mock(A2dpProfile.class);
@@ -573,22 +574,25 @@ public class LocalMediaManagerTest {
bluetoothDevices.add(bluetoothDevice);
mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(bluetoothDevices);
+ AudioDeviceAttributes audioDeviceAttributes = new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, TEST_ADDRESS);
+
+ when(mAudioManager.getMutingExpectedDevice()).thenReturn(audioDeviceAttributes);
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(cachedManager);
when(cachedManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(cachedDevice.isConnected()).thenReturn(false);
when(cachedDevice.getConnectableProfiles()).thenReturn(profiles);
when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
+ when(cachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
when(mA2dpProfile.getActiveDevice()).thenReturn(bluetoothDevice);
when(mHapProfile.getActiveDevices()).thenReturn(new ArrayList<>());
when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
- when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
- when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
- assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
+ assertThat(mLocalMediaManager.mMediaDevices).hasSize(0);
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
@@ -634,68 +638,6 @@ public class LocalMediaManagerTest {
}
@Test
- public void onDeviceListAdded_haveDisconnectedDevice_list5DisconnectedDevice() {
- final List<MediaDevice> devices = new ArrayList<>();
- final MediaDevice device1 = mock(MediaDevice.class);
- final MediaDevice device2 = mock(MediaDevice.class);
- final MediaDevice device3 = mock(MediaDevice.class);
- mLocalMediaManager.mPhoneDevice = mock(PhoneMediaDevice.class);
- devices.add(device1);
- devices.add(device2);
- mLocalMediaManager.mMediaDevices.add(device3);
- mLocalMediaManager.mMediaDevices.add(mLocalMediaManager.mPhoneDevice);
-
- final List<LocalBluetoothProfile> profiles = new ArrayList<>();
- final A2dpProfile a2dpProfile = mock(A2dpProfile.class);
- profiles.add(a2dpProfile);
-
- final List<BluetoothDevice> bluetoothDevices = new ArrayList<>();
- final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
- final BluetoothDevice bluetoothDevice2 = mock(BluetoothDevice.class);
- final BluetoothDevice bluetoothDevice3 = mock(BluetoothDevice.class);
- final BluetoothDevice bluetoothDevice4 = mock(BluetoothDevice.class);
- final BluetoothDevice bluetoothDevice5 = mock(BluetoothDevice.class);
- final BluetoothDevice bluetoothDevice6 = mock(BluetoothDevice.class);
- final BluetoothClass bluetoothClass = mock(BluetoothClass.class);
- final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
- final CachedBluetoothDeviceManager cachedManager = mock(CachedBluetoothDeviceManager.class);
- bluetoothDevices.add(bluetoothDevice);
- bluetoothDevices.add(bluetoothDevice2);
- bluetoothDevices.add(bluetoothDevice3);
- bluetoothDevices.add(bluetoothDevice4);
- bluetoothDevices.add(bluetoothDevice5);
- bluetoothDevices.add(bluetoothDevice6);
- mShadowBluetoothAdapter.setMostRecentlyConnectedDevices(bluetoothDevices);
-
- when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(cachedManager);
- when(cachedManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
- when(cachedManager.findDevice(bluetoothDevice2)).thenReturn(cachedDevice);
- when(cachedManager.findDevice(bluetoothDevice3)).thenReturn(cachedDevice);
- when(cachedManager.findDevice(bluetoothDevice4)).thenReturn(cachedDevice);
- when(cachedManager.findDevice(bluetoothDevice5)).thenReturn(cachedDevice);
- when(cachedManager.findDevice(bluetoothDevice6)).thenReturn(cachedDevice);
- when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
- when(cachedDevice.isConnected()).thenReturn(false);
- when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
- when(cachedDevice.getConnectableProfiles()).thenReturn(profiles);
- when(bluetoothDevice.getBluetoothClass()).thenReturn(bluetoothClass);
- when(bluetoothClass.getDeviceClass()).thenReturn(AUDIO_VIDEO_HEADPHONES);
-
- when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
- when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
- when(device3.getId()).thenReturn(TEST_DEVICE_ID_3);
- when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
- when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id");
-
- assertThat(mLocalMediaManager.mMediaDevices).hasSize(2);
- mLocalMediaManager.registerCallback(mCallback);
- mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
-
- assertThat(mLocalMediaManager.mMediaDevices).hasSize(7);
- verify(mCallback).onDeviceListUpdate(any());
- }
-
- @Test
public void onDeviceListAdded_bluetoothAdapterIsNull_noDisconnectedDeviceAdded() {
final List<MediaDevice> devices = new ArrayList<>();
final MediaDevice device1 = mock(MediaDevice.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
new file mode 100644
index 000000000000..dc7e313dfcfa
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2022 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.settingslib.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkScoreManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiStatusTrackerTest {
+ @Mock Context mContext;
+ @Mock WifiManager mWifiManager;
+ @Mock NetworkScoreManager mNetworkScoreManager;
+ @Mock ConnectivityManager mConnectivityManager;
+ @Mock Runnable mCallback;
+
+ private final ArgumentCaptor<ConnectivityManager.NetworkCallback>
+ mNetworkCallbackCaptor =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ /**
+ * Verify that we only clear the WifiInfo if the primary network was lost.
+ */
+ @Test
+ public void testWifiInfoClearedOnPrimaryNetworkLost() {
+ WifiStatusTracker wifiStatusTracker = new WifiStatusTracker(mContext, mWifiManager,
+ mNetworkScoreManager, mConnectivityManager, mCallback);
+ wifiStatusTracker.setListening(true);
+
+ verify(mConnectivityManager)
+ .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any());
+
+ // Trigger a validation callback for the primary Wifi network.
+ WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+ when(primaryWifiInfo.makeCopy(anyLong())).thenReturn(primaryWifiInfo);
+ when(primaryWifiInfo.isPrimary()).thenReturn(true);
+ int primaryRssi = -55;
+ when(primaryWifiInfo.getRssi()).thenReturn(primaryRssi);
+ NetworkCapabilities primaryCap = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setTransportInfo(primaryWifiInfo)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+ .build();
+ Network primaryNetwork = Mockito.mock(Network.class);
+ int primaryNetworkId = 1;
+ when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+ mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+ // Verify primary wifi info is the one being used.
+ assertThat(wifiStatusTracker.connected).isTrue();
+ assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+
+ // Trigger a validation callback for the non-primary Wifi network.
+ WifiInfo nonPrimaryWifiInfo = Mockito.mock(WifiInfo.class);
+ when(nonPrimaryWifiInfo.makeCopy(anyLong())).thenReturn(nonPrimaryWifiInfo);
+ when(nonPrimaryWifiInfo.isPrimary()).thenReturn(false);
+ int nonPrimaryRssi = -75;
+ when(primaryWifiInfo.getRssi()).thenReturn(nonPrimaryRssi);
+ NetworkCapabilities nonPrimaryCap = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setTransportInfo(nonPrimaryWifiInfo)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+ .build();
+ Network nonPrimaryNetwork = Mockito.mock(Network.class);
+ int nonPrimaryNetworkId = 2;
+ when(nonPrimaryNetwork.getNetId()).thenReturn(nonPrimaryNetworkId);
+ mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(nonPrimaryNetwork, nonPrimaryCap);
+
+ // Verify primary wifi info is still the one being used.
+ assertThat(wifiStatusTracker.connected).isTrue();
+ assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+
+ // Lose the non-primary network.
+ mNetworkCallbackCaptor.getValue().onLost(nonPrimaryNetwork);
+
+ // Verify primary wifi info is still the one being used.
+ assertThat(wifiStatusTracker.connected).isTrue();
+ assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+
+ // Lose the primary network.
+ mNetworkCallbackCaptor.getValue().onLost(primaryNetwork);
+
+ // Verify we aren't connected anymore.
+ assertThat(wifiStatusTracker.connected).isFalse();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 73bc92d270b7..b0f025d4a195 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -61,7 +61,7 @@ public class Flags {
new ResourceBooleanFlag(108, R.bool.config_notificationToContents);
public static final BooleanFlag REMOVE_UNRANKED_NOTIFICATIONS =
- new BooleanFlag(109, false);
+ new BooleanFlag(109, false, true);
public static final BooleanFlag FSI_REQUIRES_KEYGUARD =
new BooleanFlag(110, false, true);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index eeb1010693fc..ec0d0811ee76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -134,9 +134,18 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mQSCarrierGroupController
.setOnSingleCarrierChangedListener(mView::setIsSingleCarrier);
- List<String> rssiIgnoredSlots = List.of(
- getResources().getString(com.android.internal.R.string.status_bar_mobile)
- );
+ List<String> rssiIgnoredSlots;
+
+ if (mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)) {
+ rssiIgnoredSlots = List.of(
+ getResources().getString(com.android.internal.R.string.status_bar_no_calling),
+ getResources().getString(com.android.internal.R.string.status_bar_call_strength)
+ );
+ } else {
+ rssiIgnoredSlots = List.of(
+ getResources().getString(com.android.internal.R.string.status_bar_mobile)
+ );
+ }
mView.onAttach(mIconManager, mQSExpansionPathInterpolator, rssiIgnoredSlots,
mInsetsProvider, mFeatureFlags.isEnabled(Flags.COMBINED_QS_HEADERS));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt b/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt
index e925b5472c27..2dac63905524 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt
@@ -27,6 +27,7 @@ data class CellSignalState(
@JvmField val contentDescription: String? = null,
@JvmField val typeContentDescription: String? = null,
@JvmField val roaming: Boolean = false,
+ @JvmField val providerModelBehavior: Boolean = false
) {
/**
* Changes the visibility of this state by returning a copy with the visibility changed.
@@ -40,4 +41,4 @@ data class CellSignalState(
if (this.visible == visible) return this
else return copy(visible = visible)
}
-}
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index 703b95a082dc..592da6554b90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
@@ -45,7 +45,7 @@ public class QSCarrier extends LinearLayout {
private View mSpacer;
@Nullable
private CellSignalState mLastSignalState;
- private boolean mMobileSignalInitialized = false;
+ private boolean mProviderModelInitialized = false;
private boolean mIsSingleCarrier;
public QSCarrier(Context context) {
@@ -96,25 +96,35 @@ public class QSCarrier extends LinearLayout {
mMobileRoaming.setImageTintList(colorStateList);
mMobileSignal.setImageTintList(colorStateList);
- if (!mMobileSignalInitialized) {
- mMobileSignalInitialized = true;
- mMobileSignal.setImageDrawable(new SignalDrawable(mContext));
+ if (state.providerModelBehavior) {
+ if (!mProviderModelInitialized) {
+ mProviderModelInitialized = true;
+ mMobileSignal.setImageDrawable(
+ mContext.getDrawable(R.drawable.ic_qs_no_calling_sms));
+ }
+ mMobileSignal.setImageDrawable(mContext.getDrawable(state.mobileSignalIconId));
+ mMobileSignal.setContentDescription(state.contentDescription);
+ } else {
+ if (!mProviderModelInitialized) {
+ mProviderModelInitialized = true;
+ mMobileSignal.setImageDrawable(new SignalDrawable(mContext));
+ }
+ mMobileSignal.setImageLevel(state.mobileSignalIconId);
+ StringBuilder contentDescription = new StringBuilder();
+ if (state.contentDescription != null) {
+ contentDescription.append(state.contentDescription).append(", ");
+ }
+ if (state.roaming) {
+ contentDescription
+ .append(mContext.getString(R.string.data_connection_roaming))
+ .append(", ");
+ }
+ // TODO: show mobile data off/no internet text for 5 seconds before carrier text
+ if (hasValidTypeContentDescription(state.typeContentDescription)) {
+ contentDescription.append(state.typeContentDescription);
+ }
+ mMobileSignal.setContentDescription(contentDescription);
}
- mMobileSignal.setImageLevel(state.mobileSignalIconId);
- StringBuilder contentDescription = new StringBuilder();
- if (state.contentDescription != null) {
- contentDescription.append(state.contentDescription).append(", ");
- }
- if (state.roaming) {
- contentDescription
- .append(mContext.getString(R.string.data_connection_roaming))
- .append(", ");
- }
- // TODO: show mobile data off/no internet text for 5 seconds before carrier text
- if (hasValidTypeContentDescription(state.typeContentDescription)) {
- contentDescription.append(state.typeContentDescription);
- }
- mMobileSignal.setContentDescription(contentDescription);
}
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index cb76ee2bb6a1..6908e5ab49e6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -42,7 +42,10 @@ import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
@@ -75,6 +78,7 @@ public class QSCarrierGroupController {
private QSCarrier[] mCarrierGroups = new QSCarrier[SIM_SLOTS];
private int[] mLastSignalLevel = new int[SIM_SLOTS];
private String[] mLastSignalLevelDescription = new String[SIM_SLOTS];
+ private final boolean mProviderModel;
private final CarrierConfigTracker mCarrierConfigTracker;
private boolean mIsSingleCarrier;
@@ -86,6 +90,9 @@ public class QSCarrierGroupController {
private final SignalCallback mSignalCallback = new SignalCallback() {
@Override
public void setMobileDataIndicators(@NonNull MobileDataIndicators indicators) {
+ if (mProviderModel) {
+ return;
+ }
int slotIndex = getSlotIndex(indicators.subId);
if (slotIndex >= SIM_SLOTS) {
Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
@@ -100,12 +107,91 @@ public class QSCarrierGroupController {
indicators.statusIcon.icon,
indicators.statusIcon.contentDescription,
indicators.typeContentDescription.toString(),
- indicators.roaming
+ indicators.roaming,
+ mProviderModel
);
mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
}
@Override
+ public void setCallIndicator(@NonNull IconState statusIcon, int subId) {
+ if (!mProviderModel) {
+ return;
+ }
+ int slotIndex = getSlotIndex(subId);
+ if (slotIndex >= SIM_SLOTS) {
+ Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
+ return;
+ }
+ if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ Log.e(TAG, "Invalid SIM slot index for subscription: " + subId);
+ return;
+ }
+
+ boolean displayCallStrengthIcon =
+ mCarrierConfigTracker.getCallStrengthConfig(subId);
+
+ if (statusIcon.icon == R.drawable.ic_qs_no_calling_sms) {
+ if (statusIcon.visible) {
+ mInfos[slotIndex] = new CellSignalState(
+ true,
+ statusIcon.icon,
+ statusIcon.contentDescription,
+ "",
+ false,
+ mProviderModel);
+ } else {
+ // Whenever the no Calling & SMS state is cleared, switched to the last
+ // known call strength icon.
+ if (displayCallStrengthIcon) {
+ mInfos[slotIndex] = new CellSignalState(
+ true,
+ mLastSignalLevel[slotIndex],
+ mLastSignalLevelDescription[slotIndex],
+ "",
+ false,
+ mProviderModel);
+ } else {
+ mInfos[slotIndex] = new CellSignalState(
+ true,
+ R.drawable.ic_qs_sim_card,
+ "",
+ "",
+ false,
+ mProviderModel);
+ }
+ }
+ mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ } else {
+ mLastSignalLevel[slotIndex] = statusIcon.icon;
+ mLastSignalLevelDescription[slotIndex] = statusIcon.contentDescription;
+ // Only Shows the call strength icon when the no Calling & SMS icon is not
+ // shown.
+ if (mInfos[slotIndex].mobileSignalIconId
+ != R.drawable.ic_qs_no_calling_sms) {
+ if (displayCallStrengthIcon) {
+ mInfos[slotIndex] = new CellSignalState(
+ true,
+ statusIcon.icon,
+ statusIcon.contentDescription,
+ "",
+ false,
+ mProviderModel);
+ } else {
+ mInfos[slotIndex] = new CellSignalState(
+ true,
+ R.drawable.ic_qs_sim_card,
+ "",
+ "",
+ false,
+ mProviderModel);
+ }
+ mMainHandler.obtainMessage(H.MSG_UPDATE_STATE).sendToTarget();
+ }
+ }
+ }
+
+ @Override
public void setNoSims(boolean hasNoSims, boolean simDetected) {
if (hasNoSims) {
for (int i = 0; i < SIM_SLOTS; i++) {
@@ -133,8 +219,14 @@ public class QSCarrierGroupController {
@Background Handler bgHandler, @Main Looper mainLooper,
NetworkController networkController,
CarrierTextManager.Builder carrierTextManagerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
+ CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags,
+ SlotIndexResolver slotIndexResolver) {
+ if (featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)) {
+ mProviderModel = true;
+ } else {
+ mProviderModel = false;
+ }
mActivityStarter = activityStarter;
mBgHandler = bgHandler;
mNetworkController = networkController;
@@ -170,7 +262,8 @@ public class QSCarrierGroupController {
R.drawable.ic_qs_no_calling_sms,
context.getText(AccessibilityContentDescriptions.NO_CALLING).toString(),
"",
- false);
+ false,
+ mProviderModel);
mLastSignalLevel[i] = TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[0];
mLastSignalLevelDescription[i] =
context.getText(AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0])
@@ -258,7 +351,8 @@ public class QSCarrierGroupController {
for (int i = 0; i < SIM_SLOTS; i++) {
if (mInfos[i].visible
&& mInfos[i].mobileSignalIconId == R.drawable.ic_qs_sim_card) {
- mInfos[i] = new CellSignalState(true, R.drawable.ic_blank, "", "", false);
+ mInfos[i] = new CellSignalState(true, R.drawable.ic_blank, "", "", false,
+ mProviderModel);
}
}
}
@@ -376,13 +470,15 @@ public class QSCarrierGroupController {
private final CarrierTextManager.Builder mCarrierTextControllerBuilder;
private final Context mContext;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final FeatureFlags mFeatureFlags;
private final SlotIndexResolver mSlotIndexResolver;
@Inject
public Builder(ActivityStarter activityStarter, @Background Handler handler,
@Main Looper looper, NetworkController networkController,
CarrierTextManager.Builder carrierTextControllerBuilder, Context context,
- CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
+ CarrierConfigTracker carrierConfigTracker, FeatureFlags featureFlags,
+ SlotIndexResolver slotIndexResolver) {
mActivityStarter = activityStarter;
mHandler = handler;
mLooper = looper;
@@ -390,6 +486,7 @@ public class QSCarrierGroupController {
mCarrierTextControllerBuilder = carrierTextControllerBuilder;
mContext = context;
mCarrierConfigTracker = carrierConfigTracker;
+ mFeatureFlags = featureFlags;
mSlotIndexResolver = slotIndexResolver;
}
@@ -401,7 +498,7 @@ public class QSCarrierGroupController {
public QSCarrierGroupController build() {
return new QSCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
mNetworkController, mCarrierTextControllerBuilder, mContext,
- mCarrierConfigTracker, mSlotIndexResolver);
+ mCarrierConfigTracker, mFeatureFlags, mSlotIndexResolver);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index d5efe367ae2b..f629a0361ddb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -806,8 +806,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi
return;
}
- mTelephonyManager.setDataEnabledForReason(
- TelephonyManager.DATA_ENABLED_REASON_USER, enabled);
+ mTelephonyManager.setDataEnabled(enabled);
if (disableOtherSubscriptions) {
final List<SubscriptionInfo> subInfoList =
mSubscriptionManager.getActiveSubscriptionInfoList();
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
index 8c8f54fe9c3d..ad073c073ed8 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
@@ -49,8 +49,8 @@ class UserFileManagerImpl @Inject constructor(
) : UserFileManager, CoreStartable(context) {
companion object {
private const val FILES = "files"
- private const val SHARED_PREFS = "shared_prefs"
- internal const val ID = "UserFileManager"
+ @VisibleForTesting internal const val SHARED_PREFS = "shared_prefs"
+ @VisibleForTesting internal const val ID = "UserFileManager"
}
private val broadcastReceiver = object : BroadcastReceiver() {
@@ -85,13 +85,15 @@ class UserFileManagerImpl @Inject constructor(
fileName
)
} else {
- Environment.buildPath(
+ val secondaryFile = Environment.buildPath(
context.filesDir,
ID,
userId.toString(),
FILES,
fileName
)
+ ensureParentDirExists(secondaryFile)
+ secondaryFile
}
}
@@ -114,6 +116,7 @@ class UserFileManagerImpl @Inject constructor(
fileName
)
+ ensureParentDirExists(secondaryUserDir)
return context.getSharedPreferences(secondaryUserDir, mode)
}
@@ -141,4 +144,18 @@ class UserFileManagerImpl @Inject constructor(
}
}
}
+
+ /**
+ * Checks to see if parent dir of the file exists. If it does not, we create the parent dirs
+ * recursively.
+ */
+ @VisibleForTesting
+ internal fun ensureParentDirExists(file: File) {
+ val parent = file.parentFile
+ if (!parent.exists()) {
+ if (!parent.mkdirs()) {
+ Log.e(ID, "Could not create parent directory for file: ${file.absolutePath}")
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
index ec221b7eccc0..f2014e9deb72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalController.java
@@ -26,17 +26,25 @@ import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings.Global;
+import android.telephony.AccessNetworkConstants;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrengthCdma;
+import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
+import android.telephony.ims.RegistrationManager.RegistrationCallback;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.AccessibilityContentDescriptions;
import com.android.settingslib.SignalIcon.MobileIconGroup;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.MobileMappings.Config;
@@ -46,6 +54,8 @@ import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.util.CarrierConfigTracker;
import java.io.PrintWriter;
@@ -60,22 +70,33 @@ import java.util.Map;
public class MobileSignalController extends SignalController<MobileState, MobileIconGroup> {
private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
private static final int STATUS_HISTORY_SIZE = 64;
+ private static final int IMS_TYPE_WWAN = 1;
+ private static final int IMS_TYPE_WLAN = 2;
+ private static final int IMS_TYPE_WLAN_CROSS_SIM = 3;
private final TelephonyManager mPhone;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final ImsMmTelManager mImsMmTelManager;
private final SubscriptionDefaults mDefaults;
private final String mNetworkNameDefault;
private final String mNetworkNameSeparator;
private final ContentObserver mObserver;
+ private final boolean mProviderModelBehavior;
+ private final Handler mReceiverHandler;
+ private int mImsType = IMS_TYPE_WWAN;
// Save entire info for logging, we only use the id.
final SubscriptionInfo mSubscriptionInfo;
private Map<String, MobileIconGroup> mNetworkToIconLookup;
+ private int mLastLevel;
private MobileIconGroup mDefaultIcons;
private Config mConfig;
@VisibleForTesting
boolean mInflateSignalStrengths = false;
+ private int mLastWwanLevel;
+ private int mLastWlanLevel;
+ private int mLastWlanCrossSimLevel;
@VisibleForTesting
- final MobileStatusTracker mMobileStatusTracker;
+ MobileStatusTracker mMobileStatusTracker;
// Save the previous STATUS_HISTORY_SIZE states for logging.
private final String[] mMobileStatusHistory = new String[STATUS_HISTORY_SIZE];
@@ -112,6 +133,52 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
}
};
+ private final RegistrationCallback mRegistrationCallback = new RegistrationCallback() {
+ @Override
+ public void onRegistered(ImsRegistrationAttributes attributes) {
+ Log.d(mTag, "onRegistered: " + "attributes=" + attributes);
+ int imsTransportType = attributes.getTransportType();
+ int registrationAttributes = attributes.getAttributeFlags();
+ if (imsTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
+ mImsType = IMS_TYPE_WWAN;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWwanLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWwanLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ } else if (imsTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
+ if (registrationAttributes == 0) {
+ mImsType = IMS_TYPE_WLAN;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanLevel, /* isWifi= */true),
+ getCallStrengthDescription(mLastWlanLevel, /* isWifi= */true));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ } else if (registrationAttributes
+ == ImsRegistrationAttributes.ATTR_EPDG_OVER_CELL_INTERNET) {
+ mImsType = IMS_TYPE_WLAN_CROSS_SIM;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanCrossSimLevel, /* isWifi= */false),
+ getCallStrengthDescription(
+ mLastWlanCrossSimLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ }
+ }
+
+ @Override
+ public void onUnregistered(ImsReasonInfo info) {
+ Log.d(mTag, "onDeregistered: " + "info=" + info);
+ mImsType = IMS_TYPE_WWAN;
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWwanLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWwanLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ };
+
// TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
// need listener lists anymore.
public MobileSignalController(
@@ -125,7 +192,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
SubscriptionDefaults defaults,
Looper receiverLooper,
CarrierConfigTracker carrierConfigTracker,
- MobileStatusTrackerFactory mobileStatusTrackerFactory
+ FeatureFlags featureFlags
) {
super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
@@ -139,6 +206,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
R.string.status_bar_network_name_separator).toString();
mNetworkNameDefault = getTextIfExists(
com.android.internal.R.string.lockscreen_carrier_default).toString();
+ mReceiverHandler = new Handler(receiverLooper);
mNetworkToIconLookup = mapIconSets(mConfig);
mDefaultIcons = getDefaultIcons(mConfig);
@@ -155,7 +223,10 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
updateTelephony();
}
};
- mMobileStatusTracker = mobileStatusTrackerFactory.createTracker(mMobileCallback);
+ mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(info.getSubscriptionId());
+ mMobileStatusTracker = new MobileStatusTracker(mPhone, receiverLooper,
+ info, mDefaults, mMobileCallback);
+ mProviderModelBehavior = featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS);
}
void setConfiguration(Config config) {
@@ -200,14 +271,41 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
mContext.getContentResolver().registerContentObserver(Global.getUriFor(
Global.MOBILE_DATA + mSubscriptionInfo.getSubscriptionId()),
true, mObserver);
+ if (mProviderModelBehavior) {
+ mReceiverHandler.post(mTryRegisterIms);
+ }
}
+ // There is no listener to monitor whether the IMS service is ready, so we have to retry the
+ // IMS registration.
+ private final Runnable mTryRegisterIms = new Runnable() {
+ private static final int MAX_RETRY = 12;
+ private int mRetryCount;
+
+ @Override
+ public void run() {
+ try {
+ mRetryCount++;
+ mImsMmTelManager.registerImsRegistrationCallback(
+ mReceiverHandler::post, mRegistrationCallback);
+ Log.d(mTag, "registerImsRegistrationCallback succeeded");
+ } catch (RuntimeException | ImsException e) {
+ if (mRetryCount < MAX_RETRY) {
+ Log.e(mTag, mRetryCount + " registerImsRegistrationCallback failed", e);
+ // Wait for 5 seconds to retry
+ mReceiverHandler.postDelayed(mTryRegisterIms, 5000);
+ }
+ }
+ }
+ };
+
/**
* Stop listening for phone state changes.
*/
public void unregisterListener() {
mMobileStatusTracker.setListening(false);
mContext.getContentResolver().unregisterContentObserver(mObserver);
+ mImsMmTelManager.unregisterImsRegistrationCallback(mRegistrationCallback);
}
private void updateInflateSignalStrength() {
@@ -296,7 +394,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
CharSequence qsDescription = null;
if (mCurrentState.dataSim) {
- // only show QS icons if the state is also default
+ // If using provider model behavior, only show QS icons if the state is also default
if (!mCurrentState.isDefault) {
return new QsInfo(qsTypeIcon, qsIcon, qsDescription);
}
@@ -318,15 +416,32 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
private SbInfo getSbInfo(String contentDescription, int dataTypeIcon) {
final boolean dataDisabled = mCurrentState.isDataDisabledOrNotDefault();
- IconState statusIcon = new IconState(
- mCurrentState.enabled && !mCurrentState.airplaneMode,
- getCurrentIconId(), contentDescription);
+ boolean showTriangle = false;
+ int typeIcon = 0;
+ IconState statusIcon = null;
+
+ if (mProviderModelBehavior) {
+ boolean showDataIconStatusBar = (mCurrentState.dataConnected || dataDisabled)
+ && (mCurrentState.dataSim && mCurrentState.isDefault);
+ typeIcon =
+ (showDataIconStatusBar || mConfig.alwaysShowDataRatIcon) ? dataTypeIcon : 0;
+ showDataIconStatusBar |= mCurrentState.roaming;
+ statusIcon = new IconState(
+ showDataIconStatusBar && !mCurrentState.airplaneMode,
+ getCurrentIconId(), contentDescription);
+
+ showTriangle = showDataIconStatusBar && !mCurrentState.airplaneMode;
+ } else {
+ statusIcon = new IconState(
+ mCurrentState.enabled && !mCurrentState.airplaneMode,
+ getCurrentIconId(), contentDescription);
- boolean showDataIconInStatusBar =
- (mCurrentState.dataConnected && mCurrentState.isDefault) || dataDisabled;
- int typeIcon =
- (showDataIconInStatusBar || mConfig.alwaysShowDataRatIcon) ? dataTypeIcon : 0;
- boolean showTriangle = mCurrentState.enabled && !mCurrentState.airplaneMode;
+ boolean showDataIconInStatusBar =
+ (mCurrentState.dataConnected && mCurrentState.isDefault) || dataDisabled;
+ typeIcon =
+ (showDataIconInStatusBar || mConfig.alwaysShowDataRatIcon) ? dataTypeIcon : 0;
+ showTriangle = mCurrentState.enabled && !mCurrentState.airplaneMode;
+ }
return new SbInfo(showTriangle, typeIcon, statusIcon);
}
@@ -445,7 +560,144 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
}
private void updateMobileStatus(MobileStatus mobileStatus) {
+ int lastVoiceState = mCurrentState.getVoiceServiceState();
mCurrentState.setFromMobileStatus(mobileStatus);
+
+ notifyMobileLevelChangeIfNecessary(mobileStatus.signalStrength);
+ if (mProviderModelBehavior) {
+ maybeNotifyCallStateChanged(lastVoiceState);
+ }
+ }
+
+ /** Call state changed is only applicable when provider model behavior is true */
+ private void maybeNotifyCallStateChanged(int lastVoiceState) {
+ int currentVoiceState = mCurrentState.getVoiceServiceState();
+ if (lastVoiceState == currentVoiceState) {
+ return;
+ }
+ // Only update the no calling Status in the below scenarios
+ // 1. The first valid voice state has been received
+ // 2. The voice state has been changed and either the last or current state is
+ // ServiceState.STATE_IN_SERVICE
+ if (lastVoiceState == -1
+ || (lastVoiceState == ServiceState.STATE_IN_SERVICE
+ || currentVoiceState == ServiceState.STATE_IN_SERVICE)) {
+ boolean isNoCalling = mCurrentState.isNoCalling();
+ isNoCalling &= !hideNoCalling();
+ IconState statusIcon = new IconState(isNoCalling,
+ R.drawable.ic_qs_no_calling_sms,
+ getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ }
+
+ void updateNoCallingState() {
+ int currentVoiceState = mCurrentState.getVoiceServiceState();
+ boolean isNoCalling = currentVoiceState != ServiceState.STATE_IN_SERVICE;
+ isNoCalling &= !hideNoCalling();
+ IconState statusIcon = new IconState(isNoCalling,
+ R.drawable.ic_qs_no_calling_sms,
+ getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ private boolean hideNoCalling() {
+ return mNetworkController.hasDefaultNetwork()
+ && mCarrierConfigTracker.getNoCallingConfig(mSubscriptionInfo.getSubscriptionId());
+ }
+
+ private int getCallStrengthIcon(int level, boolean isWifi) {
+ return isWifi ? TelephonyIcons.WIFI_CALL_STRENGTH_ICONS[level]
+ : TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[level];
+ }
+
+ private String getCallStrengthDescription(int level, boolean isWifi) {
+ return isWifi
+ ? getTextIfExists(AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[level])
+ .toString()
+ : getTextIfExists(AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[level])
+ .toString();
+ }
+
+ void refreshCallIndicator(SignalCallback callback) {
+ boolean isNoCalling = mCurrentState.isNoCalling();
+ isNoCalling &= !hideNoCalling();
+ IconState statusIcon = new IconState(isNoCalling,
+ R.drawable.ic_qs_no_calling_sms,
+ getTextIfExists(AccessibilityContentDescriptions.NO_CALLING).toString());
+ callback.setCallIndicator(statusIcon, mSubscriptionInfo.getSubscriptionId());
+
+ switch (mImsType) {
+ case IMS_TYPE_WWAN:
+ statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWwanLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWwanLevel, /* isWifi= */false));
+ break;
+ case IMS_TYPE_WLAN:
+ statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanLevel, /* isWifi= */true),
+ getCallStrengthDescription(mLastWlanLevel, /* isWifi= */true));
+ break;
+ case IMS_TYPE_WLAN_CROSS_SIM:
+ statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(mLastWlanCrossSimLevel, /* isWifi= */false),
+ getCallStrengthDescription(mLastWlanCrossSimLevel, /* isWifi= */false));
+ }
+ callback.setCallIndicator(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ void notifyWifiLevelChange(int level) {
+ if (!mProviderModelBehavior) {
+ return;
+ }
+ mLastWlanLevel = level;
+ if (mImsType != IMS_TYPE_WLAN) {
+ return;
+ }
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(level, /* isWifi= */true),
+ getCallStrengthDescription(level, /* isWifi= */true));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ void notifyDefaultMobileLevelChange(int level) {
+ if (!mProviderModelBehavior) {
+ return;
+ }
+ mLastWlanCrossSimLevel = level;
+ if (mImsType != IMS_TYPE_WLAN_CROSS_SIM) {
+ return;
+ }
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(level, /* isWifi= */false),
+ getCallStrengthDescription(level, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+
+ void notifyMobileLevelChangeIfNecessary(SignalStrength signalStrength) {
+ if (!mProviderModelBehavior) {
+ return;
+ }
+ int newLevel = getSignalLevel(signalStrength);
+ if (newLevel != mLastLevel) {
+ mLastLevel = newLevel;
+ mLastWwanLevel = newLevel;
+ if (mImsType == IMS_TYPE_WWAN) {
+ IconState statusIcon = new IconState(
+ true,
+ getCallStrengthIcon(newLevel, /* isWifi= */false),
+ getCallStrengthDescription(newLevel, /* isWifi= */false));
+ notifyCallStateChange(statusIcon, mSubscriptionInfo.getSubscriptionId());
+ }
+ if (mCurrentState.dataSim) {
+ mNetworkController.notifyDefaultMobileLevelChange(newLevel);
+ }
+ }
}
int getSignalLevel(SignalStrength signalStrength) {
@@ -549,14 +801,19 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
mMobileStatusHistoryIndex = (mMobileStatusHistoryIndex + 1) % STATUS_HISTORY_SIZE;
}
+ @VisibleForTesting
+ void setImsType(int imsType) {
+ mImsType = imsType;
+ }
+
@Override
public void dump(PrintWriter pw) {
super.dump(pw);
pw.println(" mSubscription=" + mSubscriptionInfo + ",");
+ pw.println(" mProviderModelBehavior=" + mProviderModelBehavior + ",");
pw.println(" mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
pw.println(" isDataDisabled=" + isDataDisabled() + ",");
pw.println(" mNetworkToIconLookup=" + mNetworkToIconLookup + ",");
- pw.println(" mMobileStatusTracker.isListening=" + mMobileStatusTracker.isListening());
pw.println(" MobileStatusHistory");
int size = 0;
for (int i = 0; i < STATUS_HISTORY_SIZE; i++) {
@@ -586,11 +843,6 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
icon = iconState;
description = desc;
}
-
- @Override
- public String toString() {
- return "QsInfo: ratTypeIcon=" + ratTypeIcon + " icon=" + icon;
- }
}
/** Box for status bar icon info */
@@ -604,11 +856,5 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
ratTypeIcon = typeIcon;
icon = iconState;
}
-
- @Override
- public String toString() {
- return "SbInfo: showTriangle=" + showTriangle + " ratTypeIcon=" + ratTypeIcon
- + " icon=" + icon;
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalControllerFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalControllerFactory.kt
deleted file mode 100644
index f0e52f190165..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalControllerFactory.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.connectivity
-
-import android.content.Context
-import android.os.Looper
-import android.telephony.SubscriptionInfo
-import android.telephony.TelephonyManager
-import com.android.settingslib.mobile.MobileMappings
-import com.android.settingslib.mobile.MobileStatusTracker
-import com.android.systemui.util.CarrierConfigTracker
-import javax.inject.Inject
-
-/**
- * Factory to make MobileSignalController injectable
- */
-internal class MobileSignalControllerFactory @Inject constructor(
- val context: Context,
- val callbackHandler: CallbackHandler,
- val carrierConfigTracker: CarrierConfigTracker,
-) {
- fun createMobileSignalController(
- config: MobileMappings.Config,
- hasMobileData: Boolean,
- phone: TelephonyManager,
- networkController: NetworkControllerImpl,
- subscriptionInfo: SubscriptionInfo,
- subscriptionDefaults: MobileStatusTracker.SubscriptionDefaults,
- receiverLooper: Looper,
- ): MobileSignalController {
- val mobileTrackerFactory = MobileStatusTrackerFactory(
- phone,
- receiverLooper,
- subscriptionInfo,
- subscriptionDefaults)
-
- return MobileSignalController(
- context,
- config,
- hasMobileData,
- phone,
- callbackHandler,
- networkController,
- subscriptionInfo,
- subscriptionDefaults,
- receiverLooper,
- carrierConfigTracker,
- mobileTrackerFactory,
- )
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileStatusTrackerFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileStatusTrackerFactory.kt
deleted file mode 100644
index a4c1a1989933..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileStatusTrackerFactory.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.connectivity
-
-import android.os.Looper
-import android.telephony.SubscriptionInfo
-import android.telephony.TelephonyManager
-import com.android.settingslib.mobile.MobileStatusTracker
-
-/**
- * Factory for [MobileStatusTracker], which lives in SettingsLib
- */
-class MobileStatusTrackerFactory (
- val phone: TelephonyManager,
- val receiverLooper: Looper,
- val info: SubscriptionInfo,
- val defaults: MobileStatusTracker.SubscriptionDefaults,
-) {
- fun createTracker(
- callback: MobileStatusTracker.Callback
- ): MobileStatusTracker {
- return MobileStatusTracker(
- phone,
- receiverLooper,
- info,
- defaults,
- callback)
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index ea7ec4f7fc39..268531d48f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -71,6 +71,8 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogLevel;
import com.android.systemui.log.dagger.StatusBarNetworkControllerLog;
@@ -131,11 +133,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
private final BroadcastDispatcher mBroadcastDispatcher;
private final DemoModeController mDemoModeController;
private final Object mLock = new Object();
+ private final boolean mProviderModelBehavior;
private Config mConfig;
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final FeatureFlags mFeatureFlags;
private final DumpManager mDumpManager;
private final LogBuffer mLogBuffer;
- private final MobileSignalControllerFactory mMobileFactory;
private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -231,9 +234,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
DemoModeController demoModeController,
CarrierConfigTracker carrierConfigTracker,
WifiStatusTrackerFactory trackerFactory,
- MobileSignalControllerFactory mobileFactory,
@Main Handler handler,
InternetDialogFactory internetDialogFactory,
+ FeatureFlags featureFlags,
DumpManager dumpManager,
@StatusBarNetworkControllerLog LogBuffer logBuffer) {
this(context, connectivityManager,
@@ -253,8 +256,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
demoModeController,
carrierConfigTracker,
trackerFactory,
- mobileFactory,
handler,
+ featureFlags,
dumpManager,
logBuffer);
mReceiverHandler.post(mRegisterListeners);
@@ -279,8 +282,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
DemoModeController demoModeController,
CarrierConfigTracker carrierConfigTracker,
WifiStatusTrackerFactory trackerFactory,
- MobileSignalControllerFactory mobileFactory,
@Main Handler handler,
+ FeatureFlags featureFlags,
DumpManager dumpManager,
LogBuffer logBuffer
) {
@@ -294,7 +297,6 @@ public class NetworkControllerImpl extends BroadcastReceiver
mCallbackHandler = callbackHandler;
mDataSaverController = new DataSaverControllerImpl(context);
mBroadcastDispatcher = broadcastDispatcher;
- mMobileFactory = mobileFactory;
mSubscriptionManager = subManager;
mSubDefaults = defaultsHandler;
@@ -302,6 +304,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mHasMobileDataFeature = telephonyManager.isDataCapable();
mDemoModeController = demoModeController;
mCarrierConfigTracker = carrierConfigTracker;
+ mFeatureFlags = featureFlags;
mDumpManager = dumpManager;
mLogBuffer = logBuffer;
@@ -453,6 +456,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
};
mDemoModeController.addCallback(this);
+ mProviderModelBehavior = mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS);
mDumpManager.registerDumpable(TAG, this);
}
@@ -493,16 +497,16 @@ public class NetworkControllerImpl extends BroadcastReceiver
// broadcasts
IntentFilter filter = new IntentFilter();
- filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- filter.addAction(Intent.ACTION_SERVICE_STATE);
+ filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
- filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
+ filter.addAction(Intent.ACTION_SERVICE_STATE);
filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
- filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
mListening = true;
@@ -655,6 +659,20 @@ public class NetworkControllerImpl extends BroadcastReceiver
return controller != null ? controller.getNetworkNameForCarrierWiFi() : "";
}
+ void notifyWifiLevelChange(int level) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
+ mobileSignalController.notifyWifiLevelChange(level);
+ }
+ }
+
+ void notifyDefaultMobileLevelChange(int level) {
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
+ mobileSignalController.notifyDefaultMobileLevelChange(level);
+ }
+ }
+
private void notifyControllersMobileDataChanged() {
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
@@ -727,6 +745,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.notifyListeners(cb);
+ if (mProviderModelBehavior) {
+ mobileSignalController.refreshCallIndicator(cb);
+ }
}
mCallbackHandler.setListening(cb, true);
}
@@ -841,6 +862,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController controller = mMobileSignalControllers.valueAt(i);
controller.setConfiguration(mConfig);
+ if (mProviderModelBehavior) {
+ controller.refreshCallIndicator(mCallbackHandler);
+ }
}
refreshLocale();
}
@@ -957,15 +981,11 @@ public class NetworkControllerImpl extends BroadcastReceiver
mMobileSignalControllers.put(subId, cachedControllers.get(subId));
cachedControllers.remove(subId);
} else {
- MobileSignalController controller = mMobileFactory.createMobileSignalController(
- mConfig,
- mHasMobileDataFeature,
- mPhone.createForSubscriptionId(subId),
- this,
- subscriptions.get(i),
- mSubDefaults,
- mReceiverHandler.getLooper()
- );
+ MobileSignalController controller = new MobileSignalController(mContext, mConfig,
+ mHasMobileDataFeature, mPhone.createForSubscriptionId(subId),
+ mCallbackHandler, this, subscriptions.get(i),
+ mSubDefaults, mReceiverHandler.getLooper(), mCarrierConfigTracker,
+ mFeatureFlags);
controller.setUserSetupComplete(mUserSetup);
mMobileSignalControllers.put(subId, controller);
if (subscriptions.get(i).getSimSlotIndex() == 0) {
@@ -1119,11 +1139,24 @@ public class NetworkControllerImpl extends BroadcastReceiver
|| mValidatedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
pushConnectivityToSignals();
- mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
- && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
- && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
- mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
- mNoNetworksAvailable);
+ if (mProviderModelBehavior) {
+ mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
+ mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
+ mNoNetworksAvailable);
+ for (int i = 0; i < mMobileSignalControllers.size(); i++) {
+ MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
+ mobileSignalController.updateNoCallingState();
+ }
+ notifyAllListeners();
+ } else {
+ mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
+ mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
+ mNoNetworksAvailable);
+ }
}
/**
@@ -1313,7 +1346,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
mMobileSignalControllers.clear();
int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax();
for (int i = start /* get out of normal index range */; i < start + num; i++) {
- subs.add(addDemoModeSignalController(i, i));
+ subs.add(addSignalController(i, i));
}
mCallbackHandler.setSubs(subs);
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
@@ -1339,7 +1372,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
List<SubscriptionInfo> subs = new ArrayList<>();
while (mMobileSignalControllers.size() <= slot) {
int nextSlot = mMobileSignalControllers.size();
- subs.add(addDemoModeSignalController(nextSlot, nextSlot));
+ subs.add(addSignalController(nextSlot, nextSlot));
}
if (!subs.isEmpty()) {
mCallbackHandler.setSubs(subs);
@@ -1429,20 +1462,14 @@ public class NetworkControllerImpl extends BroadcastReceiver
mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
}
- private SubscriptionInfo addDemoModeSignalController(int id, int simSlotIndex) {
+ private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
null, null, null, "", false, null, null);
-
- MobileSignalController controller = mMobileFactory.createMobileSignalController(
- mConfig,
- mHasMobileDataFeature,
- mPhone.createForSubscriptionId(info.getSubscriptionId()),
- this,
- info,
- mSubDefaults,
- mReceiverHandler.getLooper()
- );
-
+ MobileSignalController controller = new MobileSignalController(mContext,
+ mConfig, mHasMobileDataFeature,
+ mPhone.createForSubscriptionId(info.getSubscriptionId()), mCallbackHandler, this,
+ info, mSubDefaults, mReceiverHandler.getLooper(), mCarrierConfigTracker,
+ mFeatureFlags);
mMobileSignalControllers.put(id, controller);
controller.getState().userSetup = true;
return info;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
index 12f2c22ab86a..87cdb17245f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
@@ -222,6 +222,7 @@ public class WifiSignalController extends SignalController<WifiState, IconGroup>
mCurrentState.connected = mWifiTracker.connected;
mCurrentState.ssid = mWifiTracker.ssid;
mCurrentState.rssi = mWifiTracker.rssi;
+ boolean levelChanged = mCurrentState.level != mWifiTracker.level;
mCurrentState.level = mWifiTracker.level;
mCurrentState.statusLabel = mWifiTracker.statusLabel;
mCurrentState.isCarrierMerged = mWifiTracker.isCarrierMerged;
@@ -229,6 +230,10 @@ public class WifiSignalController extends SignalController<WifiState, IconGroup>
mCurrentState.iconGroup =
mCurrentState.isCarrierMerged ? mCarrierMergedWifiIconGroup
: mUnmergedWifiIconGroup;
+
+ if (levelChanged) {
+ mNetworkController.notifyWifiLevelChange(mCurrentState.level);
+ }
}
boolean isCarrierMergedWifi(int subId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 492734e93dca..ee242a4b1b75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -26,6 +26,8 @@ import android.util.Log;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
@@ -64,6 +66,7 @@ public class StatusBarSignalPolicy implements SignalCallback,
private final Handler mHandler = Handler.getMain();
private final CarrierConfigTracker mCarrierConfigTracker;
private final TunerService mTunerService;
+ private final FeatureFlags mFeatureFlags;
private boolean mHideAirplane;
private boolean mHideMobile;
@@ -87,7 +90,8 @@ public class StatusBarSignalPolicy implements SignalCallback,
CarrierConfigTracker carrierConfigTracker,
NetworkController networkController,
SecurityController securityController,
- TunerService tunerService
+ TunerService tunerService,
+ FeatureFlags featureFlags
) {
mContext = context;
@@ -96,6 +100,7 @@ public class StatusBarSignalPolicy implements SignalCallback,
mNetworkController = networkController;
mSecurityController = securityController;
mTunerService = tunerService;
+ mFeatureFlags = featureFlags;
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
@@ -373,6 +378,40 @@ public class StatusBarSignalPolicy implements SignalCallback,
}
@Override
+ public void setConnectivityStatus(boolean noDefaultNetwork, boolean noValidatedNetwork,
+ boolean noNetworksAvailable) {
+ if (!mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)) {
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "setConnectivityStatus: "
+ + "noDefaultNetwork = " + noDefaultNetwork + ","
+ + "noValidatedNetwork = " + noValidatedNetwork + ","
+ + "noNetworksAvailable = " + noNetworksAvailable);
+ }
+ WifiIconState newState = mWifiIconState.copy();
+ newState.noDefaultNetwork = noDefaultNetwork;
+ newState.noValidatedNetwork = noValidatedNetwork;
+ newState.noNetworksAvailable = noNetworksAvailable;
+ newState.slot = mSlotWifi;
+ newState.airplaneSpacerVisible = mIsAirplaneMode;
+ if (noDefaultNetwork && noNetworksAvailable && !mIsAirplaneMode) {
+ newState.visible = true;
+ newState.resId = R.drawable.ic_qs_no_internet_unavailable;
+ } else if (noDefaultNetwork && !noNetworksAvailable
+ && (!mIsAirplaneMode || (mIsAirplaneMode && mIsWifiEnabled))) {
+ newState.visible = true;
+ newState.resId = R.drawable.ic_qs_no_internet_available;
+ } else {
+ newState.visible = false;
+ newState.resId = 0;
+ }
+ updateWifiIconWithState(newState);
+ mWifiIconState = newState;
+ }
+
+
+ @Override
public void setEthernetIndicators(IconState state) {
boolean visible = state.visible && !mHideEthernet;
int resId = state.icon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 2e6664820fa7..dfcdaefd8e03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -62,7 +62,6 @@ import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.LatencyTracker;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.users.UserCreatingDialog;
-import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.GuestResetOrExitSessionReceiver;
import com.android.systemui.GuestResumeSessionReceiver;
@@ -167,6 +166,7 @@ public class UserSwitcherController implements Dumpable {
private final AtomicBoolean mGuestIsResetting;
private final AtomicBoolean mGuestCreationScheduled;
private FalsingManager mFalsingManager;
+ @Nullable
private View mView;
private String mCreateSupervisedUserPackage;
private GlobalSettings mGlobalSettings;
@@ -572,9 +572,11 @@ public class UserSwitcherController implements Dumpable {
protected void switchToUserId(int id) {
try {
- mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder
- .withView(InteractionJankMonitor.CUJ_USER_SWITCH, mView)
- .setTimeout(MULTI_USER_JOURNEY_TIMEOUT));
+ if (mView != null) {
+ mInteractionJankMonitor.begin(InteractionJankMonitor.Configuration.Builder
+ .withView(InteractionJankMonitor.CUJ_USER_SWITCH, mView)
+ .setTimeout(MULTI_USER_JOURNEY_TIMEOUT));
+ }
mLatencyTracker.onActionStart(LatencyTracker.ACTION_USER_SWITCH);
pauseRefreshUsers();
mActivityManager.switchUser(id);
@@ -936,15 +938,17 @@ public class UserSwitcherController implements Dumpable {
guestCreationProgressDialog.show();
// userManager.createGuest will block the thread so post is needed for the dialog to show
- ThreadUtils.postOnMainThread(() -> {
+ mBgExecutor.execute(() -> {
final int guestId = createGuest();
- guestCreationProgressDialog.dismiss();
- if (guestId == UserHandle.USER_NULL) {
- Toast.makeText(mContext,
- com.android.settingslib.R.string.add_guest_failed,
- Toast.LENGTH_SHORT).show();
- }
- callback.accept(guestId);
+ mUiExecutor.execute(() -> {
+ guestCreationProgressDialog.dismiss();
+ if (guestId == UserHandle.USER_NULL) {
+ Toast.makeText(mContext,
+ com.android.settingslib.R.string.add_guest_failed,
+ Toast.LENGTH_SHORT).show();
+ }
+ callback.accept(guestId);
+ });
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserCreator.java b/packages/SystemUI/src/com/android/systemui/user/UserCreator.java
deleted file mode 100644
index 0686071c1718..000000000000
--- a/packages/SystemUI/src/com/android/systemui/user/UserCreator.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.user;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.UserManager;
-
-import com.android.internal.util.UserIcons;
-import com.android.settingslib.users.UserCreatingDialog;
-import com.android.settingslib.utils.ThreadUtils;
-
-import java.util.function.Consumer;
-
-import javax.inject.Inject;
-
-/**
- * A class to do the user creation process. It shows a progress dialog, and manages the user
- * creation
- */
-public class UserCreator {
-
- private final Context mContext;
- private final UserManager mUserManager;
-
- @Inject
- public UserCreator(Context context, UserManager userManager) {
- mContext = context;
- mUserManager = userManager;
- }
-
- /**
- * Shows a progress dialog then starts the user creation process on the main thread.
- *
- * @param successCallback is called when the user creation is successful.
- * @param errorCallback is called when userManager.createUser returns null.
- * (Exceptions are not handled by this class)
- */
- public void createUser(String userName, Drawable userIcon, Consumer<UserInfo> successCallback,
- Runnable errorCallback) {
-
- Dialog userCreationProgressDialog = new UserCreatingDialog(mContext);
- userCreationProgressDialog.show();
-
- // userManager.createUser will block the thread so post is needed for the dialog to show
- ThreadUtils.postOnMainThread(() -> {
- UserInfo user =
- mUserManager.createUser(userName, UserManager.USER_TYPE_FULL_SECONDARY, 0);
- if (user == null) {
- // Couldn't create user for some reason
- userCreationProgressDialog.dismiss();
- errorCallback.run();
- return;
- }
-
- Drawable newUserIcon = userIcon;
- Resources res = mContext.getResources();
- if (newUserIcon == null) {
- newUserIcon = UserIcons.getDefaultUserIcon(res, user.id, false);
- }
- mUserManager.setUserIcon(
- user.id, UserIcons.convertToBitmapAtUserIconSize(res, newUserIcon));
-
- userCreationProgressDialog.dismiss();
- successCallback.accept(user);
- });
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserCreator.kt b/packages/SystemUI/src/com/android/systemui/user/UserCreator.kt
new file mode 100644
index 000000000000..dcbbe7441922
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/UserCreator.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.user
+
+import android.app.Dialog
+import android.content.Context
+import android.content.pm.UserInfo
+import android.graphics.drawable.Drawable
+import android.os.UserManager
+import com.android.internal.util.UserIcons
+import com.android.settingslib.users.UserCreatingDialog
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import java.util.concurrent.Executor
+import java.util.function.Consumer
+import javax.inject.Inject
+
+/**
+ * A class to do the user creation process. It shows a progress dialog, and manages the user
+ * creation
+ */
+class UserCreator @Inject constructor(
+ private val context: Context,
+ private val userManager: UserManager,
+ @Main private val mainExecutor: Executor,
+ @Background private val bgExecutor: Executor
+) {
+ /**
+ * Shows a progress dialog then starts the user creation process on the main thread.
+ *
+ * @param successCallback is called when the user creation is successful.
+ * @param errorCallback is called when userManager.createUser returns null.
+ * (Exceptions are not handled by this class)
+ */
+ fun createUser(
+ userName: String?,
+ userIcon: Drawable?,
+ successCallback: Consumer<UserInfo?>,
+ errorCallback: Runnable
+ ) {
+ val userCreationProgressDialog: Dialog = UserCreatingDialog(context)
+ userCreationProgressDialog.show()
+
+ // userManager.createUser will block the thread so post is needed for the dialog to show
+ bgExecutor.execute {
+ val user = userManager.createUser(userName, UserManager.USER_TYPE_FULL_SECONDARY, 0)
+ mainExecutor.execute main@{
+ if (user == null) {
+ // Couldn't create user for some reason
+ userCreationProgressDialog.dismiss()
+ errorCallback.run()
+ return@main
+ }
+ bgExecutor.execute {
+ var newUserIcon = userIcon
+ val res = context.resources
+ if (newUserIcon == null) {
+ newUserIcon = UserIcons.getDefaultUserIcon(res, user.id, false)
+ }
+ userManager.setUserIcon(
+ user.id, UserIcons.convertToBitmapAtUserIconSize(res, newUserIcon))
+ }
+ userCreationProgressDialog.dismiss()
+ successCallback.accept(user)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index be14cc51ef96..07c8af953d1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -26,6 +26,7 @@ import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.colorextraction.SysuiColorExtractor
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.qs.carrier.QSCarrierGroup
import com.android.systemui.qs.carrier.QSCarrierGroupController
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
@@ -45,10 +46,10 @@ import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
+import org.mockito.Mockito.`when`
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -161,6 +162,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
@Test
fun testRSSISlot_notCombined() {
+ `when`(featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)).thenReturn(false)
controller.init()
val captor = argumentCaptor<List<String>>()
@@ -172,6 +174,20 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
}
@Test
+ fun testRSSISlot_combined() {
+ `when`(featureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)).thenReturn(true)
+ controller.init()
+
+ val captor = argumentCaptor<List<String>>()
+ verify(view).onAttach(any(), any(), capture(captor), any(), anyBoolean())
+
+ assertThat(captor.value).containsExactly(
+ mContext.getString(com.android.internal.R.string.status_bar_no_calling),
+ mContext.getString(com.android.internal.R.string.status_bar_call_strength)
+ )
+ }
+
+ @Test
fun testSingleCarrierCallback() {
controller.init()
reset(view)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
index 1963e30e741e..bd794d6813ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierGroupControllerTest.java
@@ -37,6 +37,7 @@ import android.widget.TextView;
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.connectivity.IconState;
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
@@ -79,6 +80,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
@Mock
private QSCarrier mQSCarrier3;
private TestableLooper mTestableLooper;
+ @Mock private FeatureFlags mFeatureFlags;
@Mock
private QSCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
@@ -118,7 +120,7 @@ public class QSCarrierGroupControllerTest extends LeakCheckedTest {
mQSCarrierGroupController = new QSCarrierGroupController.Builder(
mActivityStarter, handler, TestableLooper.get(this).getLooper(),
mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker,
- mSlotIndexResolver)
+ mFeatureFlags, mSlotIndexResolver)
.setQSCarrierGroup(mQSCarrierGroup)
.build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
index 99a17a613041..5212255078fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
@@ -22,11 +22,13 @@ import static org.junit.Assert.assertTrue;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.FeatureFlagUtils;
import android.view.LayoutInflater;
import android.view.View;
import androidx.test.filters.SmallTest;
+import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -57,14 +59,14 @@ public class QSCarrierTest extends SysuiTestCase {
@Test
public void testUpdateState_first() {
- CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false);
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
assertTrue(mQSCarrier.updateState(c, false));
}
@Test
public void testUpdateState_same() {
- CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false);
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
assertTrue(mQSCarrier.updateState(c, false));
assertFalse(mQSCarrier.updateState(c, false));
@@ -72,7 +74,7 @@ public class QSCarrierTest extends SysuiTestCase {
@Test
public void testUpdateState_changed() {
- CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false);
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
assertTrue(mQSCarrier.updateState(c, false));
@@ -83,14 +85,14 @@ public class QSCarrierTest extends SysuiTestCase {
@Test
public void testUpdateState_singleCarrier_first() {
- CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false);
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
assertTrue(mQSCarrier.updateState(c, true));
}
@Test
public void testUpdateState_singleCarrier_noShowIcon() {
- CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false);
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
mQSCarrier.updateState(c, true);
@@ -99,7 +101,7 @@ public class QSCarrierTest extends SysuiTestCase {
@Test
public void testUpdateState_multiCarrier_showIcon() {
- CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false);
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
mQSCarrier.updateState(c, false);
@@ -108,7 +110,7 @@ public class QSCarrierTest extends SysuiTestCase {
@Test
public void testUpdateState_changeSingleMultiSingle() {
- CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false);
+ CellSignalState c = new CellSignalState(true, mSignalIconId, "", "", false, false);
mQSCarrier.updateState(c, true);
assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
index 73226fa0b12c..6d9b01e28aa4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
@@ -31,6 +31,7 @@ import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.Executor
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -62,6 +63,14 @@ class UserFileManagerImplTest : SysuiTestCase() {
broadcastDispatcher, backgroundExecutor)
}
+ @After
+ fun end() {
+ val dir = Environment.buildPath(
+ context.filesDir,
+ UserFileManagerImpl.ID)
+ dir.deleteRecursively()
+ }
+
@Test
fun testGetFile() {
assertThat(userFileManager.getFile(TEST_FILE_NAME, 0).path)
@@ -72,8 +81,19 @@ class UserFileManagerImplTest : SysuiTestCase() {
@Test
fun testGetSharedPreferences() {
+ val secondarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11)
+ val secondaryUserDir = Environment.buildPath(
+ context.filesDir,
+ UserFileManagerImpl.ID,
+ "11",
+ UserFileManagerImpl.SHARED_PREFS,
+ TEST_FILE_NAME
+ )
+
+ assertThat(secondarySharedPref).isNotNull()
+ assertThat(secondaryUserDir.exists())
assertThat(userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 0))
- .isNotEqualTo(userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11))
+ .isNotEqualTo(secondarySharedPref)
}
@Test
@@ -115,6 +135,19 @@ class UserFileManagerImplTest : SysuiTestCase() {
verify(userManager).aliveUsers
assertThat(secondaryUserDir.exists()).isFalse()
assertThat(file.exists()).isFalse()
- dir.deleteRecursively()
+ }
+
+ @Test
+ fun testEnsureParentDirExists() {
+ val file = Environment.buildPath(
+ context.filesDir,
+ UserFileManagerImpl.ID,
+ "11",
+ "files",
+ TEST_FILE_NAME
+ )
+ assertThat(file.parentFile.exists()).isFalse()
+ userFileManager.ensureParentDirExists(file)
+ assertThat(file.parentFile.exists()).isTrue()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
index f8a0d2fc415c..0d1879cb2593 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerBaseTest.java
@@ -70,6 +70,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -125,8 +127,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected CarrierConfigTracker mCarrierConfigTracker;
protected FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
protected Handler mMainHandler;
+ protected FeatureFlags mFeatureFlags;
protected WifiStatusTrackerFactory mWifiStatusTrackerFactory;
- protected MobileSignalControllerFactory mMobileFactory;
protected int mSubId;
@@ -156,6 +158,9 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
+ mFeatureFlags = mock(FeatureFlags.class);
+ when(mFeatureFlags.isEnabled(Flags.COMBINED_STATUS_BAR_SIGNAL_ICONS)).thenReturn(false);
+
mInstrumentation = InstrumentationRegistry.getInstrumentation();
Settings.Global.putInt(mContext.getContentResolver(), Global.AIRPLANE_MODE_ON, 0);
TestableResources res = mContext.getOrCreateTestableResources();
@@ -219,11 +224,6 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mWifiStatusTrackerFactory = new WifiStatusTrackerFactory(
mContext, mMockWm, mMockNsm, mMockCm, mMainHandler);
- mMobileFactory = new MobileSignalControllerFactory(
- mContext,
- mCallbackHandler,
- mCarrierConfigTracker
- );
mNetworkController = new NetworkControllerImpl(mContext,
mMockCm,
@@ -243,8 +243,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mDemoModeController,
mCarrierConfigTracker,
mWifiStatusTrackerFactory,
- mMobileFactory,
mMainHandler,
+ mFeatureFlags,
mock(DumpManager.class),
mock(LogBuffer.class)
);
@@ -438,6 +438,10 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
updateSignalStrength();
}
+ public void setImsType(int imsType) {
+ mMobileSignalController.setImsType(imsType);
+ }
+
public void setIsGsm(boolean gsm) {
when(mSignalStrength.isGsm()).thenReturn(gsm);
updateSignalStrength();
@@ -633,4 +637,5 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected void assertDataNetworkNameEquals(String expected) {
assertEquals("Data network name", expected, mNetworkController.getMobileDataNetworkName());
}
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
index ed8a3e16cdd1..e3dd6f4e6e40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
@@ -145,8 +145,8 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
mDemoModeController,
mock(CarrierConfigTracker.class),
mWifiStatusTrackerFactory,
- mMobileFactory,
new Handler(TestableLooper.get(this).getLooper()),
+ mFeatureFlags,
mock(DumpManager.class),
mock(LogBuffer.class));
setupNetworkController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
index a76676e01c15..698899a8fc36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
@@ -85,8 +85,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
mDemoModeController,
mCarrierConfigTracker,
mWifiStatusTrackerFactory,
- mMobileFactory,
mMainHandler,
+ mFeatureFlags,
mock(DumpManager.class),
mock(LogBuffer.class)
);
@@ -121,8 +121,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
mDemoModeController,
mCarrierConfigTracker,
mWifiStatusTrackerFactory,
- mMobileFactory,
mMainHandler,
+ mFeatureFlags,
mock(DumpManager.class),
mock(LogBuffer.class));
TestableLooper.get(this).processAllMessages();
@@ -155,8 +155,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
mDemoModeController,
mock(CarrierConfigTracker.class),
mWifiStatusTrackerFactory,
- mMobileFactory,
mMainHandler,
+ mFeatureFlags,
mock(DumpManager.class),
mock(LogBuffer.class));
setupNetworkController();
@@ -192,8 +192,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
mDemoModeController,
mock(CarrierConfigTracker.class),
mWifiStatusTrackerFactory,
- mMobileFactory,
mMainHandler,
+ mFeatureFlags,
mock(DumpManager.class),
mock(LogBuffer.class));
mNetworkController.registerListeners();
@@ -277,8 +277,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
mDemoModeController,
mock(CarrierConfigTracker.class),
mWifiStatusTrackerFactory,
- mMobileFactory,
mMainHandler,
+ mFeatureFlags,
mock(DumpManager.class),
mock(LogBuffer.class));
setupNetworkController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
index 68170ea4b518..3f7149159247 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
@@ -30,6 +30,7 @@ import android.net.NetworkInfo;
import android.net.vcn.VcnTransportInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.telephony.CellSignalStrength;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -284,6 +285,44 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
verifyLastMobileDataIndicatorsForVcn(false, 1, 0, false);
}
+ @Test
+ public void testCallStrengh() {
+ if (true) return;
+ String testSsid = "Test SSID";
+ setWifiEnabled(true);
+ setWifiState(true, testSsid);
+ // Set the ImsType to be IMS_TYPE_WLAN
+ setImsType(2);
+ setWifiLevel(1);
+ for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
+ setWifiLevel(testLevel);
+ verifyLastCallStrength(TelephonyIcons.WIFI_CALL_STRENGTH_ICONS[testLevel]);
+ }
+ // Set the ImsType to be IMS_TYPE_WWAN
+ setImsType(1);
+ setupDefaultSignal();
+ for (int testStrength = 0;
+ testStrength < CellSignalStrength.getNumSignalStrengthLevels(); testStrength++) {
+ setLevel(testStrength);
+ verifyLastCallStrength(TelephonyIcons.MOBILE_CALL_STRENGTH_ICONS[testStrength]);
+ }
+ }
+
+ @Test
+ public void testNonPrimaryWiFi() {
+ if (true) return;
+ String testSsid = "Test SSID";
+ setWifiEnabled(true);
+ setWifiState(true, testSsid);
+ // Set the ImsType to be IMS_TYPE_WLAN
+ setImsType(2);
+ setWifiLevel(1);
+ verifyLastCallStrength(TelephonyIcons.WIFI_CALL_STRENGTH_ICONS[1]);
+ when(mWifiInfo.isPrimary()).thenReturn(false);
+ setWifiLevel(3);
+ verifyLastCallStrength(TelephonyIcons.WIFI_CALL_STRENGTH_ICONS[1]);
+ }
+
protected void setWifiActivity(int activity) {
// TODO: Not this, because this variable probably isn't sticking around.
mNetworkController.mWifiSignalController.setActivity(activity);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 09d7c03c2091..359a780d2a94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -77,6 +77,7 @@ import org.mockito.Mockito.doNothing
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@@ -269,6 +270,8 @@ class UserSwitcherControllerTest : SysuiTestCase() {
`when`(userManager.createGuest(any())).thenReturn(guestInfo)
userSwitcherController.onUserListItemClicked(emptyGuestUserRecord, null)
+ bgExecutor.runAllReady()
+ uiExecutor.runAllReady()
testableLooper.processAllMessages()
verify(interactionJankMonitor).begin(any())
verify(latencyTracker).onActionStart(LatencyTracker.ACTION_USER_SWITCH)
@@ -294,6 +297,8 @@ class UserSwitcherControllerTest : SysuiTestCase() {
`when`(userManager.createGuest(any())).thenReturn(guestInfo)
userSwitcherController.onUserListItemClicked(emptyGuestUserRecord, dialogShower)
+ bgExecutor.runAllReady()
+ uiExecutor.runAllReady()
testableLooper.processAllMessages()
verify(dialogShower).dismiss()
}
@@ -584,4 +589,24 @@ class UserSwitcherControllerTest : SysuiTestCase() {
broadcastReceiverCaptor.value.onReceive(context, intent)
verify(cb).onUserSwitched()
}
+
+ @Test
+ fun onUserItemClicked_guest_runsOnBgThread() {
+ val dialogShower = mock(UserSwitchDialogController.DialogShower::class.java)
+ val guestUserRecord = UserSwitcherController.UserRecord(
+ null,
+ picture,
+ true /* guest */,
+ false /* current */,
+ false /* isAddUser */,
+ false /* isRestricted */,
+ true /* isSwitchToEnabled */,
+ false /* isAddSupervisedUser */)
+
+ userSwitcherController.onUserListItemClicked(guestUserRecord, dialogShower)
+ assertTrue(bgExecutor.numPending() > 0)
+ verify(userManager, never()).createGuest(context)
+ bgExecutor.runAllReady()
+ verify(userManager).createGuest(context)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
new file mode 100644
index 000000000000..a85ae7df546b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
@@ -0,0 +1,73 @@
+package com.android.systemui.user
+
+import android.content.pm.UserInfo
+import android.graphics.Bitmap
+import android.os.UserManager
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.time.FakeSystemClock
+import java.util.function.Consumer
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class UserCreatorTest : SysuiTestCase() {
+ companion object {
+ const val USER_NAME = "abc"
+ }
+
+ @Mock
+ private lateinit var userCreator: UserCreator
+ @Mock
+ private lateinit var userManager: UserManager
+ private lateinit var mainExecutor: FakeExecutor
+ private lateinit var bgExecutor: FakeExecutor
+ private lateinit var user: UserInfo
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mainExecutor = FakeExecutor(FakeSystemClock())
+ bgExecutor = FakeExecutor(FakeSystemClock())
+ userCreator = UserCreator(context, userManager, mainExecutor, bgExecutor)
+ user = Mockito.mock(UserInfo::class.java)
+ Mockito.`when`(userManager.createUser(USER_NAME, UserManager.USER_TYPE_FULL_SECONDARY, 0))
+ .thenReturn(user)
+ }
+
+ @Test
+ fun testCreateUser_threadingOrder() {
+ val successCallback = Mockito.mock(Consumer::class.java)
+ val errorCallback = Mockito.mock(Runnable::class.java)
+
+ userCreator.createUser(
+ USER_NAME,
+ null,
+ successCallback as Consumer<UserInfo?>,
+ errorCallback)
+
+ verify(userManager, never()).createUser(USER_NAME, UserManager.USER_TYPE_FULL_SECONDARY, 0)
+ bgExecutor.runAllReady()
+ verify(successCallback, never()).accept(user)
+ mainExecutor.runAllReady()
+ verify(userManager, never()).setUserIcon(anyInt(), any(Bitmap::class.java))
+ bgExecutor.runAllReady()
+
+ verify(userManager).createUser(USER_NAME, UserManager.USER_TYPE_FULL_SECONDARY, 0)
+ verify(userManager).setUserIcon(anyInt(), any(Bitmap::class.java))
+ verify(successCallback).accept(user)
+ }
+}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 73d9cc759b10..d29e25c3faff 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -862,10 +862,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
return list;
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.SHUTDOWN)
@Override
public void shutdown() {
// TODO: remove from aidl if nobody calls externally
- mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
Slog.i(TAG, "Shutting down");
}
@@ -1203,9 +1203,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
setUidOnMeteredNetworkList(uid, true, enable);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.NETWORK_SETTINGS)
@Override
public boolean setDataSaverModeEnabled(boolean enable) {
- mContext.enforceCallingOrSelfPermission(NETWORK_SETTINGS, TAG);
if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
synchronized (mQuotaLock) {
@@ -1741,9 +1741,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub {
return NetdUtils.removeRoutesFromLocalNetwork(mNetdService, routes);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY)
@Override
public boolean isNetworkRestricted(int uid) {
- mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
return isNetworkRestrictedInternal(uid);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c5b5fb941e05..002aa773d85a 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4413,7 +4413,7 @@ public final class ActiveServices {
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
thread.scheduleCreateService(r, r.serviceInfo,
- mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
+ null /* compatInfo (unused but need to keep method signature) */,
app.mState.getReportedProcState());
r.postNotification();
created = true;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9f0aeec40bd7..5729a06830cf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4980,7 +4980,6 @@ public class ActivityManagerService extends IActivityManager.Stub
PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
try {
thread.scheduleCreateBackupAgent(backupTarget.appInfo,
- compatibilityInfoForPackage(backupTarget.appInfo),
backupTarget.backupMode, backupTarget.userId, backupTarget.operationType);
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
@@ -12900,8 +12899,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (thread != null) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc);
try {
- thread.scheduleCreateBackupAgent(app,
- compatibilityInfoForPackage(app), backupMode, targetUserId,
+ thread.scheduleCreateBackupAgent(app, backupMode, targetUserId,
operationType);
} catch (RemoteException e) {
// Will time out on the backup manager side
@@ -13027,8 +13025,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final IApplicationThread thread = proc.getThread();
if (thread != null) {
try {
- thread.scheduleDestroyBackupAgent(appInfo,
- compatibilityInfoForPackage(appInfo), userId);
+ thread.scheduleDestroyBackupAgent(appInfo, userId);
} catch (Exception e) {
Slog.e(TAG, "Exception when unbinding backup agent:");
e.printStackTrace();
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 0cd1bfa3740a..6d520c3c6be8 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -361,7 +361,7 @@ public final class BroadcastQueue {
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
- mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
+ null /* compatInfo (unused but need to keep method signature) */,
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.mState.getReportedProcState());
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 7371d07183a9..33e407025ae6 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -564,10 +564,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return res;
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
@Override
public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
- mAm.mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
synchronized (mLock) {
long now = SystemClock.uptimeMillis();
@@ -619,11 +618,10 @@ public final class ProcessStatsService extends IProcessStats.Stub {
* @return List of proto binary of individual commit files or one that is merged from them;
* the merged, final ProcessStats object.
*/
+ @android.annotation.EnforcePermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
@Override
public long getCommittedStatsMerged(long highWaterMarkMs, int section, boolean doAggregate,
List<ParcelFileDescriptor> committedStats, ProcessStats mergedStats) {
- mAm.mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_USAGE_STATS, null);
long newHighWaterMark = highWaterMarkMs;
mFileLock.lock();
@@ -708,10 +706,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return fds[0];
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
@Override
public ParcelFileDescriptor getStatsOverTime(long minTime) {
- mAm.mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
long curTime;
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 18d5194e8bc0..e40925605899 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3904,6 +3904,36 @@ public class AudioService extends IAudioService.Stub
}
}
+ private void setLeAudioVolumeOnModeUpdate(int mode) {
+ switch (mode) {
+ case AudioSystem.MODE_IN_COMMUNICATION:
+ case AudioSystem.MODE_IN_CALL:
+ case AudioSystem.MODE_NORMAL:
+ break;
+ case AudioSystem.MODE_RINGTONE:
+ // not changing anything for ringtone
+ return;
+ case AudioSystem.MODE_CURRENT:
+ case AudioSystem.MODE_INVALID:
+ default:
+ // don't know what to do in this case, better bail
+ return;
+ }
+
+ int streamType = getBluetoothContextualVolumeStream(mode);
+
+ // Currently, DEVICE_OUT_BLE_HEADSET is the only output type for LE_AUDIO profile.
+ // (See AudioDeviceBroker#createBtDeviceInfo())
+ int index = mStreamStates[streamType].getIndex(AudioSystem.DEVICE_OUT_BLE_HEADSET);
+ int maxIndex = mStreamStates[streamType].getMaxIndex();
+
+ if (DEBUG_VOL) {
+ Log.d(TAG, "setLeAudioVolumeOnModeUpdate postSetLeAudioVolumeIndex index="
+ + index + " maxIndex=" + maxIndex + " streamType=" + streamType);
+ }
+ mDeviceBroker.postSetLeAudioVolumeIndex(index, maxIndex, streamType);
+ }
+
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
String caller, String attributionTag, int uid,
boolean hasModifyAudioSettings) {
@@ -5276,6 +5306,10 @@ public class AudioService extends IAudioService.Stub
// change of mode may require volume to be re-applied on some devices
updateAbsVolumeMultiModeDevices(previousMode, mode);
+ // Forcefully set LE audio volume as a workaround, since the value of 'device'
+ // is not DEVICE_OUT_BLE_* even when BLE is connected.
+ setLeAudioVolumeOnModeUpdate(mode);
+
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
mDeviceBroker.postSetModeOwnerPid(pid, mode);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index e37a8e031c57..5e20dfbc7144 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -412,7 +412,7 @@ final class InputMethodUtils {
enabledSubtypes = SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
context.getResources(), imi);
}
- return InputMethodSubtype.sort(context, 0, imi, enabledSubtypes);
+ return InputMethodSubtype.sort(imi, enabledSubtypes);
}
List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(InputMethodInfo imi) {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index 371ef76b1ba6..b06af8e5a385 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -17,6 +17,7 @@
package com.android.server.locksettings;
import android.security.AndroidKeyStoreMaintenance;
+import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
@@ -210,10 +211,26 @@ public class SyntheticPasswordCrypto {
.setBoundToSpecificSecureUserId(sid)
.setUserAuthenticationValidityDurationSeconds(USER_AUTHENTICATION_VALIDITY);
}
+ final KeyProtection protNonRollbackResistant = builder.build();
+ builder.setRollbackResistant(true);
+ final KeyProtection protRollbackResistant = builder.build();
+ final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(keyStoreKey);
+ try {
+ keyStore.setEntry(keyAlias, entry, protRollbackResistant);
+ Slog.i(TAG, "Using rollback-resistant key");
+ } catch (KeyStoreException e) {
+ if (!(e.getCause() instanceof android.security.KeyStoreException)) {
+ throw e;
+ }
+ int errorCode = ((android.security.KeyStoreException) e.getCause()).getErrorCode();
+ if (errorCode != KeymasterDefs.KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE) {
+ throw e;
+ }
+ Slog.w(TAG, "Rollback-resistant keys unavailable. Falling back to "
+ + "non-rollback-resistant key");
+ keyStore.setEntry(keyAlias, entry, protNonRollbackResistant);
+ }
- keyStore.setEntry(keyAlias,
- new KeyStore.SecretKeyEntry(keyStoreKey),
- builder.build());
byte[] intermediate = encrypt(protectorSecret, PROTECTOR_SECRET_PERSONALIZATION, data);
return encrypt(keyStoreKey, intermediate);
} catch (CertificateException | IOException | BadPaddingException
diff --git a/services/core/java/com/android/server/pm/ApexPackageInfo.java b/services/core/java/com/android/server/pm/ApexPackageInfo.java
index f959a52f0374..73cb0ada6b87 100644
--- a/services/core/java/com/android/server/pm/ApexPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ApexPackageInfo.java
@@ -22,10 +22,9 @@ import static com.android.server.pm.ApexManager.MATCH_FACTORY_PACKAGE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.ArrayMap;
+import android.util.Pair;
import android.util.PrintWriterPrinter;
import com.android.internal.annotations.GuardedBy;
@@ -33,8 +32,9 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
@@ -59,16 +59,17 @@ class ApexPackageInfo {
private final Object mLock = new Object();
@GuardedBy("mLock")
- private List<PackageInfo> mAllPackagesCache;
+ private List<Pair<ApexInfo, AndroidPackage>> mAllPackagesCache;
- /**
- * Whether an APEX package is active or not.
- *
- * @param packageInfo the package to check
- * @return {@code true} if this package is active, {@code false} otherwise.
- */
- private static boolean isActive(PackageInfo packageInfo) {
- return packageInfo.isActiveApex;
+ @Nullable
+ private final PackageManagerService mPackageManager;
+
+ ApexPackageInfo() {
+ mPackageManager = null;
+ }
+
+ ApexPackageInfo(@NonNull PackageManagerService pms) {
+ mPackageManager = pms;
}
/**
@@ -105,20 +106,23 @@ class ApexPackageInfo {
* is not found.
*/
@Nullable
- PackageInfo getPackageInfo(String packageName, @ApexManager.PackageInfoFlags int flags) {
+ Pair<ApexInfo, AndroidPackage> getPackageInfo(String packageName,
+ @ApexManager.PackageInfoFlags int flags) {
synchronized (mLock) {
Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (!packageInfo.packageName.equals(packageName)) {
+ final Pair<ApexInfo, AndroidPackage> pair = mAllPackagesCache.get(i);
+ var apexInfo = pair.first;
+ var pkg = pair.second;
+ if (!pkg.getPackageName().equals(packageName)) {
continue;
}
- if ((matchActive && isActive(packageInfo))
- || (matchFactory && isFactory(packageInfo))) {
- return packageInfo;
+ if ((matchActive && apexInfo.isActive)
+ || (matchFactory && apexInfo.isFactory)) {
+ return pair;
}
}
return null;
@@ -128,18 +132,18 @@ class ApexPackageInfo {
/**
* Retrieves information about all active APEX packages.
*
- * @return a List of PackageInfo object, each one containing information about a different
- * active package.
+ * @return list containing information about different active packages.
*/
- List<PackageInfo> getActivePackages() {
+ @NonNull
+ List<Pair<ApexInfo, AndroidPackage>> getActivePackages() {
synchronized (mLock) {
Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
- final List<PackageInfo> activePackages = new ArrayList<>();
+ final List<Pair<ApexInfo, AndroidPackage>> activePackages = new ArrayList<>();
for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (isActive(packageInfo)) {
- activePackages.add(packageInfo);
+ final var pair = mAllPackagesCache.get(i);
+ if (pair.first.isActive) {
+ activePackages.add(pair);
}
}
return activePackages;
@@ -147,20 +151,20 @@ class ApexPackageInfo {
}
/**
- * Retrieves information about all active pre-installed APEX packages.
+ * Retrieves information about all pre-installed APEX packages.
*
- * @return a List of PackageInfo object, each one containing information about a different
- * active pre-installed package.
+ * @return list containing information about different pre-installed packages.
*/
- List<PackageInfo> getFactoryPackages() {
+ @NonNull
+ List<Pair<ApexInfo, AndroidPackage>> getFactoryPackages() {
synchronized (mLock) {
Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
- final List<PackageInfo> factoryPackages = new ArrayList<>();
+ final List<Pair<ApexInfo, AndroidPackage>> factoryPackages = new ArrayList<>();
for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (isFactory(packageInfo)) {
- factoryPackages.add(packageInfo);
+ final var pair = mAllPackagesCache.get(i);
+ if (pair.first.isFactory) {
+ factoryPackages.add(pair);
}
}
return factoryPackages;
@@ -170,18 +174,18 @@ class ApexPackageInfo {
/**
* Retrieves information about all inactive APEX packages.
*
- * @return a List of PackageInfo object, each one containing information about a different
- * inactive package.
+ * @return list containing information about different inactive packages.
*/
- List<PackageInfo> getInactivePackages() {
+ @NonNull
+ List<Pair<ApexInfo, AndroidPackage>> getInactivePackages() {
synchronized (mLock) {
Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
- final List<PackageInfo> inactivePackages = new ArrayList<>();
+ final List<Pair<ApexInfo, AndroidPackage>> inactivePackages = new ArrayList<>();
for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (!isActive(packageInfo)) {
- inactivePackages.add(packageInfo);
+ final var pair = mAllPackagesCache.get(i);
+ if (!pair.first.isActive) {
+ inactivePackages.add(pair);
}
}
return inactivePackages;
@@ -199,8 +203,8 @@ class ApexPackageInfo {
Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (packageInfo.packageName.equals(packageName)) {
+ final var pair = mAllPackagesCache.get(i);
+ if (pair.second.getPackageName().equals(packageName)) {
return true;
}
}
@@ -222,21 +226,18 @@ class ApexPackageInfo {
}
void notifyPackageInstalled(ApexInfo apexInfo, AndroidPackage pkg) {
- final int flags = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_SIGNATURES;
- final PackageInfo newApexPkg = PackageInfoWithoutStateUtils.generate(
- pkg, apexInfo, flags);
- final String packageName = newApexPkg.packageName;
+ final String packageName = pkg.getPackageName();
synchronized (mLock) {
for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- PackageInfo oldApexPkg = mAllPackagesCache.get(i);
- if (oldApexPkg.isActiveApex && oldApexPkg.packageName.equals(packageName)) {
- if (isFactory(oldApexPkg)) {
- oldApexPkg.isActiveApex = false;
- mAllPackagesCache.add(newApexPkg);
+ var pair = mAllPackagesCache.get(i);
+ var oldApexInfo = pair.first;
+ var oldApexPkg = pair.second;
+ if (oldApexInfo.isActive && oldApexPkg.getPackageName().equals(packageName)) {
+ if (oldApexInfo.isFactory) {
+ oldApexInfo.isActive = false;
+ mAllPackagesCache.add(Pair.create(apexInfo, pkg));
} else {
- mAllPackagesCache.set(i, newApexPkg);
+ mAllPackagesCache.set(i, Pair.create(apexInfo, pkg));
}
break;
}
@@ -245,16 +246,6 @@ class ApexPackageInfo {
}
/**
- * Whether the APEX package is pre-installed or not.
- *
- * @param packageInfo the package to check
- * @return {@code true} if this package is pre-installed, {@code false} otherwise.
- */
- private static boolean isFactory(@NonNull PackageInfo packageInfo) {
- return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0;
- }
-
- /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -288,33 +279,25 @@ class ApexPackageInfo {
HashSet<String> factoryPackagesSet = new HashSet<>();
for (ApexManager.ScanResult result : scanResults) {
ApexInfo ai = result.apexInfo;
-
- final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
- result.pkg, ai, flags);
- if (packageInfo == null) {
- throw new IllegalStateException("Unable to generate package info: "
- + ai.modulePath);
- }
- if (!packageInfo.packageName.equals(result.packageName)) {
+ String packageName = result.pkg.getPackageName();
+ if (!packageName.equals(result.packageName)) {
throw new IllegalStateException("Unmatched package name: "
- + result.packageName + " != " + packageInfo.packageName
+ + result.packageName + " != " + packageName
+ ", path=" + ai.modulePath);
}
- mAllPackagesCache.add(packageInfo);
+ mAllPackagesCache.add(Pair.create(ai, result.pkg));
if (ai.isActive) {
- if (!activePackagesSet.add(packageInfo.packageName)) {
+ if (!activePackagesSet.add(packageName)) {
throw new IllegalStateException(
- "Two active packages have the same name: "
- + packageInfo.packageName);
+ "Two active packages have the same name: " + packageName);
}
}
if (ai.isFactory) {
// Don't throw when the duplicating APEX is VNDK APEX
- if (!factoryPackagesSet.add(packageInfo.packageName)
+ if (!factoryPackagesSet.add(packageName)
&& !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) {
throw new IllegalStateException(
- "Two factory packages have the same name: "
- + packageInfo.packageName);
+ "Two factory packages have the same name: " + packageName);
}
}
}
@@ -348,6 +331,13 @@ class ApexPackageInfo {
if (throwable == null) {
// Calling hideAsFinal to assign derived fields for the app info flags.
parseResult.parsedPackage.hideAsFinal();
+
+ // TODO: When ENABLE_FEATURE_SCAN_APEX is finalized, remove this and the entire
+ // calling path code
+ ScanPackageUtils.applyPolicy(parseResult.parsedPackage,
+ PackageManagerService.SCAN_AS_SYSTEM,
+ mPackageManager == null ? null : mPackageManager.getPlatformPackage(),
+ false);
results.add(new ApexManager.ScanResult(
ai, parseResult.parsedPackage, parseResult.parsedPackage.getPackageName()));
} else if (throwable instanceof PackageManagerException) {
@@ -363,34 +353,69 @@ class ApexPackageInfo {
}
/**
+ * @see #dumpPackages(List, String, IndentingPrintWriter)
+ */
+ static void dumpPackageStates(List<PackageStateInternal> packageStates, boolean isActive,
+ @Nullable String packageName, IndentingPrintWriter ipw) {
+ ipw.println();
+ ipw.increaseIndent();
+ for (int i = 0, size = packageStates.size(); i < size; i++) {
+ final var packageState = packageStates.get(i);
+ var pkg = packageState.getPkg();
+ if (packageName != null && !packageName.equals(pkg.getPackageName())) {
+ continue;
+ }
+ ipw.println(pkg.getPackageName());
+ ipw.increaseIndent();
+ ipw.println("Version: " + pkg.getLongVersionCode());
+ ipw.println("Path: " + pkg.getBaseApkPath());
+ ipw.println("IsActive: " + isActive);
+ ipw.println("IsFactory: " + !packageState.isUpdatedSystemApp());
+ ipw.println("ApplicationInfo: ");
+ ipw.increaseIndent();
+ // TODO: Dump the package manually
+ AndroidPackageUtils.generateAppInfoWithoutState(pkg)
+ .dump(new PrintWriterPrinter(ipw), "");
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ }
+ ipw.decreaseIndent();
+ ipw.println();
+ }
+
+ /**
* Dump information about the packages contained in a particular cache
* @param packagesCache the cache to print information about.
* @param packageName a {@link String} containing a package name, or {@code null}. If set,
* only information about that specific package will be dumped.
* @param ipw the {@link IndentingPrintWriter} object to send information to.
*/
- static void dumpPackages(List<PackageInfo> packagesCache,
+ static void dumpPackages(List<Pair<ApexInfo, AndroidPackage>> packagesCache,
@Nullable String packageName, IndentingPrintWriter ipw) {
ipw.println();
ipw.increaseIndent();
for (int i = 0, size = packagesCache.size(); i < size; i++) {
- final PackageInfo pi = packagesCache.get(i);
- if (packageName != null && !packageName.equals(pi.packageName)) {
+ final var pair = packagesCache.get(i);
+ var apexInfo = pair.first;
+ var pkg = pair.second;
+ if (packageName != null && !packageName.equals(pkg.getPackageName())) {
continue;
}
- ipw.println(pi.packageName);
+ ipw.println(pkg.getPackageName());
ipw.increaseIndent();
- ipw.println("Version: " + pi.versionCode);
- ipw.println("Path: " + pi.applicationInfo.sourceDir);
- ipw.println("IsActive: " + isActive(pi));
- ipw.println("IsFactory: " + isFactory(pi));
+ ipw.println("Version: " + pkg.getLongVersionCode());
+ ipw.println("Path: " + pkg.getBaseApkPath());
+ ipw.println("IsActive: " + apexInfo.isActive);
+ ipw.println("IsFactory: " + apexInfo.isFactory);
ipw.println("ApplicationInfo: ");
ipw.increaseIndent();
- pi.applicationInfo.dump(new PrintWriterPrinter(ipw), "");
+ // TODO: Dump the package manually
+ AndroidPackageUtils.generateAppInfoWithoutState(pkg)
+ .dump(new PrintWriterPrinter(ipw), "");
ipw.decreaseIndent();
ipw.decreaseIndent();
}
ipw.decreaseIndent();
ipw.println();
}
-}
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 63c25ea520f7..8ec3d2bc74ca 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -65,6 +65,7 @@ import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.apex.ApexInfo;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -1018,11 +1019,12 @@ public class ComputerEngine implements Computer {
if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
apexFlags = ApexManager.MATCH_FACTORY_PACKAGE;
}
- final PackageInfo pi = mApexPackageInfo.getPackageInfo(packageName, apexFlags);
- if (pi == null) {
+ final var pair = mApexPackageInfo.getPackageInfo(packageName, apexFlags);
+ if (pair == null) {
return null;
}
- return pi.applicationInfo;
+ return PackageInfoUtils.generateApplicationInfo(pair.second, flags,
+ PackageUserStateInternal.DEFAULT, userId, null);
}
}
if ("android".equals(packageName) || "system".equals(packageName)) {
@@ -1718,8 +1720,12 @@ public class ComputerEngine implements Computer {
// Instant app filtering for APEX modules is ignored
if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
if (matchApex) {
- return mApexPackageInfo.getPackageInfo(packageName,
+ final var pair = mApexPackageInfo.getPackageInfo(packageName,
ApexManager.MATCH_FACTORY_PACKAGE);
+ if (pair == null) {
+ return null;
+ }
+ return PackageInfoUtils.generate(pair.second, pair.first, flags, null, userId);
}
}
final PackageStateInternal ps = mSettings.getDisabledSystemPkg(packageName);
@@ -1775,8 +1781,12 @@ public class ComputerEngine implements Computer {
}
if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
if (matchApex) {
- return mApexPackageInfo.getPackageInfo(packageName,
+ final var pair = mApexPackageInfo.getPackageInfo(packageName,
ApexManager.MATCH_ACTIVE_PACKAGE);
+ if (pair == null) {
+ return null;
+ }
+ return PackageInfoUtils.generate(pair.second, pair.first, flags, null, userId);
}
}
return null;
@@ -1883,10 +1893,17 @@ public class ComputerEngine implements Computer {
}
if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
if (listApex) {
+ List<Pair<ApexInfo, AndroidPackage>> pairs;
if (listFactory) {
- list.addAll(mApexPackageInfo.getFactoryPackages());
+ pairs = mApexPackageInfo.getFactoryPackages();
} else {
- list.addAll(mApexPackageInfo.getActivePackages());
+ pairs = mApexPackageInfo.getActivePackages();
+ }
+
+ for (int index = 0; index < pairs.size(); index++) {
+ var pair = pairs.get(index);
+ list.add(PackageInfoUtils.generate(pair.second, pair.first, flags, null,
+ userId));
}
}
}
@@ -3404,29 +3421,23 @@ public class ComputerEngine implements Computer {
} // switch
}
- private void generateApexPackageInfo(List<PackageInfo> activePackages,
- List<PackageInfo> inactivePackages, List<PackageInfo> factoryPackages) {
+ private void generateApexPackageInfo(@NonNull List<PackageStateInternal> activePackages,
+ @NonNull List<PackageStateInternal> inactivePackages,
+ @NonNull List<PackageStateInternal> factoryActivePackages,
+ @NonNull List<PackageStateInternal> factoryInactivePackages) {
for (AndroidPackage p : mPackages.values()) {
final String packageName = p.getPackageName();
PackageStateInternal ps = mSettings.getPackage(packageName);
if (!p.isApex() || ps == null) {
continue;
}
- PackageInfo pi = generatePackageInfo(ps, 0, 0);
- if (pi == null) {
- continue;
- }
- pi.isActiveApex = true;
- activePackages.add(pi);
+ activePackages.add(ps);
if (!ps.isUpdatedSystemApp()) {
- factoryPackages.add(pi);
+ factoryActivePackages.add(ps);
} else {
PackageStateInternal psDisabled = mSettings.getDisabledSystemPkg(packageName);
- pi = generatePackageInfo(psDisabled, 0, 0);
- if (pi != null) {
- factoryPackages.add(pi);
- inactivePackages.add(pi);
- }
+ factoryInactivePackages.add(psDisabled);
+ inactivePackages.add(psDisabled);
}
}
}
@@ -3434,16 +3445,19 @@ public class ComputerEngine implements Computer {
private void dumpApex(PrintWriter pw, String packageName) {
if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- List<PackageInfo> activePackages = new ArrayList<>();
- List<PackageInfo> inactivePackages = new ArrayList<>();
- List<PackageInfo> factoryPackages = new ArrayList<>();
- generateApexPackageInfo(activePackages, inactivePackages, factoryPackages);
+ List<PackageStateInternal> activePackages = new ArrayList<>();
+ List<PackageStateInternal> inactivePackages = new ArrayList<>();
+ List<PackageStateInternal> factoryActivePackages = new ArrayList<>();
+ List<PackageStateInternal> factoryInactivePackages = new ArrayList<>();
+ generateApexPackageInfo(activePackages, inactivePackages, factoryActivePackages,
+ factoryInactivePackages);
ipw.println("Active APEX packages:");
- ApexPackageInfo.dumpPackages(activePackages, packageName, ipw);
+ ApexPackageInfo.dumpPackageStates(activePackages, true, packageName, ipw);
ipw.println("Inactive APEX packages:");
- ApexPackageInfo.dumpPackages(inactivePackages, packageName, ipw);
+ ApexPackageInfo.dumpPackageStates(inactivePackages, false, packageName, ipw);
ipw.println("Factory APEX packages:");
- ApexPackageInfo.dumpPackages(factoryPackages, packageName, ipw);
+ ApexPackageInfo.dumpPackageStates(factoryActivePackages, true, packageName, ipw);
+ ApexPackageInfo.dumpPackageStates(factoryInactivePackages, false, packageName, ipw);
} else {
mApexPackageInfo.dump(pw, packageName);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2bdf62bdd707..32b3e6a4ab76 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1611,7 +1611,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mSharedLibraries = injector.getSharedLibrariesImpl();
mApexManager = testParams.apexManager;
- mApexPackageInfo = new ApexPackageInfo();
+ mApexPackageInfo = new ApexPackageInfo(this);
mArtManagerService = testParams.artManagerService;
mAvailableFeatures = testParams.availableFeatures;
mBackgroundDexOptService = testParams.backgroundDexOptService;
@@ -1811,7 +1811,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = injector.getApexManager();
- mApexPackageInfo = new ApexPackageInfo();
+ mApexPackageInfo = new ApexPackageInfo(this);
mAppsFilter = mInjector.getAppsFilter();
mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager,
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 0e57c917a72b..86affdd75481 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -823,8 +823,8 @@ final class ScanPackageUtils {
* ideally be static, but, it requires locks to read system state.
*/
public static void applyPolicy(ParsedPackage parsedPackage,
- final @PackageManagerService.ScanFlags int scanFlags, AndroidPackage platformPkg,
- boolean isUpdatedSystemApp) {
+ final @PackageManagerService.ScanFlags int scanFlags,
+ @Nullable AndroidPackage platformPkg, boolean isUpdatedSystemApp) {
if ((scanFlags & SCAN_AS_SYSTEM) != 0) {
parsedPackage.setSystem(true);
// TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 937b2cf047a4..b57d4d55b6eb 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -219,38 +219,21 @@ class UserSystemPackageInstaller {
// Install/uninstall system packages per user.
for (int userId : mUm.getUserIds()) {
- final Set<String> userWhitelist = getInstallablePackagesForUserId(userId);
-
- // If null, run for all packages
- if (userWhitelist == null) {
- pmInt.forEachPackageState(packageState -> {
- if (packageState.getPkg() == null) {
- return;
- }
- final boolean install = !packageState.getTransientState()
- .isHiddenUntilInstalled();
- if (packageState.getUserStateOrDefault(userId).isInstalled() != install
- && shouldChangeInstallationState(packageState, install, userId,
- isFirstBoot, isConsideredUpgrade, preExistingPackages)) {
- changesToCommit.add(userId, packageState.getPackageName(), install);
- }
- });
- } else {
- for (String packageName : userWhitelist) {
- PackageStateInternal packageState = pmInt.getPackageStateInternal(packageName);
- if (packageState.getPkg() == null) {
- continue;
- }
-
- final boolean install = !packageState.getTransientState()
- .isHiddenUntilInstalled();
- if (packageState.getUserStateOrDefault(userId).isInstalled() != install
- && shouldChangeInstallationState(packageState, install, userId,
- isFirstBoot, isConsideredUpgrade, preExistingPackages)) {
- changesToCommit.add(userId, packageState.getPackageName(), install);
- }
+ final Set<String> userAllowlist = getInstallablePackagesForUserId(userId);
+
+ pmInt.forEachPackageState(packageState -> {
+ if (packageState.getPkg() == null) {
+ return;
}
- }
+ boolean install = (userAllowlist == null
+ || userAllowlist.contains(packageState.getPackageName()))
+ && !packageState.getTransientState().isHiddenUntilInstalled();
+ if (packageState.getUserStateOrDefault(userId).isInstalled() != install
+ && shouldChangeInstallationState(packageState, install, userId,
+ isFirstBoot, isConsideredUpgrade, preExistingPackages)) {
+ changesToCommit.add(userId, packageState.getPackageName(), install);
+ }
+ });
}
pmInt.commitPackageStateMutation(null, packageStateMutator -> {
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 9c620c4ff3ab..a44def8f772a 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -93,12 +93,14 @@ public class PackageInfoUtils {
/**
* @param pkgSetting See {@link PackageInfoUtils} for description of pkgSetting usage.
+ * @deprecated Once ENABLE_FEATURE_SCAN_APEX is removed, this should also be removed.
*/
+ @Deprecated
@Nullable
- public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, int flags,
- @Nullable PackageStateInternal pkgSetting) {
+ public static PackageInfo generate(AndroidPackage pkg, ApexInfo apexInfo, long flags,
+ @Nullable PackageStateInternal pkgSetting, @UserIdInt int userId) {
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
- PackageUserStateInternal.DEFAULT, UserHandle.getCallingUserId(), apexInfo, pkgSetting);
+ PackageUserStateInternal.DEFAULT, userId, apexInfo, pkgSetting);
}
/**
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index b91f15a4d037..748d32894d8a 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import com.android.server.pm.pkg.SELinuxUtil;
import android.content.pm.SigningDetails;
import android.content.res.TypedArray;
import android.os.Environment;
@@ -35,6 +34,7 @@ import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.pkg.SELinuxUtil;
import com.android.server.pm.pkg.component.ComponentMutateUtils;
import com.android.server.pm.pkg.component.ParsedActivity;
import com.android.server.pm.pkg.component.ParsedProvider;
@@ -255,7 +255,7 @@ public class PackageImpl extends ParsingPackageImpl implements ParsedPackage, An
}
@Override
- public PackageImpl setSigningDetails(@Nullable SigningDetails value) {
+ public PackageImpl setSigningDetails(@NonNull SigningDetails value) {
super.setSigningDetails(value);
return this;
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 40f859c5e82e..b7b37b2630f7 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -334,7 +334,7 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setSharedUserLabel(int sharedUserLabel);
- ParsingPackage setSigningDetails(SigningDetails signingDetails);
+ ParsingPackage setSigningDetails(@NonNull SigningDetails signingDetails);
ParsingPackage setSplitClassLoaderName(int splitIndex, String classLoaderName);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 6a4513d45d8f..803780fe2a9b 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -317,8 +317,8 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
protected String volumeUuid;
- @Nullable
- private SigningDetails signingDetails;
+ @NonNull
+ private SigningDetails signingDetails = SigningDetails.UNKNOWN;
@NonNull
@DataClass.ParcelWith(ForInternedString.class)
@@ -1873,7 +1873,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
return volumeUuid;
}
- @Nullable
+ @NonNull
@Override
public SigningDetails getSigningDetails() {
return signingDetails;
@@ -2474,7 +2474,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
- public ParsingPackageImpl setSigningDetails(@Nullable SigningDetails value) {
+ public ParsingPackageImpl setSigningDetails(@NonNull SigningDetails value) {
signingDetails = value;
return this;
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 20b1ed8d0c3e..22729993af64 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -188,6 +188,7 @@ public interface ParsingPackageRead extends PkgWithoutStateAppInfo, PkgWithoutSt
* The signature data of all APKs in this package, which must be exactly the same across the
* base and splits.
*/
+ @NonNull
SigningDetails getSigningDetails();
/**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 69bbff3a4db1..42e0533f178f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -272,7 +272,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConstrainDisplayApisConfig;
import android.content.pm.PackageManager;
-import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -478,7 +477,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private int mLastReportedDisplayId;
boolean mLastReportedMultiWindowMode;
boolean mLastReportedPictureInPictureMode;
- CompatibilityInfo compat;// last used compatibility mode
ActivityRecord resultTo; // who started this entry, so will get our reply
final String resultWho; // additional identifier for use by resultTo.
final int requestCode; // code given by requester (resultTo)
@@ -1022,7 +1020,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (rootVoiceInteraction) {
pw.print(prefix); pw.print("rootVoiceInteraction="); pw.println(rootVoiceInteraction);
}
- pw.print(prefix); pw.print("compat="); pw.print(compat);
+ pw.print(prefix); pw.print("compat=");
+ pw.print(mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo));
pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 84740683f6aa..345ec117b03a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -875,7 +875,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY);
r.forceNewConfig = false;
mService.getAppWarningsLocked().onStartActivity(r);
- r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo);
// Because we could be starting an Activity in the system process this may not go
// across a Binder interface which would create a new Configuration. Consequently
@@ -905,7 +904,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
- mergedConfiguration.getOverrideConfiguration(), r.compat,
+ mergedConfiguration.getOverrideConfiguration(),
r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeOptions(), isTransitionForward,
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3ef4aaeffd0c..366ca3b25130 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -137,7 +137,6 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITIO
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.WINDOW;
@@ -4957,10 +4956,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|| isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
}
- boolean isExitAnimationRunningSelfOrChild() {
- return isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION);
- }
-
private boolean shouldFinishAnimatingExit() {
// Exit animation might be applied soon.
if (inTransition()) {
@@ -5916,6 +5911,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (!super.prepareSync()) {
return false;
}
+ if (mIsWallpaper) {
+ // TODO(b/233286785): Add sync support to wallpaper.
+ return false;
+ }
// In the WindowContainer implementation we immediately mark ready
// since a generic WindowContainer only needs to wait for its
// children to finish and is immediately ready from its own
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index 721777ca6b38..13510adbb960 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -30,6 +30,7 @@ import android.content.pm.PackageInfo;
import android.os.UserHandle;
import android.util.Log;
import android.util.SparseArrayMap;
+import android.util.SparseLongArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -174,10 +175,13 @@ public class ScribeTest {
when(mIrs.getConsumptionLimitLocked()).thenReturn(consumptionLimit);
Ledger ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- ledger.recordTransaction(new Ledger.Transaction(0, 1000L, 1, null, 2000, 0));
+ ledger.recordTransaction(
+ new Ledger.Transaction(0, 1000L, EconomicPolicy.TYPE_REWARD | 1, null, 2000, 0));
// Negative ledger balance shouldn't affect the total circulation value.
ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID + 1, TEST_PACKAGE);
- ledger.recordTransaction(new Ledger.Transaction(0, 1000L, 1, null, -5000, 3000));
+ ledger.recordTransaction(
+ new Ledger.Transaction(0, 1000L,
+ EconomicPolicy.TYPE_ACTION | 1, null, -5000, 3000));
mScribeUnderTest.setLastReclamationTimeLocked(lastReclamationTime);
mScribeUnderTest.setConsumptionLimitLocked(consumptionLimit);
mScribeUnderTest.adjustRemainingConsumableCakesLocked(
@@ -209,9 +213,13 @@ public class ScribeTest {
@Test
public void testWritingPopulatedLedgerToDisk() {
final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51, 0));
- ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52, -1));
- ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3, 12));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD | 1, null, 51, 0));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(1500, 2000,
+ EconomicPolicy.TYPE_REWARD | 2, "green", 52, -1));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(2500, 3000, EconomicPolicy.TYPE_REWARD | 3, "blue", 3, 12));
mScribeUnderTest.writeImmediatelyForTesting();
mScribeUnderTest.loadFromDiskLocked();
@@ -230,11 +238,13 @@ public class ScribeTest {
addInstalledPackage(userId, pkgName);
final Ledger ledger = mScribeUnderTest.getLedgerLocked(userId, pkgName);
ledger.recordTransaction(new Ledger.Transaction(
- 0, 1000L * u + l, 1, null, -51L * u + l, 50));
+ 0, 1000L * u + l, EconomicPolicy.TYPE_ACTION | 1, null, -51L * u + l, 50));
ledger.recordTransaction(new Ledger.Transaction(
- 1500L * u + l, 2000L * u + l, 2 * u + l, "green" + u + l, 52L * u + l, 0));
+ 1500L * u + l, 2000L * u + l,
+ EconomicPolicy.TYPE_REWARD | 2 * u + l, "green" + u + l, 52L * u + l, 0));
ledger.recordTransaction(new Ledger.Transaction(
- 2500L * u + l, 3000L * u + l, 3 * u + l, "blue" + u + l, 3L * u + l, 0));
+ 2500L * u + l, 3000L * u + l,
+ EconomicPolicy.TYPE_REWARD | 3 * u + l, "blue" + u + l, 3L * u + l, 0));
ledgers.add(userId, pkgName, ledger);
}
}
@@ -248,9 +258,12 @@ public class ScribeTest {
@Test
public void testDiscardLedgerFromDisk() {
final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
- ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51, 1));
- ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52, 0));
- ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3, 1));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD | 1, null, 51, 1));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(1500, 2000, EconomicPolicy.TYPE_REWARD | 2, "green", 52, 0));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(2500, 3000, EconomicPolicy.TYPE_REWARD | 3, "blue", 3, 1));
mScribeUnderTest.writeImmediatelyForTesting();
mScribeUnderTest.loadFromDiskLocked();
@@ -269,9 +282,12 @@ public class ScribeTest {
public void testLoadingMissingPackageFromDisk() {
final String pkgName = TEST_PACKAGE + ".uninstalled";
final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, pkgName);
- ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51, 1));
- ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52, 2));
- ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3, 3));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REGULATION | 1, null, 51, 1));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(1500, 2000, EconomicPolicy.TYPE_REWARD | 2, "green", 52, 2));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(2500, 3000, EconomicPolicy.TYPE_ACTION | 3, "blue", -3, 3));
mScribeUnderTest.writeImmediatelyForTesting();
// Package isn't installed, so make sure it's not saved to memory after loading.
@@ -283,9 +299,13 @@ public class ScribeTest {
public void testLoadingMissingUserFromDisk() {
final int userId = TEST_USER_ID + 1;
final Ledger ogLedger = mScribeUnderTest.getLedgerLocked(userId, TEST_PACKAGE);
- ogLedger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 51, 0));
- ogLedger.recordTransaction(new Ledger.Transaction(1500, 2000, 2, "green", 52, 1));
- ogLedger.recordTransaction(new Ledger.Transaction(2500, 3000, 3, "blue", 3, 3));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(0, 1000, EconomicPolicy.TYPE_REWARD | 1, null, 51, 0));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(1500, 2000, EconomicPolicy.TYPE_REWARD | 2, "green", 52, 1));
+ ogLedger.recordTransaction(
+ new Ledger.Transaction(2500, 3000,
+ EconomicPolicy.TYPE_REGULATION | 3, "blue", 3, 3));
mScribeUnderTest.writeImmediatelyForTesting();
// User doesn't show up with any packages, so make sure nothing is saved after loading.
@@ -331,12 +351,34 @@ public class ScribeTest {
}
assertNotNull(actual);
assertEquals(expected.getCurrentBalance(), actual.getCurrentBalance());
+
List<Ledger.Transaction> expectedTransactions = expected.getTransactions();
List<Ledger.Transaction> actualTransactions = actual.getTransactions();
assertEquals(expectedTransactions.size(), actualTransactions.size());
for (int i = 0; i < expectedTransactions.size(); ++i) {
assertTransactionsEqual(expectedTransactions.get(i), actualTransactions.get(i));
}
+
+ List<Ledger.RewardBucket> expectedRewardBuckets = expected.getRewardBuckets();
+ List<Ledger.RewardBucket> actualRewardBuckets = actual.getRewardBuckets();
+ assertEquals(expectedRewardBuckets.size(), actualRewardBuckets.size());
+ for (int i = 0; i < expectedRewardBuckets.size(); ++i) {
+ assertRewardBucketsEqual(expectedRewardBuckets.get(i), actualRewardBuckets.get(i));
+ }
+ }
+
+ private void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
+ if (expected == null) {
+ assertNull(actual);
+ return;
+ }
+ assertNotNull(actual);
+ final int size = expected.size();
+ assertEquals(size, actual.size());
+ for (int i = 0; i < size; ++i) {
+ assertEquals(expected.keyAt(i), actual.keyAt(i));
+ assertEquals(expected.valueAt(i), actual.valueAt(i));
+ }
}
private void assertReportListsEqual(List<Analyst.Report> expected,
@@ -382,6 +424,17 @@ public class ScribeTest {
}
}
+ private void assertRewardBucketsEqual(Ledger.RewardBucket expected,
+ Ledger.RewardBucket actual) {
+ if (expected == null) {
+ assertNull(actual);
+ return;
+ }
+ assertNotNull(actual);
+ assertEquals(expected.startTimeMs, actual.startTimeMs);
+ assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
+ }
+
private void assertTransactionsEqual(Ledger.Transaction expected, Ledger.Transaction actual) {
if (expected == null) {
assertNull(actual);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 20482afd53ac..503ca69a627f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -36,8 +36,6 @@ import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams;
import android.apex.IApexService;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -93,16 +91,16 @@ public class ApexManagerTest {
ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
apexPackageInfo.scanApexPackages(
apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- final PackageInfo activePkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
+ final var activePair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_ACTIVE_PACKAGE);
- assertThat(activePkgPi).isNotNull();
- assertThat(activePkgPi.packageName).contains(TEST_APEX_PKG);
+ assertThat(activePair).isNotNull();
+ assertThat(activePair.second.getPackageName()).contains(TEST_APEX_PKG);
- final PackageInfo factoryPkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
+ final var factoryPair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_FACTORY_PACKAGE);
- assertThat(factoryPkgPi).isNull();
+ assertThat(factoryPair).isNull();
}
@Test
@@ -111,16 +109,16 @@ public class ApexManagerTest {
ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
apexPackageInfo.scanApexPackages(
apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- PackageInfo factoryPkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
+ var factoryPair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_FACTORY_PACKAGE);
- assertThat(factoryPkgPi).isNotNull();
- assertThat(factoryPkgPi.packageName).contains(TEST_APEX_PKG);
+ assertThat(factoryPair).isNotNull();
+ assertThat(factoryPair.second.getPackageName()).contains(TEST_APEX_PKG);
- final PackageInfo activePkgPi = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
+ final var activePair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
ApexManager.MATCH_ACTIVE_PACKAGE);
- assertThat(activePkgPi).isNull();
+ assertThat(activePair).isNull();
}
@Test
@@ -388,23 +386,16 @@ public class ApexManagerTest {
newApexInfo = mApexManager.installPackage(installedApex);
apexPackageInfo.notifyPackageInstalled(newApexInfo, mPackageParser2);
- PackageInfo newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
+ var newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_ACTIVE_PACKAGE);
- assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
- assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
- assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)
- .isEqualTo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
- assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
- .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
-
- PackageInfo factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
+ assertThat(newInfo.second.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
+ assertThat(newInfo.second.getLongVersionCode()).isEqualTo(2);
+
+ var factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_FACTORY_PACKAGE);
- assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(activeApexInfo.modulePath);
- assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
- assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
- .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
- assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
- .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(factoryInfo.second.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath);
+ assertThat(factoryInfo.second.getLongVersionCode()).isEqualTo(1);
+ assertThat(factoryInfo.second.isSystem()).isTrue();
}
@Test
@@ -429,23 +420,16 @@ public class ApexManagerTest {
newApexInfo = mApexManager.installPackage(installedApex);
apexPackageInfo.notifyPackageInstalled(newApexInfo, mPackageParser2);
- PackageInfo newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
+ var newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_ACTIVE_PACKAGE);
- assertThat(newInfo.applicationInfo.sourceDir).isEqualTo(finalApex.getAbsolutePath());
- assertThat(newInfo.applicationInfo.longVersionCode).isEqualTo(2);
- assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)
- .isEqualTo(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
- assertThat(newInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
- .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
-
- PackageInfo factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
+ assertThat(newInfo.second.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
+ assertThat(newInfo.second.getLongVersionCode()).isEqualTo(2);
+
+ var factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
ApexManager.MATCH_FACTORY_PACKAGE);
- assertThat(factoryInfo.applicationInfo.sourceDir).isEqualTo(factoryApexInfo.modulePath);
- assertThat(factoryInfo.applicationInfo.longVersionCode).isEqualTo(1);
- assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
- .isEqualTo(ApplicationInfo.FLAG_SYSTEM);
- assertThat(factoryInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)
- .isEqualTo(ApplicationInfo.FLAG_INSTALLED);
+ assertThat(factoryInfo.second.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath);
+ assertThat(factoryInfo.second.getLongVersionCode()).isEqualTo(1);
+ assertThat(factoryInfo.second.isSystem()).isTrue();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
index 22dcf842906c..54566c39a8d2 100644
--- a/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
+++ b/services/tests/servicestests/src/com/android/server/tare/LedgerTest.java
@@ -22,7 +22,12 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static com.android.server.tare.TareUtils.getCurrentTimeMillis;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.util.SparseLongArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -32,7 +37,10 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Clock;
+import java.time.Duration;
import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.List;
/** Test that the ledger records transactions correctly. */
@RunWith(AndroidJUnit4.class)
@@ -44,6 +52,11 @@ public class LedgerTest {
TareUtils.sSystemClock = Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
}
+ private void shiftSystemTime(long incrementMs) {
+ TareUtils.sSystemClock =
+ Clock.offset(TareUtils.sSystemClock, Duration.ofMillis(incrementMs));
+ }
+
@Test
public void testInitialState() {
final Ledger ledger = new Ledger();
@@ -52,37 +65,149 @@ public class LedgerTest {
}
@Test
+ public void testInitialization_FullLists() {
+ final long balance = 1234567890L;
+ List<Ledger.Transaction> transactions = new ArrayList<>();
+ List<Ledger.RewardBucket> rewardBuckets = new ArrayList<>();
+
+ final long now = getCurrentTimeMillis();
+ Ledger.Transaction secondTxn = null;
+ Ledger.RewardBucket remainingBucket = null;
+ for (int i = 0; i < Ledger.MAX_TRANSACTION_COUNT; ++i) {
+ final long start = now - 10 * HOUR_IN_MILLIS + i * MINUTE_IN_MILLIS;
+ Ledger.Transaction transaction = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
+ if (i == 1) {
+ secondTxn = transaction;
+ }
+ transactions.add(transaction);
+ }
+ for (int b = 0; b < Ledger.NUM_REWARD_BUCKET_WINDOWS; ++b) {
+ final long start = now - (Ledger.NUM_REWARD_BUCKET_WINDOWS - b) * 24 * HOUR_IN_MILLIS;
+ Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
+ rewardBucket.startTimeMs = start;
+ for (int r = 0; r < 5; ++r) {
+ rewardBucket.cumulativeDelta.put(EconomicPolicy.TYPE_REWARD | r, b * start + r);
+ }
+ if (b == Ledger.NUM_REWARD_BUCKET_WINDOWS - 1) {
+ remainingBucket = rewardBucket;
+ }
+ rewardBuckets.add(rewardBucket);
+ }
+ final Ledger ledger = new Ledger(balance, transactions, rewardBuckets);
+ assertEquals(balance, ledger.getCurrentBalance());
+ assertEquals(transactions, ledger.getTransactions());
+ // Everything but the last bucket is old, so the returned list should only contain that
+ // bucket.
+ rewardBuckets.clear();
+ rewardBuckets.add(remainingBucket);
+ assertEquals(rewardBuckets, ledger.getRewardBuckets());
+
+ // Make sure the ledger can properly record new transactions.
+ final long start = now - MINUTE_IN_MILLIS;
+ final long delta = 400;
+ final Ledger.Transaction transaction = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, EconomicPolicy.TYPE_REWARD | 1, null, delta, 0);
+ ledger.recordTransaction(transaction);
+ assertEquals(balance + delta, ledger.getCurrentBalance());
+ transactions = ledger.getTransactions();
+ assertEquals(secondTxn, transactions.get(0));
+ assertEquals(transaction, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 1));
+ final Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
+ rewardBucket.startTimeMs = now;
+ rewardBucket.cumulativeDelta.put(EconomicPolicy.TYPE_REWARD | 1, delta);
+ rewardBuckets = ledger.getRewardBuckets();
+ assertRewardBucketsEqual(remainingBucket, rewardBuckets.get(0));
+ assertRewardBucketsEqual(rewardBucket, rewardBuckets.get(1));
+ }
+
+ @Test
+ public void testInitialization_OverflowingLists() {
+ final long balance = 1234567890L;
+ final List<Ledger.Transaction> transactions = new ArrayList<>();
+ final List<Ledger.RewardBucket> rewardBuckets = new ArrayList<>();
+
+ final long now = getCurrentTimeMillis();
+ for (int i = 0; i < 2 * Ledger.MAX_TRANSACTION_COUNT; ++i) {
+ final long start = now - 20 * HOUR_IN_MILLIS + i * MINUTE_IN_MILLIS;
+ Ledger.Transaction transaction = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
+ transactions.add(transaction);
+ }
+ for (int b = 0; b < 2 * Ledger.NUM_REWARD_BUCKET_WINDOWS; ++b) {
+ final long start = now
+ - (2 * Ledger.NUM_REWARD_BUCKET_WINDOWS - b) * 6 * HOUR_IN_MILLIS;
+ Ledger.RewardBucket rewardBucket = new Ledger.RewardBucket();
+ rewardBucket.startTimeMs = start;
+ for (int r = 0; r < 5; ++r) {
+ rewardBucket.cumulativeDelta.put(EconomicPolicy.TYPE_REWARD | r, b * start + r);
+ }
+ rewardBuckets.add(rewardBucket);
+ }
+ final Ledger ledger = new Ledger(balance, transactions, rewardBuckets);
+ assertEquals(balance, ledger.getCurrentBalance());
+ assertEquals(transactions.subList(Ledger.MAX_TRANSACTION_COUNT,
+ 2 * Ledger.MAX_TRANSACTION_COUNT),
+ ledger.getTransactions());
+ assertEquals(rewardBuckets.subList(Ledger.NUM_REWARD_BUCKET_WINDOWS,
+ 2 * Ledger.NUM_REWARD_BUCKET_WINDOWS),
+ ledger.getRewardBuckets());
+ }
+
+ @Test
public void testMultipleTransactions() {
final Ledger ledger = new Ledger();
ledger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 5, 0));
assertEquals(5, ledger.getCurrentBalance());
- assertEquals(5, ledger.get24HourSum(1, 60_000));
ledger.recordTransaction(new Ledger.Transaction(2000, 2000, 1, null, 25, 0));
assertEquals(30, ledger.getCurrentBalance());
- assertEquals(30, ledger.get24HourSum(1, 60_000));
ledger.recordTransaction(new Ledger.Transaction(5000, 5500, 1, null, -10, 5));
assertEquals(20, ledger.getCurrentBalance());
- assertEquals(20, ledger.get24HourSum(1, 60_000));
}
@Test
public void test24HourSum() {
+ final long now = getCurrentTimeMillis();
+ final long end = now + 24 * HOUR_IN_MILLIS;
+ final int reward1 = EconomicPolicy.TYPE_REWARD | 1;
+ final int reward2 = EconomicPolicy.TYPE_REWARD | 2;
final Ledger ledger = new Ledger();
- ledger.recordTransaction(new Ledger.Transaction(0, 1000, 1, null, 500, 0));
- assertEquals(500, ledger.get24HourSum(1, 24 * HOUR_IN_MILLIS));
+
+ // First bucket
+ assertEquals(0, ledger.get24HourSum(reward1, end));
+ ledger.recordTransaction(new Ledger.Transaction(now, now + 1000, reward1, null, 500, 0));
+ assertEquals(500, ledger.get24HourSum(reward1, end));
+ assertEquals(0, ledger.get24HourSum(reward2, end));
+ ledger.recordTransaction(
+ new Ledger.Transaction(now + 2 * HOUR_IN_MILLIS, now + 3 * HOUR_IN_MILLIS,
+ reward1, null, 2500, 0));
+ assertEquals(3000, ledger.get24HourSum(reward1, end));
+ // Second bucket
+ shiftSystemTime(7 * HOUR_IN_MILLIS); // now + 7
+ ledger.recordTransaction(
+ new Ledger.Transaction(now + 7 * HOUR_IN_MILLIS, now + 7 * HOUR_IN_MILLIS,
+ reward1, null, 1, 0));
ledger.recordTransaction(
- new Ledger.Transaction(2 * HOUR_IN_MILLIS, 3 * HOUR_IN_MILLIS, 1, null, 2500, 0));
- assertEquals(3000, ledger.get24HourSum(1, 24 * HOUR_IN_MILLIS));
+ new Ledger.Transaction(now + 7 * HOUR_IN_MILLIS, now + 7 * HOUR_IN_MILLIS,
+ reward2, null, 42, 0));
+ assertEquals(3001, ledger.get24HourSum(reward1, end));
+ assertEquals(42, ledger.get24HourSum(reward2, end));
+ // Third bucket
+ shiftSystemTime(12 * HOUR_IN_MILLIS); // now + 19
ledger.recordTransaction(
- new Ledger.Transaction(4 * HOUR_IN_MILLIS, 4 * HOUR_IN_MILLIS, 1, null, 1, 0));
- assertEquals(3001, ledger.get24HourSum(1, 24 * HOUR_IN_MILLIS));
- assertEquals(2501, ledger.get24HourSum(1, 25 * HOUR_IN_MILLIS));
- assertEquals(2501, ledger.get24HourSum(1, 26 * HOUR_IN_MILLIS));
- // Pro-rated as the second transaction phases out
- assertEquals(1251,
- ledger.get24HourSum(1, 26 * HOUR_IN_MILLIS + 30 * MINUTE_IN_MILLIS));
- assertEquals(1, ledger.get24HourSum(1, 27 * HOUR_IN_MILLIS));
- assertEquals(0, ledger.get24HourSum(1, 28 * HOUR_IN_MILLIS));
+ new Ledger.Transaction(now + 12 * HOUR_IN_MILLIS, now + 13 * HOUR_IN_MILLIS,
+ reward1, null, 300, 0));
+ assertEquals(3301, ledger.get24HourSum(reward1, end));
+ assertRewardBucketsInOrder(ledger.getRewardBuckets());
+ // Older buckets should be excluded
+ assertEquals(301, ledger.get24HourSum(reward1, end + HOUR_IN_MILLIS));
+ assertEquals(301, ledger.get24HourSum(reward1, end + 2 * HOUR_IN_MILLIS));
+ // 2nd bucket should still be included since it started at the 7 hour mark
+ assertEquals(301, ledger.get24HourSum(reward1, end + 6 * HOUR_IN_MILLIS));
+ assertEquals(42, ledger.get24HourSum(reward2, end + 6 * HOUR_IN_MILLIS));
+ assertEquals(300, ledger.get24HourSum(reward1, end + 7 * HOUR_IN_MILLIS + 1));
+ assertEquals(0, ledger.get24HourSum(reward2, end + 8 * HOUR_IN_MILLIS));
+ assertEquals(0, ledger.get24HourSum(reward1, end + 19 * HOUR_IN_MILLIS + 1));
}
@Test
@@ -125,4 +250,127 @@ public class LedgerTest {
ledger.removeOldTransactions(0);
assertNull(ledger.getEarliestTransaction());
}
+
+ @Test
+ public void testTransactionsAlwaysInOrder() {
+ final Ledger ledger = new Ledger();
+ List<Ledger.Transaction> transactions = ledger.getTransactions();
+ assertTrue(transactions.isEmpty());
+
+ final long now = getCurrentTimeMillis();
+ Ledger.Transaction transaction1 = new Ledger.Transaction(
+ now - 48 * HOUR_IN_MILLIS, now - 40 * HOUR_IN_MILLIS, 1, null, 4800, 0);
+ Ledger.Transaction transaction2 = new Ledger.Transaction(
+ now - 24 * HOUR_IN_MILLIS, now - 23 * HOUR_IN_MILLIS, 1, null, 600, 0);
+ Ledger.Transaction transaction3 = new Ledger.Transaction(
+ now - 22 * HOUR_IN_MILLIS, now - 21 * HOUR_IN_MILLIS, 1, null, 600, 0);
+ // Instant event
+ Ledger.Transaction transaction4 = new Ledger.Transaction(
+ now - 20 * HOUR_IN_MILLIS, now - 20 * HOUR_IN_MILLIS, 1, null, 500, 0);
+
+ Ledger.Transaction transaction5 = new Ledger.Transaction(
+ now - 15 * HOUR_IN_MILLIS, now - 15 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS,
+ 1, null, 400, 0);
+ ledger.recordTransaction(transaction1);
+ ledger.recordTransaction(transaction2);
+ ledger.recordTransaction(transaction3);
+ ledger.recordTransaction(transaction4);
+ ledger.recordTransaction(transaction5);
+
+ transactions = ledger.getTransactions();
+ assertEquals(5, transactions.size());
+ assertTransactionsInOrder(transactions);
+
+ for (int i = 0; i < Ledger.MAX_TRANSACTION_COUNT - 5; ++i) {
+ final long start = now - 10 * HOUR_IN_MILLIS + i * MINUTE_IN_MILLIS;
+ Ledger.Transaction transaction = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
+ ledger.recordTransaction(transaction);
+ }
+ transactions = ledger.getTransactions();
+ assertEquals(Ledger.MAX_TRANSACTION_COUNT, transactions.size());
+ assertTransactionsInOrder(transactions);
+
+ long start = now - 5 * HOUR_IN_MILLIS;
+ Ledger.Transaction transactionLast5 = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, 1, null, 4800, 0);
+ start = now - 4 * HOUR_IN_MILLIS;
+ Ledger.Transaction transactionLast4 = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, 1, null, 600, 0);
+ start = now - 3 * HOUR_IN_MILLIS;
+ Ledger.Transaction transactionLast3 = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, 1, null, 600, 0);
+ // Instant event
+ start = now - 2 * HOUR_IN_MILLIS;
+ Ledger.Transaction transactionLast2 = new Ledger.Transaction(
+ start, start, 1, null, 500, 0);
+ Ledger.Transaction transactionLast1 = new Ledger.Transaction(
+ start, start + MINUTE_IN_MILLIS, 1, null, 400, 0);
+ ledger.recordTransaction(transactionLast5);
+ ledger.recordTransaction(transactionLast4);
+ ledger.recordTransaction(transactionLast3);
+ ledger.recordTransaction(transactionLast2);
+ ledger.recordTransaction(transactionLast1);
+
+ transactions = ledger.getTransactions();
+ assertEquals(Ledger.MAX_TRANSACTION_COUNT, transactions.size());
+ assertTransactionsInOrder(transactions);
+ assertEquals(transactionLast1, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 1));
+ assertEquals(transactionLast2, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 2));
+ assertEquals(transactionLast3, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 3));
+ assertEquals(transactionLast4, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 4));
+ assertEquals(transactionLast5, transactions.get(Ledger.MAX_TRANSACTION_COUNT - 5));
+ assertFalse(transactions.contains(transaction1));
+ assertFalse(transactions.contains(transaction2));
+ assertFalse(transactions.contains(transaction3));
+ assertFalse(transactions.contains(transaction4));
+ assertFalse(transactions.contains(transaction5));
+ }
+
+ private void assertSparseLongArraysEqual(SparseLongArray expected, SparseLongArray actual) {
+ if (expected == null) {
+ assertNull(actual);
+ return;
+ }
+ assertNotNull(actual);
+ final int size = expected.size();
+ assertEquals(size, actual.size());
+ for (int i = 0; i < size; ++i) {
+ assertEquals(expected.keyAt(i), actual.keyAt(i));
+ assertEquals(expected.valueAt(i), actual.valueAt(i));
+ }
+ }
+
+ private void assertRewardBucketsEqual(Ledger.RewardBucket expected,
+ Ledger.RewardBucket actual) {
+ if (expected == null) {
+ assertNull(actual);
+ return;
+ }
+ assertNotNull(actual);
+ assertEquals(expected.startTimeMs, actual.startTimeMs);
+ assertSparseLongArraysEqual(expected.cumulativeDelta, actual.cumulativeDelta);
+ }
+
+ private void assertRewardBucketsInOrder(List<Ledger.RewardBucket> rewardBuckets) {
+ assertNotNull(rewardBuckets);
+ for (int i = 1; i < rewardBuckets.size(); ++i) {
+ final Ledger.RewardBucket prev = rewardBuckets.get(i - 1);
+ final Ledger.RewardBucket cur = rewardBuckets.get(i);
+ assertTrue("Newer bucket stored before older bucket @ index " + i
+ + ": " + prev.startTimeMs + " vs " + cur.startTimeMs,
+ prev.startTimeMs <= cur.startTimeMs);
+ }
+ }
+
+ private void assertTransactionsInOrder(List<Ledger.Transaction> transactions) {
+ assertNotNull(transactions);
+ for (int i = 1; i < transactions.size(); ++i) {
+ final Ledger.Transaction prev = transactions.get(i - 1);
+ final Ledger.Transaction cur = transactions.get(i);
+ assertTrue("Newer transaction stored before older transaction @ index " + i
+ + ": " + prev.endTimeMs + " vs " + cur.endTimeMs,
+ prev.endTimeMs <= cur.endTimeMs);
+ }
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a0b01a7fc27d..959429e255dd 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -639,6 +639,11 @@ public class UsageStatsService extends SystemService implements
mAppStandby.initializeDefaultsForSystemApps(userId);
}
+ private boolean sameApp(int callingUid, @UserIdInt int userId, String packageName) {
+ return mPackageManagerInternal.getPackageUid(packageName, 0 /* flags */, userId)
+ == callingUid;
+ }
+
private boolean isInstantApp(String packageName, int userId) {
return mPackageManagerInternal.isPackageEphemeral(userId, packageName);
}
@@ -2354,17 +2359,15 @@ public class UsageStatsService extends SystemService implements
}
final int packageUid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
// If the calling app is asking about itself, continue, else check for permission.
- if (packageUid != callingUid) {
- if (!hasPermission(callingPackage)) {
- throw new SecurityException(
- "Don't have permission to query app standby bucket");
- }
+ final boolean sameApp = packageUid == callingUid;
+ if (!sameApp && !hasPermission(callingPackage)) {
+ throw new SecurityException("Don't have permission to query app standby bucket");
}
final boolean isInstantApp = isInstantApp(packageName, userId);
final boolean cannotAccessInstantApps = shouldObfuscateInstantAppsForCaller(callingUid,
userId);
- if (packageUid < 0 || (isInstantApp && cannotAccessInstantApps)) {
+ if (packageUid < 0 || (!sameApp && isInstantApp && cannotAccessInstantApps)) {
throw new IllegalArgumentException(
"Cannot get standby bucket for non existent package (" + packageName + ")");
}
@@ -2418,7 +2421,9 @@ public class UsageStatsService extends SystemService implements
}
final int targetUserId = userId;
standbyBucketList.removeIf(
- i -> cannotAccessInstantApps && isInstantApp(i.mPackageName, targetUserId));
+ i -> !sameApp(callingUid, targetUserId, i.mPackageName)
+ && isInstantApp(i.mPackageName, targetUserId)
+ && cannotAccessInstantApps);
return new ParceledListSlice<>(standbyBucketList);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/tests/Camera2Tests/CameraToo/Android.bp b/tests/Camera2Tests/CameraToo/Android.bp
new file mode 100644
index 000000000000..ebc6fed9fefd
--- /dev/null
+++ b/tests/Camera2Tests/CameraToo/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2014 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 {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "frameworks_base_license",
+ ],
+}
+
+android_test {
+ name: "CameraToo",
+
+ sdk_version: "current",
+ srcs: ["src/**/*.java"],
+
+}
diff --git a/tests/Camera2Tests/CameraToo/Android.mk b/tests/Camera2Tests/CameraToo/Android.mk
deleted file mode 100644
index 33473143c8cb..000000000000
--- a/tests/Camera2Tests/CameraToo/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := CameraToo
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
-include $(BUILD_PACKAGE)
diff --git a/tests/backup/Android.bp b/tests/backup/Android.bp
new file mode 100644
index 000000000000..3890a1f58078
--- /dev/null
+++ b/tests/backup/Android.bp
@@ -0,0 +1,54 @@
+// Copyright (C) 2008 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.
+
+// native test
+// ========================================
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "frameworks_base_license",
+ ],
+}
+
+cc_binary {
+ name: "backup_helper_test",
+
+ srcs: ["backup_helper_test.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libandroidfw",
+ "libutils",
+ ],
+
+}
+
+// java test
+// ========================================
+android_app {
+ name: "BackupTest",
+
+ srcs: ["**/*.java"],
+
+ platform_apis: true,
+
+ optimize: {
+ enabled: false,
+ },
+
+}
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
deleted file mode 100644
index b6f34717658c..000000000000
--- a/tests/backup/Android.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (C) 2008 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.
-
-LOCAL_PATH := $(call my-dir)
-
-# native test
-# ========================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- backup_helper_test.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE := backup_helper_test
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SHARED_LIBRARIES := libandroidfw libutils
-
-include $(BUILD_EXECUTABLE)
-
-# java test
-# ========================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := BackupTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
-include $(BUILD_PACKAGE)