Merge "Fade back button in and out tied with the overview/shelf (1/2)" into pi-dev
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 02003c0..766c2d1 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -83,6 +83,7 @@
mTimeBaseNs(timeBaseNs),
mLargestTimestampSeen(0),
mLastTimestampSeen(0) {
+ mStatsPullerManager.ForceClearPullerCache();
}
StatsLogProcessor::~StatsLogProcessor() {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 136fd14..41e55cb 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -414,9 +414,11 @@
interval.tainted += 1;
}
}
- } else { // for pushed events
- interval.sum += value;
- interval.hasValue = true;
+ } else { // for pushed events, only accumulate when condition is true
+ if (mCondition == true || mConditionTrackerIndex < 0) {
+ interval.sum += value;
+ interval.hasValue = true;
+ }
}
long wholeBucketVal = interval.sum;
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 66afa15..cb6b051 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -169,11 +169,14 @@
const bool mUseAbsoluteValueOnReset;
FRIEND_TEST(ValueMetricProducerTest, TestNonDimensionalEvents);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
+ FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset);
FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse);
FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
+ FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithCondition);
FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 13b3cb1..67acd61 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -84,6 +84,7 @@
CreateDimensions(android::util::TEMPERATURE, {2 /* sensor name field */});
valueMetric->set_bucket(FIVE_MINUTES);
valueMetric->set_min_bucket_size_nanos(minTime);
+ valueMetric->set_use_absolute_value_on_reset(true);
return config;
}
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index 6923e7b..dd28d36 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -48,7 +48,7 @@
*valueMetric->mutable_dimensions_in_what() =
CreateDimensions(android::util::TEMPERATURE, {2/* sensor name field */ });
valueMetric->set_bucket(FIVE_MINUTES);
-
+ valueMetric->set_use_absolute_value_on_reset(true);
return config;
}
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 087a612..e3a8a55 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -129,6 +129,153 @@
}
/*
+ * Tests pulled atoms with no conditions and take absolute value after reset
+ */
+TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_use_absolute_value_on_reset(true);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ shared_ptr<MockStatsPullerManager> pullerManager =
+ make_shared<StrictMock<MockStatsPullerManager>>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(tagId);
+ event->write(11);
+ event->init();
+ allData.push_back(event);
+
+ valueProducer.onDataPulled(allData);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
+ EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(0, curInterval.tainted);
+ EXPECT_EQ(0, curInterval.sum);
+ EXPECT_EQ(11, curInterval.start);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+ allData.clear();
+ event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
+ event->write(tagId);
+ event->write(10);
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(0, curInterval.tainted);
+ EXPECT_EQ(0, curInterval.sum);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().mValue);
+
+ allData.clear();
+ event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
+ event->write(tagId);
+ event->write(36);
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(0, curInterval.tainted);
+ EXPECT_EQ(0, curInterval.sum);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValue);
+}
+
+/*
+ * Tests pulled atoms with no conditions and take zero value after reset
+ */
+TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ shared_ptr<MockStatsPullerManager> pullerManager =
+ make_shared<StrictMock<MockStatsPullerManager>>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(tagId);
+ event->write(11);
+ event->init();
+ allData.push_back(event);
+
+ valueProducer.onDataPulled(allData);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
+ EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(0, curInterval.tainted);
+ EXPECT_EQ(0, curInterval.sum);
+ EXPECT_EQ(11, curInterval.start);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+ allData.clear();
+ event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
+ event->write(tagId);
+ event->write(10);
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(0, curInterval.tainted);
+ EXPECT_EQ(0, curInterval.sum);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+ allData.clear();
+ event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
+ event->write(tagId);
+ event->write(36);
+ event->init();
+ allData.push_back(event);
+ valueProducer.onDataPulled(allData);
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(true, curInterval.startUpdated);
+ EXPECT_EQ(0, curInterval.tainted);
+ EXPECT_EQ(0, curInterval.sum);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second.back().mValue);
+}
+
+/*
* Test pulled event with non sliced condition.
*/
TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
@@ -401,6 +548,72 @@
EXPECT_EQ(30, valueProducer.mPastBuckets.begin()->second.back().mValue);
}
+TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ shared_ptr<MockStatsPullerManager> pullerManager =
+ make_shared<StrictMock<MockStatsPullerManager>>();
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, -1, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+ valueProducer.setBucketSize(60 * NS_PER_SEC);
+
+ shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+ event1->write(1);
+ event1->write(10);
+ event1->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
+ // has 1 slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(false, curInterval.hasValue);
+
+ valueProducer.onConditionChangedLocked(true, bucketStartTimeNs + 15);
+ shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
+ event2->write(1);
+ event2->write(20);
+ event2->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(20, curInterval.sum);
+
+ shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 30);
+ event3->write(1);
+ event3->write(30);
+ event3->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(50, curInterval.sum);
+
+ valueProducer.onConditionChangedLocked(false, bucketStartTimeNs + 35);
+ shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 40);
+ event4->write(1);
+ event4->write(40);
+ event4->init();
+ valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
+
+ // has one slice
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ curInterval = valueProducer.mCurrentSlicedBucket.begin()->second;
+ EXPECT_EQ(50, curInterval.sum);
+
+ valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
+ EXPECT_EQ(50, valueProducer.mPastBuckets.begin()->second.back().mValue);
+}
+
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
sp<AlarmMonitor> alarmMonitor;
Alert alert;
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 0a667cc..96f04ac 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -164,6 +164,7 @@
Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
Landroid/app/ActivityManager;->setPersistentVrThread(I)V
Landroid/app/ActivityManager;->staticGetMemoryClass()I
+Landroid/app/ActivityManager;->switchUser(I)Z
Landroid/app/ActivityManagerNative;-><init>()V
Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
@@ -572,6 +573,7 @@
Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/app/IActivityManager$Stub$Proxy;->setActivityController(Landroid/app/IActivityController;Z)V
Landroid/app/IActivityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
Landroid/app/IActivityManager;->broadcastIntent(Landroid/app/IApplicationThread;Landroid/content/Intent;Ljava/lang/String;Landroid/content/IIntentReceiver;ILjava/lang/String;Landroid/os/Bundle;[Ljava/lang/String;ILandroid/os/Bundle;ZZI)I
@@ -895,6 +897,9 @@
Landroid/app/SearchManager;->launchAssist(Landroid/os/Bundle;)V
Landroid/app/SearchManager;->mSearchDialog:Landroid/app/SearchDialog;
Landroid/app/SearchManager;->startSearch(Ljava/lang/String;ZLandroid/content/ComponentName;Landroid/os/Bundle;ZLandroid/graphics/Rect;)V
+Landroid/app/servertransaction/ClientTransaction;->mActivityCallbacks:Ljava/util/List;
+Landroid/app/servertransaction/LaunchActivityItem;->mInfo:Landroid/content/pm/ActivityInfo;
+Landroid/app/servertransaction/LaunchActivityItem;->mIntent:Landroid/content/Intent;
Landroid/app/Service;->attach(Landroid/content/Context;Landroid/app/ActivityThread;Ljava/lang/String;Landroid/os/IBinder;Landroid/app/Application;Ljava/lang/Object;)V
Landroid/app/Service;->mActivityManager:Landroid/app/IActivityManager;
Landroid/app/Service;->mApplication:Landroid/app/Application;
@@ -2203,6 +2208,7 @@
Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
Landroid/graphics/GraphicBuffer;->mNativeObject:J
Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
+Landroid/graphics/ImageFormat;->Y8:I
Landroid/graphics/Insets;->bottom:I
Landroid/graphics/Insets;->left:I
Landroid/graphics/Insets;->NONE:Landroid/graphics/Insets;
@@ -4211,6 +4217,7 @@
Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;)Ljava/lang/String;
Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
Landroid/os/UEventObserver;-><init>()V
+Landroid/os/UEventObserver;->onUEvent(Landroid/os/UEventObserver$UEvent;)V
Landroid/os/UEventObserver;->startObserving(Ljava/lang/String;)V
Landroid/os/UEventObserver;->stopObserving()V
Landroid/os/UpdateLock;->acquire()V
@@ -4439,9 +4446,11 @@
Landroid/provider/Downloads$Impl;->isStatusSuccess(I)Z
Landroid/provider/Downloads$Impl;->PUBLICLY_ACCESSIBLE_DOWNLOADS_URI:Landroid/net/Uri;
Landroid/provider/MediaStore$Files$FileColumns;->FORMAT:Ljava/lang/String;
+Landroid/provider/MediaStore$Files$FileColumns;->STORAGE_ID:Ljava/lang/String;
Landroid/provider/MediaStore$Files;->getMtpObjectsUri(Ljava/lang/String;)Landroid/net/Uri;
Landroid/provider/MediaStore$Files;->getMtpObjectsUri(Ljava/lang/String;J)Landroid/net/Uri;
Landroid/provider/MediaStore$Files;->getMtpReferencesUri(Ljava/lang/String;J)Landroid/net/Uri;
+Landroid/provider/MediaStore$MediaColumns;->IS_DRM:Ljava/lang/String;
Landroid/provider/Settings$Bookmarks;->add(Landroid/content/ContentResolver;Landroid/content/Intent;Ljava/lang/String;Ljava/lang/String;CI)Landroid/net/Uri;
Landroid/provider/Settings$Bookmarks;->CONTENT_URI:Landroid/net/Uri;
Landroid/provider/Settings$ContentProviderHolder;->mContentProvider:Landroid/content/IContentProvider;
@@ -4484,6 +4493,7 @@
Landroid/provider/Settings$Secure;->ENABLED_PRINT_SERVICES:Ljava/lang/String;
Landroid/provider/Settings$Secure;->getIntForUser(Landroid/content/ContentResolver;Ljava/lang/String;II)I
Landroid/provider/Settings$Secure;->getLongForUser(Landroid/content/ContentResolver;Ljava/lang/String;JI)J
+Landroid/provider/Settings$Secure;->IMMERSIVE_MODE_CONFIRMATIONS:Ljava/lang/String;
Landroid/provider/Settings$Secure;->INCALL_POWER_BUTTON_BEHAVIOR:Ljava/lang/String;
Landroid/provider/Settings$Secure;->LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS:Ljava/lang/String;
Landroid/provider/Settings$Secure;->LOCK_SCREEN_LOCK_AFTER_TIMEOUT:Ljava/lang/String;
@@ -6439,6 +6449,7 @@
Landroid/view/WindowInsets;-><init>(Landroid/graphics/Rect;)V
Landroid/view/WindowInsets;->CONSUMED:Landroid/view/WindowInsets;
Landroid/view/WindowInsets;->getSystemWindowInsets()Landroid/graphics/Rect;
+Landroid/view/WindowInsets;->inset(IIII)Landroid/view/WindowInsets;
Landroid/view/WindowLeaked;-><init>(Ljava/lang/String;)V
Landroid/view/WindowManager$LayoutParams;->backup()V
Landroid/view/WindowManager$LayoutParams;->FLAG_SLIPPERY:I
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0ae4b7d..494ea39 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -124,6 +124,7 @@
import android.util.SparseIntArray;
import android.util.SuperNotCalledException;
import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.ThreadedRenderer;
@@ -145,6 +146,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
import com.android.server.am.MemInfoDumpProto;
@@ -1406,7 +1408,15 @@
}
public void scheduleTrimMemory(int level) {
- sendMessage(H.TRIM_MEMORY, null, level);
+ final Runnable r = PooledLambda.obtainRunnable(ActivityThread::handleTrimMemory,
+ ActivityThread.this, level);
+ // Schedule trimming memory after drawing the frame to minimize jank-risk.
+ Choreographer choreographer = Choreographer.getMainThreadInstance();
+ if (choreographer != null) {
+ choreographer.postCallback(Choreographer.CALLBACK_COMMIT, r, null);
+ } else {
+ mH.post(r);
+ }
}
public void scheduleTranslucentConversionComplete(IBinder token, boolean drawComplete) {
@@ -1561,7 +1571,6 @@
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
- public static final int TRIM_MEMORY = 140;
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
@@ -1607,7 +1616,6 @@
case SLEEPING: return "SLEEPING";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
- case TRIM_MEMORY: return "TRIM_MEMORY";
case DUMP_PROVIDER: return "DUMP_PROVIDER";
case UNSTABLE_PROVIDER_DIED: return "UNSTABLE_PROVIDER_DIED";
case REQUEST_ASSIST_CONTEXT_EXTRAS: return "REQUEST_ASSIST_CONTEXT_EXTRAS";
@@ -1741,11 +1749,6 @@
case UPDATE_PACKAGE_COMPATIBILITY_INFO:
handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
break;
- case TRIM_MEMORY:
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
- handleTrimMemory(msg.arg1);
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- break;
case UNSTABLE_PROVIDER_DIED:
handleUnstableProviderDied((IBinder)msg.obj, false);
break;
@@ -5409,7 +5412,8 @@
BinderInternal.forceGc("mem");
}
- final void handleTrimMemory(int level) {
+ private void handleTrimMemory(int level) {
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
@@ -5420,6 +5424,7 @@
}
WindowManagerGlobal.getInstance().trimMemory(level);
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
private void setupGraphicsSupport(Context context) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 526888d..a591eaf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -984,6 +984,17 @@
public static final String EXTRA_SHOW_REMOTE_INPUT_SPINNER = "android.remoteInputSpinner";
/**
+ * {@link #extras} key: boolean as supplied to
+ * {@link Builder#setHideSmartReplies(boolean)}.
+ *
+ * If set to true, then any smart reply buttons will be hidden.
+ *
+ * @see Builder#setHideSmartReplies(boolean)
+ * @hide
+ */
+ public static final String EXTRA_HIDE_SMART_REPLIES = "android.hideSmartReplies";
+
+ /**
* {@link #extras} key: this is a small piece of additional text as supplied to
* {@link Builder#setContentInfo(CharSequence)}.
*/
@@ -3595,6 +3606,15 @@
}
/**
+ * Sets whether smart reply buttons should be hidden.
+ * @hide
+ */
+ public Builder setHideSmartReplies(boolean hideSmartReplies) {
+ mN.extras.putBoolean(EXTRA_HIDE_SMART_REPLIES, hideSmartReplies);
+ return this;
+ }
+
+ /**
* Sets the number of items this notification represents. May be displayed as a badge count
* for Launchers that support badging.
*/
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 80b1c3d..c3b8f39 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -696,7 +696,7 @@
*
* @hide
*/
- public static final String PRIVATE_DNS_DEFAULT_MODE = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC;
private final IConnectivityManager mService;
/**
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 53b1c51..7858c59 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -91,7 +91,14 @@
= "android.intent.action.UPDATE_NETWORK_WATCHLIST";
/**
- * Update carrier id config file.
+ * Broadcast intent action indicating that the updated carrier id config is available.
+ * <p>Extra: "VERSION" the numeric version of the new data. Devices should only install if the
+ * update version is newer than the current one.
+ * <p>Extra: "REQUIRED_HASH" the hash of the current update data.
+ * <p>Input: {@link android.content.Intent#getData} is URI of downloaded carrier id file.
+ * Devices should pick up the downloaded file and persist to the database
+ * {@link com.android.providers.telephony.CarrierIdProvider}.
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 27f446a..7bf3af1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6001,6 +6001,23 @@
new SettingsValidators.ComponentNameListValidator(":");
/**
+ * Whether the hush gesture has ever been used // TODO: beverlyt
+ * @hide
+ */
+ public static final String HUSH_GESTURE_USED = "hush_gesture_used";
+
+ private static final Validator HUSH_GESTURE_USED_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
+ * Number of times the user has manually clicked the ringer toggle
+ * @hide
+ */
+ public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
+
+ private static final Validator MANUAL_RINGER_TOGGLE_COUNT_VALIDATOR =
+ NON_NEGATIVE_INTEGER_VALIDATOR;
+
+ /**
* Uri of the slice that's presented on the keyguard.
* Defaults to a slice with the date and next alarm.
*
@@ -7983,7 +8000,9 @@
SCREENSAVER_ACTIVATE_ON_SLEEP,
LOCKDOWN_IN_POWER_MENU,
SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
- VOLUME_HUSH_GESTURE
+ VOLUME_HUSH_GESTURE,
+ MANUAL_RINGER_TOGGLE_COUNT,
+ HUSH_GESTURE_USED,
};
/**
@@ -8130,6 +8149,8 @@
ENABLED_NOTIFICATION_ASSISTANT_VALIDATOR); //legacy restore setting
VALIDATORS.put(ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR); //legacy restore setting
+ VALIDATORS.put(HUSH_GESTURE_USED, HUSH_GESTURE_USED_VALIDATOR);
+ VALIDATORS.put(MANUAL_RINGER_TOGGLE_COUNT, MANUAL_RINGER_TOGGLE_COUNT_VALIDATOR);
}
/**
@@ -8610,6 +8631,14 @@
private static final Validator CHARGING_SOUNDS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
+ * Whether to vibrate for wireless charging events.
+ * @hide
+ */
+ public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled";
+
+ private static final Validator CHARGING_VIBRATION_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
* Whether we keep the device on while the device is plugged in.
* Supported values are:
* <ul>
@@ -9297,7 +9326,7 @@
* values.
* Consists of a comma seperated list of strings:
* "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
- * note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN"
+ * note that empty fields can be omitted: "name,apn,,,,,,,,,310,260,,DUN"
* @hide
*/
public static final String TETHER_DUN_APN = "tether_dun_apn";
@@ -10358,6 +10387,17 @@
private static final Validator PRIVATE_DNS_SPECIFIER_VALIDATOR = ANY_STRING_VALIDATOR;
+ /**
+ * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
+ * This allows changing the default mode without effectively disabling other modes,
+ * all of which require explicit user action to enable/configure. See also b/79719289.
+ *
+ * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
+ *
+ * {@hide}
+ */
+ public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
+
/** {@hide} */
public static final String
BLUETOOTH_HEADSET_PRIORITY_PREFIX = "bluetooth_headset_priority_";
@@ -12017,6 +12057,7 @@
PRIVATE_DNS_SPECIFIER,
SOFT_AP_TIMEOUT_ENABLED,
ZEN_DURATION,
+ CHARGING_VIBRATION_ENABLED,
};
/**
@@ -12060,6 +12101,7 @@
WIFI_CARRIER_NETWORKS_AVAILABLE_NOTIFICATION_ON_VALIDATOR);
VALIDATORS.put(APP_AUTO_RESTRICTION_ENABLED, APP_AUTO_RESTRICTION_ENABLED_VALIDATOR);
VALIDATORS.put(ZEN_DURATION, ZEN_DURATION_VALIDATOR);
+ VALIDATORS.put(CHARGING_VIBRATION_ENABLED, CHARGING_VIBRATION_ENABLED_VALIDATOR);
}
/**
diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java
index 5885b6b..c878bba 100644
--- a/core/java/android/provider/SettingsValidators.java
+++ b/core/java/android/provider/SettingsValidators.java
@@ -79,7 +79,7 @@
public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
@Override
public boolean validate(String value) {
- return ComponentName.unflattenFromString(value) != null;
+ return value != null && ComponentName.unflattenFromString(value) != null;
}
};
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 1caea57..f8cfd0d 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -106,10 +106,16 @@
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
- return new Choreographer(looper, VSYNC_SOURCE_APP);
+ Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
+ if (looper == Looper.getMainLooper()) {
+ mMainInstance = choreographer;
+ }
+ return choreographer;
}
};
+ private static volatile Choreographer mMainInstance;
+
// Thread local storage for the SF choreographer.
private static final ThreadLocal<Choreographer> sSfThreadInstance =
new ThreadLocal<Choreographer>() {
@@ -263,6 +269,14 @@
return sSfThreadInstance.get();
}
+ /**
+ * @return The Choreographer of the main thread, if it exists, or {@code null} otherwise.
+ * @hide
+ */
+ public static Choreographer getMainThreadInstance() {
+ return mMainInstance;
+ }
+
/** Destroys the calling thread's choreographer
* @hide
*/
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e03f5fa..d19cc9c 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -790,7 +790,8 @@
* @param attachInfo AttachInfo tied to the specified view.
* @param callbacks Callbacks invoked when drawing happens.
*/
- void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
+ void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks,
+ FrameDrawingCallback frameDrawingCallback) {
attachInfo.mIgnoreDirtyState = true;
final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
@@ -815,6 +816,9 @@
}
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
+ if (frameDrawingCallback != null) {
+ nSetFrameCallback(mNativeProxy, frameDrawingCallback);
+ }
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
setEnabled(false);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 049d34f..172e248 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9838,26 +9838,20 @@
/**
* @hide Compute the insets that should be consumed by this view and the ones
* that should propagate to those under it.
+ *
+ * Note: This is used by appcompat's ActionBarOverlayLayout through reflection.
+ *
+ * @param inoutInsets the insets given to this view
+ * @param outLocalInsets the insets that should be applied to this view
+ * @deprecated use {@link #computeSystemWindowInsets}
+ * @return
*/
+ @Deprecated
protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) {
- if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
- || mAttachInfo == null
- || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
- && !mAttachInfo.mOverscanRequested)) {
- outLocalInsets.set(inoutInsets);
- inoutInsets.set(0, 0, 0, 0);
- return true;
- } else {
- // The application wants to take care of fitting system window for
- // the content... however we still need to take care of any overscan here.
- final Rect overscan = mAttachInfo.mOverscanInsets;
- outLocalInsets.set(overscan);
- inoutInsets.left -= overscan.left;
- inoutInsets.top -= overscan.top;
- inoutInsets.right -= overscan.right;
- inoutInsets.bottom -= overscan.bottom;
- return false;
- }
+ WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets),
+ outLocalInsets);
+ inoutInsets.set(innerInsets.getSystemWindowInsets());
+ return innerInsets.isSystemWindowInsetsConsumed();
}
/**
@@ -9873,12 +9867,16 @@
public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0
|| mAttachInfo == null
- || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) {
+ || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0
+ && !mAttachInfo.mOverscanRequested)) {
outLocalInsets.set(in.getSystemWindowInsets());
- return in.consumeSystemWindowInsets();
+ return in.consumeSystemWindowInsets().inset(outLocalInsets);
} else {
- outLocalInsets.set(0, 0, 0, 0);
- return in;
+ // The application wants to take care of fitting system window for
+ // the content... however we still need to take care of any overscan here.
+ final Rect overscan = mAttachInfo.mOverscanInsets;
+ outLocalInsets.set(overscan);
+ return in.inset(outLocalInsets);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 239185e..7c814f4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -80,6 +80,7 @@
import android.util.TimeUtils;
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
+import android.view.ThreadedRenderer.FrameDrawingCallback;
import android.view.View.AttachInfo;
import android.view.View.FocusDirection;
import android.view.View.MeasureSpec;
@@ -175,6 +176,8 @@
static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
static boolean sFirstDrawComplete = false;
+ private FrameDrawingCallback mNextRtFrameCallback;
+
/**
* Callback for notifying about global configuration changes.
*/
@@ -967,6 +970,17 @@
}
}
+ /**
+ * Registers a callback to be executed when the next frame is being drawn on RenderThread. This
+ * callback will be executed on a RenderThread worker thread, and only used for the next frame
+ * and thus it will only fire once.
+ *
+ * @param callback The callback to register.
+ */
+ public void registerRtFrameCallback(FrameDrawingCallback callback) {
+ mNextRtFrameCallback = callback;
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -3260,7 +3274,8 @@
requestDrawWindow();
}
- mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
+ mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this, mNextRtFrameCallback);
+ mNextRtFrameCallback = null;
} else {
// If we get here with a disabled & requested hardware renderer, something went
// wrong (an invalidate posted right before we destroyed the hardware surface
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index e5cbe96..fbd8141 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -20,6 +20,10 @@
import android.annotation.Nullable;
import android.graphics.Rect;
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
/**
* Describes a set of insets for window content.
*
@@ -27,6 +31,12 @@
* To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
* with the adjusted properties.</p>
*
+ * <p>Note: Before {@link android.os.Build.VERSION_CODES#P P}, WindowInsets instances were only
+ * immutable during a single layout pass (i.e. would return the same values between
+ * {@link View#onApplyWindowInsets} and {@link View#onLayout}, but could return other values
+ * otherwise). Starting with {@link android.os.Build.VERSION_CODES#P P}, WindowInsets are
+ * always immutable and implement equality.
+ *
* @see View.OnApplyWindowInsetsListener
* @see View#onApplyWindowInsets(WindowInsets)
*/
@@ -69,13 +79,14 @@
public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
mSystemWindowInsetsConsumed = systemWindowInsets == null;
- mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
+ mSystemWindowInsets = mSystemWindowInsetsConsumed
+ ? EMPTY_RECT : new Rect(systemWindowInsets);
mWindowDecorInsetsConsumed = windowDecorInsets == null;
- mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets;
+ mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : new Rect(windowDecorInsets);
mStableInsetsConsumed = stableInsets == null;
- mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : stableInsets;
+ mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : new Rect(stableInsets);
mIsRound = isRound;
mAlwaysConsumeNavBar = alwaysConsumeNavBar;
@@ -535,4 +546,104 @@
+ (isRound() ? " round" : "")
+ "}";
}
+
+ /**
+ * Returns a copy of this instance inset in the given directions.
+ *
+ * @see #inset(int, int, int, int)
+ * @hide
+ */
+ public WindowInsets inset(Rect r) {
+ return inset(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Returns a copy of this instance inset in the given directions.
+ *
+ * This is intended for dispatching insets to areas of the window that are smaller than the
+ * current area.
+ *
+ * <p>Example:
+ * <pre>
+ * childView.dispatchApplyWindowInsets(insets.inset(
+ * childMarginLeft, childMarginTop, childMarginBottom, childMarginRight));
+ * </pre>
+ *
+ * @param left the amount of insets to remove from the left. Must be non-negative.
+ * @param top the amount of insets to remove from the top. Must be non-negative.
+ * @param right the amount of insets to remove from the right. Must be non-negative.
+ * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
+ *
+ * @return the inset insets
+ *
+ * @hide pending API
+ */
+ public WindowInsets inset(int left, int top, int right, int bottom) {
+ Preconditions.checkArgumentNonnegative(left);
+ Preconditions.checkArgumentNonnegative(top);
+ Preconditions.checkArgumentNonnegative(right);
+ Preconditions.checkArgumentNonnegative(bottom);
+
+ WindowInsets result = new WindowInsets(this);
+ if (!result.mSystemWindowInsetsConsumed) {
+ result.mSystemWindowInsets =
+ insetInsets(result.mSystemWindowInsets, left, top, right, bottom);
+ }
+ if (!result.mWindowDecorInsetsConsumed) {
+ result.mWindowDecorInsets =
+ insetInsets(result.mWindowDecorInsets, left, top, right, bottom);
+ }
+ if (!result.mStableInsetsConsumed) {
+ result.mStableInsets = insetInsets(result.mStableInsets, left, top, right, bottom);
+ }
+ if (mDisplayCutout != null) {
+ result.mDisplayCutout = result.mDisplayCutout.inset(left, top, right, bottom);
+ if (result.mDisplayCutout.isEmpty()) {
+ result.mDisplayCutout = null;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || !(o instanceof WindowInsets)) return false;
+ WindowInsets that = (WindowInsets) o;
+ return mIsRound == that.mIsRound
+ && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar
+ && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
+ && mWindowDecorInsetsConsumed == that.mWindowDecorInsetsConsumed
+ && mStableInsetsConsumed == that.mStableInsetsConsumed
+ && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
+ && Objects.equals(mSystemWindowInsets, that.mSystemWindowInsets)
+ && Objects.equals(mWindowDecorInsets, that.mWindowDecorInsets)
+ && Objects.equals(mStableInsets, that.mStableInsets)
+ && Objects.equals(mDisplayCutout, that.mDisplayCutout);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, mIsRound,
+ mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed,
+ mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
+ }
+
+ private static Rect insetInsets(Rect insets, int left, int top, int right, int bottom) {
+ int newLeft = Math.max(0, insets.left - left);
+ int newTop = Math.max(0, insets.top - top);
+ int newRight = Math.max(0, insets.right - right);
+ int newBottom = Math.max(0, insets.bottom - bottom);
+ if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
+ return insets;
+ }
+ return new Rect(newLeft, newTop, newRight, newBottom);
+ }
+
+ /**
+ * @return whether system window insets have been consumed.
+ */
+ boolean isSystemWindowInsetsConsumed() {
+ return mSystemWindowInsetsConsumed;
+ }
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 2db5739..465957d 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -983,14 +983,14 @@
if (attrs.height == WindowManager.LayoutParams.WRAP_CONTENT) {
mFloatingInsets.top = insets.getSystemWindowInsetTop();
mFloatingInsets.bottom = insets.getSystemWindowInsetBottom();
- insets = insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), 0,
- insets.getSystemWindowInsetRight(), 0);
+ insets = insets.inset(0, insets.getSystemWindowInsetTop(),
+ 0, insets.getSystemWindowInsetBottom());
}
if (mWindow.getAttributes().width == WindowManager.LayoutParams.WRAP_CONTENT) {
mFloatingInsets.left = insets.getSystemWindowInsetTop();
mFloatingInsets.right = insets.getSystemWindowInsetBottom();
- insets = insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(),
- 0, insets.getSystemWindowInsetBottom());
+ insets = insets.inset(insets.getSystemWindowInsetLeft(), 0,
+ insets.getSystemWindowInsetRight(), 0);
}
}
mFrameOffsets.set(insets.getSystemWindowInsets());
@@ -1158,11 +1158,7 @@
}
}
if (insets != null) {
- insets = insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft() - consumedLeft,
- insets.getSystemWindowInsetTop() - consumedTop,
- insets.getSystemWindowInsetRight() - consumedRight,
- insets.getSystemWindowInsetBottom() - consumedBottom);
+ insets = insets.inset(consumedLeft, consumedTop, consumedRight, consumedBottom);
}
}
@@ -1383,8 +1379,9 @@
// screen_simple_overlay_action_mode.xml).
final boolean nonOverlay = (mWindow.getLocalFeaturesPrivate()
& (1 << Window.FEATURE_ACTION_MODE_OVERLAY)) == 0;
- insets = insets.consumeSystemWindowInsets(
- false, nonOverlay && showStatusGuard /* top */, false, false);
+ if (nonOverlay && showStatusGuard) {
+ insets = insets.inset(0, insets.getSystemWindowInsetTop(), 0, 0);
+ }
} else {
// reset top margin
if (mlp.topMargin != 0) {
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.java b/core/java/com/android/internal/statusbar/NotificationVisibility.java
index 7fe440c..ea0344d 100644
--- a/core/java/com/android/internal/statusbar/NotificationVisibility.java
+++ b/core/java/com/android/internal/statusbar/NotificationVisibility.java
@@ -51,7 +51,7 @@
@Override
public String toString() {
return "NotificationVisibility(id=" + id
- + "key=" + key
+ + " key=" + key
+ " rank=" + rank
+ " count=" + count
+ (visible?" visible":"")
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 5d7fa6a..4a1c955 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -75,10 +75,10 @@
private final Rect mBaseContentInsets = new Rect();
private final Rect mLastBaseContentInsets = new Rect();
private final Rect mContentInsets = new Rect();
- private final Rect mBaseInnerInsets = new Rect();
- private final Rect mLastBaseInnerInsets = new Rect();
- private final Rect mInnerInsets = new Rect();
- private final Rect mLastInnerInsets = new Rect();
+ private WindowInsets mBaseInnerInsets = WindowInsets.CONSUMED;
+ private WindowInsets mLastBaseInnerInsets = WindowInsets.CONSUMED;
+ private WindowInsets mInnerInsets = WindowInsets.CONSUMED;
+ private WindowInsets mLastInnerInsets = WindowInsets.CONSUMED;
private ActionBarVisibilityCallback mActionBarVisibilityCallback;
@@ -322,11 +322,14 @@
changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
}
- mBaseInnerInsets.set(systemInsets);
- computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
+ // Cannot use the result of computeSystemWindowInsets, because that consumes the
+ // systemWindowInsets. Instead, we do the insetting by the local insets ourselves.
+ computeSystemWindowInsets(insets, mBaseContentInsets);
+ mBaseInnerInsets = insets.inset(mBaseContentInsets);
+
if (!mLastBaseInnerInsets.equals(mBaseInnerInsets)) {
changed = true;
- mLastBaseContentInsets.set(mBaseContentInsets);
+ mLastBaseInnerInsets = mBaseInnerInsets;
}
if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
changed = true;
@@ -430,22 +433,29 @@
// will still be covered by the action bar if they have requested it to
// overlay.
mContentInsets.set(mBaseContentInsets);
- mInnerInsets.set(mBaseInnerInsets);
+ mInnerInsets = mBaseInnerInsets;
if (!mOverlayMode && !stable) {
mContentInsets.top += topInset;
mContentInsets.bottom += bottomInset;
+ // Content view has been shrunk, shrink all insets to match.
+ mInnerInsets = mInnerInsets.inset(0 /* left */, topInset, 0 /* right */, bottomInset);
} else {
- mInnerInsets.top += topInset;
- mInnerInsets.bottom += bottomInset;
+ // Add ActionBar to system window inset, but leave other insets untouched.
+ mInnerInsets = mInnerInsets.replaceSystemWindowInsets(
+ mInnerInsets.getSystemWindowInsetLeft(),
+ mInnerInsets.getSystemWindowInsetTop() + topInset,
+ mInnerInsets.getSystemWindowInsetRight(),
+ mInnerInsets.getSystemWindowInsetBottom() + bottomInset
+ );
}
applyInsets(mContent, mContentInsets, true, true, true, true);
if (!mLastInnerInsets.equals(mInnerInsets)) {
// If the inner insets have changed, we need to dispatch this down to
- // the app's fitSystemWindows(). We do this before measuring the content
+ // the app's onApplyWindowInsets(). We do this before measuring the content
// view to keep the same semantics as the normal fitSystemWindows() call.
- mLastInnerInsets.set(mInnerInsets);
- mContent.dispatchApplyWindowInsets(new WindowInsets(mInnerInsets));
+ mLastInnerInsets = mInnerInsets;
+ mContent.dispatchApplyWindowInsets(mInnerInsets);
}
measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp
index 7166c75..8dd5f5f 100644
--- a/core/jni/android/graphics/AnimatedImageDrawable.cpp
+++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp
@@ -239,11 +239,6 @@
return drawable->byteSize();
}
-static void AnimatedImageDrawable_nMarkInvisible(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
- auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
- drawable->markInvisible();
-}
-
static void AnimatedImageDrawable_nSetMirrored(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
jboolean mirrored) {
auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
@@ -264,7 +259,6 @@
{ "nSetRepeatCount", "(JI)V", (void*) AnimatedImageDrawable_nSetRepeatCount },
{ "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
{ "nNativeByteSize", "(J)J", (void*) AnimatedImageDrawable_nNativeByteSize },
- { "nMarkInvisible", "(J)V", (void*) AnimatedImageDrawable_nMarkInvisible },
{ "nSetMirrored", "(JZ)V", (void*) AnimatedImageDrawable_nSetMirrored },
};
diff --git a/packages/SystemUI/res/drawable/ic_lock_lockdown.xml b/core/res/res/drawable/ic_lock_lockdown.xml
similarity index 96%
rename from packages/SystemUI/res/drawable/ic_lock_lockdown.xml
rename to core/res/res/drawable/ic_lock_lockdown.xml
index d591aa8..b9685d3 100644
--- a/packages/SystemUI/res/drawable/ic_lock_lockdown.xml
+++ b/core/res/res/drawable/ic_lock_lockdown.xml
@@ -21,6 +21,6 @@
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="#000000"
+ android:fillColor="#FF000000"
android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
</vector>
diff --git a/core/res/res/layout/autofill_dataset_picker.xml b/core/res/res/layout/autofill_dataset_picker.xml
index a88836e..dca0128 100644
--- a/core/res/res/layout/autofill_dataset_picker.xml
+++ b/core/res/res/layout/autofill_dataset_picker.xml
@@ -18,6 +18,7 @@
android:id="@+id/autofill_dataset_picker"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
+ android:foreground="?attr/listChoiceBackgroundIndicator"
style="@style/AutofillDatasetPicker">
<ListView
diff --git a/core/res/res/layout/autofill_dataset_picker_fullscreen.xml b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml
index 1d2b5e5..90435e9 100644
--- a/core/res/res/layout/autofill_dataset_picker_fullscreen.xml
+++ b/core/res/res/layout/autofill_dataset_picker_fullscreen.xml
@@ -60,12 +60,13 @@
</LinearLayout>
- <!-- autofill_container is the common parent for inserting authentication item or
- autofill_dataset_list, autofill_dataset_foolter-->
+ <!-- autofill_dataset_picker is the common parent for inserting authentication item or
+ autofill_dataset_list, autofill_dataset_footer-->
<LinearLayout
android:layout_width="304dp"
android:layout_height="wrap_content"
android:id="@+id/autofill_dataset_picker"
+ android:foreground="?attr/listChoiceBackgroundIndicator"
android:orientation="vertical">
<ListView
android:id="@+id/autofill_dataset_list"
@@ -83,4 +84,4 @@
android:orientation="vertical"/>
</LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout/autofill_dataset_picker_header_footer.xml b/core/res/res/layout/autofill_dataset_picker_header_footer.xml
index 093f035..4d5f4f0 100644
--- a/core/res/res/layout/autofill_dataset_picker_header_footer.xml
+++ b/core/res/res/layout/autofill_dataset_picker_header_footer.xml
@@ -18,6 +18,7 @@
android:id="@+id/autofill_dataset_picker"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
+ android:foreground="?attr/listChoiceBackgroundIndicator"
style="@style/AutofillDatasetPicker">
<LinearLayout
diff --git a/core/res/res/values-mcc312-mnc530/config.xml b/core/res/res/values-mcc312-mnc530/config.xml
index f6aed13..413c698 100644
--- a/core/res/res/values-mcc312-mnc530/config.xml
+++ b/core/res/res/values-mcc312-mnc530/config.xml
@@ -25,6 +25,10 @@
-->
<integer name="config_mobile_mtu">1422</integer>
+ <!-- If this value is true, The mms content-disposition field is supported correctly.
+ If false, Content-disposition fragments are ignored -->
+ <bool name="config_mms_content_disposition_support">false</bool>
+
<!-- An array of CDMA roaming indicators which means international roaming -->
<integer-array translatable="false" name="config_cdma_international_roaming_indicators" >
<item>2</item>
diff --git a/core/res/res/values-w195dp/dimens_material.xml b/core/res/res/values-w195dp/dimens_material.xml
new file mode 100644
index 0000000..7f3ad29
--- /dev/null
+++ b/core/res/res/values-w195dp/dimens_material.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <dimen name="screen_percentage_05">9.75dp</dimen>
+ <dimen name="screen_percentage_10">19.5dp</dimen>
+ <dimen name="screen_percentage_15">29.25dp</dimen>
+</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 70eac97..7708911 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3382,4 +3382,5 @@
<java-symbol type="id" name="user_loading" />
<java-symbol type="string" name="battery_saver_description_with_learn_more" />
+ <java-symbol type="drawable" name="ic_lock_lockdown" />
</resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 22aca30..5b7fc6e 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -358,6 +358,7 @@
Settings.Global.PREFERRED_NETWORK_MODE,
Settings.Global.PRIV_APP_OOB_ENABLED,
Settings.Global.PRIV_APP_OOB_LIST,
+ Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
Settings.Global.RADIO_BLUETOOTH,
Settings.Global.RADIO_CELL,
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index e750766..c4d5b0c 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -16,9 +16,9 @@
package android.provider;
-import static org.junit.Assert.fail;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.platform.test.annotations.Presubmit;
import android.provider.SettingsValidators.Validator;
@@ -63,6 +63,11 @@
}
@Test
+ public void testComponentNameValidator_onNullValue_doesNotThrow() {
+ assertFalse(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate(null));
+ }
+
+ @Test
public void testLocaleValidator() {
assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("en_US"));
assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("es"));
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
new file mode 100644
index 0000000..cac4e88
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import static android.view.DisplayCutout.NO_CUTOUT;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayCutout;
+import android.view.View;
+import android.view.View.OnApplyWindowInsetsListener;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+import android.widget.Toolbar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ActionBarOverlayLayoutTest {
+
+ private static final Rect TOP_INSET_5 = new Rect(0, 5, 0, 0);
+ private static final Rect TOP_INSET_25 = new Rect(0, 25, 0, 0);
+ private static final Rect ZERO_INSET = new Rect(0, 0, 0, 0);
+ private static final DisplayCutout CONSUMED_CUTOUT = null;
+ private static final DisplayCutout CUTOUT_5 = new DisplayCutout(TOP_INSET_5, Arrays.asList(
+ new Rect(100, 0, 200, 5)));
+ private static final int EXACTLY_1000 = makeMeasureSpec(1000, EXACTLY);
+
+ private Context mContext;
+ private TestActionBarOverlayLayout mLayout;
+
+ private ViewGroup mContent;
+ private ViewGroup mActionBarTop;
+ private Toolbar mToolbar;
+ private FakeOnApplyWindowListener mContentInsetsListener;
+
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mLayout = new TestActionBarOverlayLayout(mContext);
+ mLayout.makeOptionalFitsSystemWindows();
+
+ mContent = createViewGroupWithId(com.android.internal.R.id.content);
+ mContent.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mLayout.addView(mContent);
+
+ mContentInsetsListener = new FakeOnApplyWindowListener();
+ mContent.setOnApplyWindowInsetsListener(mContentInsetsListener);
+
+ mActionBarTop = new ActionBarContainer(mContext);
+ mActionBarTop.setId(com.android.internal.R.id.action_bar_container);
+ mActionBarTop.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, 20));
+ mLayout.addView(mActionBarTop);
+ mLayout.setActionBarHeight(20);
+
+ mToolbar = new Toolbar(mContext);
+ mToolbar.setId(com.android.internal.R.id.action_bar);
+ mActionBarTop.addView(mToolbar);
+ }
+
+ @Test
+ public void topInset_consumedCutout_stable() {
+ mLayout.setStable(true);
+ mLayout.dispatchApplyWindowInsets(insetsWith(TOP_INSET_5, CONSUMED_CUTOUT));
+
+ assertThat(mContentInsetsListener.captured, nullValue());
+
+ mLayout.measure(EXACTLY_1000, EXACTLY_1000);
+
+ // Action bar height is added to the top inset
+ assertThat(mContentInsetsListener.captured, is(insetsWith(TOP_INSET_25, CONSUMED_CUTOUT)));
+ }
+
+ @Test
+ public void topInset_consumedCutout_notStable() {
+ mLayout.dispatchApplyWindowInsets(insetsWith(TOP_INSET_5, CONSUMED_CUTOUT));
+
+ assertThat(mContentInsetsListener.captured, nullValue());
+
+ mLayout.measure(EXACTLY_1000, EXACTLY_1000);
+
+ assertThat(mContentInsetsListener.captured, is(insetsWith(ZERO_INSET, CONSUMED_CUTOUT)));
+ }
+
+ @Test
+ public void topInset_noCutout_stable() {
+ mLayout.setStable(true);
+ mLayout.dispatchApplyWindowInsets(insetsWith(TOP_INSET_5, NO_CUTOUT));
+
+ assertThat(mContentInsetsListener.captured, nullValue());
+
+ mLayout.measure(EXACTLY_1000, EXACTLY_1000);
+
+ // Action bar height is added to the top inset
+ assertThat(mContentInsetsListener.captured, is(insetsWith(TOP_INSET_25, NO_CUTOUT)));
+ }
+
+ @Test
+ public void topInset_noCutout_notStable() {
+ mLayout.dispatchApplyWindowInsets(insetsWith(TOP_INSET_5, NO_CUTOUT));
+
+ assertThat(mContentInsetsListener.captured, nullValue());
+
+ mLayout.measure(EXACTLY_1000, EXACTLY_1000);
+
+ assertThat(mContentInsetsListener.captured, is(insetsWith(ZERO_INSET, NO_CUTOUT)));
+ }
+
+ @Test
+ public void topInset_cutout_stable() {
+ mLayout.setStable(true);
+ mLayout.dispatchApplyWindowInsets(insetsWith(TOP_INSET_5, CUTOUT_5));
+
+ assertThat(mContentInsetsListener.captured, nullValue());
+
+ mLayout.measure(EXACTLY_1000, EXACTLY_1000);
+
+ // Action bar height is added to the top inset
+ assertThat(mContentInsetsListener.captured, is(insetsWith(TOP_INSET_25, CUTOUT_5)));
+ }
+
+ @Test
+ public void topInset_cutout_notStable() {
+ mLayout.dispatchApplyWindowInsets(insetsWith(TOP_INSET_5, CUTOUT_5));
+
+ assertThat(mContentInsetsListener.captured, nullValue());
+
+ mLayout.measure(EXACTLY_1000, EXACTLY_1000);
+
+ assertThat(mContentInsetsListener.captured, is(insetsWith(ZERO_INSET, NO_CUTOUT)));
+ }
+
+ private WindowInsets insetsWith(Rect content, DisplayCutout cutout) {
+ return new WindowInsets(content, null, null, false, false, cutout);
+ }
+
+ private ViewGroup createViewGroupWithId(int id) {
+ final FrameLayout v = new FrameLayout(mContext);
+ v.setId(id);
+ return v;
+ }
+
+ static class TestActionBarOverlayLayout extends ActionBarOverlayLayout {
+ private boolean mStable;
+
+ public TestActionBarOverlayLayout(Context context) {
+ super(context);
+ }
+
+ @Override
+ public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
+ if (mStable) {
+ // Emulate the effect of makeOptionalFitsSystemWindows, because we can't do that
+ // without being attached to a window.
+ outLocalInsets.setEmpty();
+ return in;
+ }
+ return super.computeSystemWindowInsets(in, outLocalInsets);
+ }
+
+ void setStable(boolean stable) {
+ mStable = stable;
+ setSystemUiVisibility(stable ? SYSTEM_UI_FLAG_LAYOUT_STABLE : 0);
+ }
+
+ @Override
+ public int getWindowSystemUiVisibility() {
+ return getSystemUiVisibility();
+ }
+
+ void setActionBarHeight(int height) {
+ try {
+ final Field field = ActionBarOverlayLayout.class.getDeclaredField(
+ "mActionBarHeight");
+ field.setAccessible(true);
+ field.setInt(this, height);
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ static class FakeOnApplyWindowListener implements OnApplyWindowInsetsListener {
+ WindowInsets captured;
+
+ @Override
+ public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ assertNotNull(insets);
+ captured = insets;
+ return v.onApplyWindowInsets(insets);
+ }
+ }
+}
diff --git a/data/keyboards/Vendor_054c_Product_05c4.kl b/data/keyboards/Vendor_054c_Product_05c4.kl
index f465733..a1284a4 100644
--- a/data/keyboards/Vendor_054c_Product_05c4.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4.kl
@@ -62,6 +62,10 @@
key 0x139 BUTTON_START
# PS key
-key 0x13c HOME
+key 0x13c BUTTON_MODE
+
# Touchpad press
-key 0x13d BUTTON_MODE
+# The touchpad for this joystick will become a separate input device in future releases
+# and this button will be equivalent to left mouse button
+# Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
+key 0x13d BUTTON_1
diff --git a/data/keyboards/Vendor_054c_Product_09cc.kl b/data/keyboards/Vendor_054c_Product_09cc.kl
index f465733..a1284a4 100644
--- a/data/keyboards/Vendor_054c_Product_09cc.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc.kl
@@ -62,6 +62,10 @@
key 0x139 BUTTON_START
# PS key
-key 0x13c HOME
+key 0x13c BUTTON_MODE
+
# Touchpad press
-key 0x13d BUTTON_MODE
+# The touchpad for this joystick will become a separate input device in future releases
+# and this button will be equivalent to left mouse button
+# Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
+key 0x13d BUTTON_1
diff --git a/data/sounds/AudioTv.mk b/data/sounds/AudioTv.mk
index ee37cb9..91265af 100644
--- a/data/sounds/AudioTv.mk
+++ b/data/sounds/AudioTv.mk
@@ -15,111 +15,8 @@
LOCAL_PATH := frameworks/base/data/sounds
PRODUCT_COPY_FILES += \
- $(LOCAL_PATH)/Alarm_Beep_01.ogg:system/media/audio/alarms/Alarm_Beep_01.ogg \
- $(LOCAL_PATH)/Alarm_Beep_02.ogg:system/media/audio/alarms/Alarm_Beep_02.ogg \
- $(LOCAL_PATH)/Alarm_Beep_03.ogg:system/media/audio/alarms/Alarm_Beep_03.ogg \
- $(LOCAL_PATH)/Alarm_Buzzer.ogg:system/media/audio/alarms/Alarm_Buzzer.ogg \
- $(LOCAL_PATH)/Alarm_Classic.ogg:system/media/audio/alarms/Alarm_Classic.ogg \
- $(LOCAL_PATH)/Alarm_Rooster_02.ogg:system/media/audio/alarms/Alarm_Rooster_02.ogg \
- $(LOCAL_PATH)/alarms/ogg/Argon.ogg:system/media/audio/alarms/Argon.ogg \
- $(LOCAL_PATH)/alarms/ogg/Barium.ogg:system/media/audio/alarms/Barium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Carbon.ogg:system/media/audio/alarms/Carbon.ogg \
- $(LOCAL_PATH)/alarms/ogg/Cesium.ogg:system/media/audio/alarms/Cesium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Fermium.ogg:system/media/audio/alarms/Fermium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Hassium.ogg:system/media/audio/alarms/Hassium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Helium.ogg:system/media/audio/alarms/Helium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Krypton.ogg:system/media/audio/alarms/Krypton.ogg \
- $(LOCAL_PATH)/alarms/ogg/Neon.ogg:system/media/audio/alarms/Neon.ogg \
- $(LOCAL_PATH)/alarms/ogg/Neptunium.ogg:system/media/audio/alarms/Neptunium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Nobelium.ogg:system/media/audio/alarms/Nobelium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Oxygen.ogg:system/media/audio/alarms/Oxygen.ogg \
- $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
- $(LOCAL_PATH)/alarms/ogg/Plutonium.ogg:system/media/audio/alarms/Plutonium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Promethium.ogg:system/media/audio/alarms/Promethium.ogg \
- $(LOCAL_PATH)/alarms/ogg/Scandium.ogg:system/media/audio/alarms/Scandium.ogg \
- $(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
- $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
- $(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
- $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
- $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
- $(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
- $(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
- $(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:system/media/audio/ui/Trusted.ogg \
- $(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
- $(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
- $(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
- $(LOCAL_PATH)/effects/ogg/VideoStop_48k.ogg:system/media/audio/ui/VideoStop.ogg \
- $(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
- $(LOCAL_PATH)/F1_MissedCall.ogg:system/media/audio/notifications/F1_MissedCall.ogg \
- $(LOCAL_PATH)/F1_New_MMS.ogg:system/media/audio/notifications/F1_New_MMS.ogg \
- $(LOCAL_PATH)/F1_New_SMS.ogg:system/media/audio/notifications/F1_New_SMS.ogg \
- $(LOCAL_PATH)/notifications/Aldebaran.ogg:system/media/audio/notifications/Aldebaran.ogg \
- $(LOCAL_PATH)/notifications/Altair.ogg:system/media/audio/notifications/Altair.ogg \
- $(LOCAL_PATH)/notifications/Antares.ogg:system/media/audio/notifications/Antares.ogg \
- $(LOCAL_PATH)/notifications/arcturus.ogg:system/media/audio/notifications/arcturus.ogg \
- $(LOCAL_PATH)/notifications/Beat_Box_Android.ogg:system/media/audio/notifications/Beat_Box_Android.ogg \
- $(LOCAL_PATH)/notifications/Betelgeuse.ogg:system/media/audio/notifications/Betelgeuse.ogg \
- $(LOCAL_PATH)/notifications/Canopus.ogg:system/media/audio/notifications/Canopus.ogg \
- $(LOCAL_PATH)/notifications/Castor.ogg:system/media/audio/notifications/Castor.ogg \
- $(LOCAL_PATH)/notifications/Cricket.ogg:system/media/audio/notifications/Cricket.ogg \
- $(LOCAL_PATH)/notifications/Deneb.ogg:system/media/audio/notifications/Deneb.ogg \
- $(LOCAL_PATH)/notifications/Doink.ogg:system/media/audio/notifications/Doink.ogg \
- $(LOCAL_PATH)/notifications/Drip.ogg:system/media/audio/notifications/Drip.ogg \
- $(LOCAL_PATH)/notifications/Electra.ogg:system/media/audio/notifications/Electra.ogg \
- $(LOCAL_PATH)/notifications/Fomalhaut.ogg:system/media/audio/notifications/Fomalhaut.ogg \
- $(LOCAL_PATH)/notifications/Heaven.ogg:system/media/audio/notifications/Heaven.ogg \
- $(LOCAL_PATH)/notifications/Merope.ogg:system/media/audio/notifications/Merope.ogg \
- $(LOCAL_PATH)/notifications/moonbeam.ogg:system/media/audio/notifications/moonbeam.ogg \
- $(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
- $(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
- $(LOCAL_PATH)/notifications/ogg/Antimony.ogg:system/media/audio/notifications/Antimony.ogg \
- $(LOCAL_PATH)/notifications/ogg/Arcturus.ogg:system/media/audio/notifications/Arcturus.ogg \
- $(LOCAL_PATH)/notifications/ogg/Argon.ogg:system/media/audio/notifications/Argon.ogg \
- $(LOCAL_PATH)/notifications/ogg/Bellatrix.ogg:system/media/audio/notifications/Bellatrix.ogg \
- $(LOCAL_PATH)/notifications/ogg/Beryllium.ogg:system/media/audio/notifications/Beryllium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg \
- $(LOCAL_PATH)/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg \
- $(LOCAL_PATH)/notifications/ogg/Cobalt.ogg:system/media/audio/notifications/Cobalt.ogg \
- $(LOCAL_PATH)/notifications/ogg/Fluorine.ogg:system/media/audio/notifications/Fluorine.ogg \
- $(LOCAL_PATH)/notifications/ogg/Gallium.ogg:system/media/audio/notifications/Gallium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Helium.ogg:system/media/audio/notifications/Helium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Hojus.ogg:system/media/audio/notifications/Hojus.ogg \
- $(LOCAL_PATH)/notifications/ogg/Iridium.ogg:system/media/audio/notifications/Iridium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Krypton.ogg:system/media/audio/notifications/Krypton.ogg \
- $(LOCAL_PATH)/notifications/ogg/Lalande.ogg:system/media/audio/notifications/Lalande.ogg \
- $(LOCAL_PATH)/notifications/ogg/Mira.ogg:system/media/audio/notifications/Mira.ogg \
- $(LOCAL_PATH)/notifications/ogg/Palladium.ogg:system/media/audio/notifications/Palladium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg \
- $(LOCAL_PATH)/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg \
- $(LOCAL_PATH)/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg \
- $(LOCAL_PATH)/notifications/ogg/Proxima.ogg:system/media/audio/notifications/Proxima.ogg \
- $(LOCAL_PATH)/notifications/ogg/Radon.ogg:system/media/audio/notifications/Radon.ogg \
- $(LOCAL_PATH)/notifications/ogg/Rubidium.ogg:system/media/audio/notifications/Rubidium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Selenium.ogg:system/media/audio/notifications/Selenium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Shaula.ogg:system/media/audio/notifications/Shaula.ogg \
- $(LOCAL_PATH)/notifications/ogg/Spica.ogg:system/media/audio/notifications/Spica.ogg \
- $(LOCAL_PATH)/notifications/ogg/Strontium.ogg:system/media/audio/notifications/Strontium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Syrma.ogg:system/media/audio/notifications/Syrma.ogg \
- $(LOCAL_PATH)/notifications/ogg/Talitha.ogg:system/media/audio/notifications/Talitha.ogg \
- $(LOCAL_PATH)/notifications/ogg/Tejat.ogg:system/media/audio/notifications/Tejat.ogg \
- $(LOCAL_PATH)/notifications/ogg/Thallium.ogg:system/media/audio/notifications/Thallium.ogg \
- $(LOCAL_PATH)/notifications/ogg/Upsilon.ogg:system/media/audio/notifications/Upsilon.ogg \
- $(LOCAL_PATH)/notifications/ogg/Vega.ogg:system/media/audio/notifications/Vega.ogg \
- $(LOCAL_PATH)/notifications/ogg/Xenon.ogg:system/media/audio/notifications/Xenon.ogg \
- $(LOCAL_PATH)/notifications/ogg/Zirconium.ogg:system/media/audio/notifications/Zirconium.ogg \
- $(LOCAL_PATH)/notifications/pixiedust.ogg:system/media/audio/notifications/pixiedust.ogg \
- $(LOCAL_PATH)/notifications/pizzicato.ogg:system/media/audio/notifications/pizzicato.ogg \
- $(LOCAL_PATH)/notifications/Plastic_Pipe.ogg:system/media/audio/notifications/Plastic_Pipe.ogg \
- $(LOCAL_PATH)/notifications/regulus.ogg:system/media/audio/notifications/regulus.ogg \
- $(LOCAL_PATH)/notifications/sirius.ogg:system/media/audio/notifications/sirius.ogg \
- $(LOCAL_PATH)/notifications/Sirrah.ogg:system/media/audio/notifications/Sirrah.ogg \
- $(LOCAL_PATH)/notifications/SpaceSeed.ogg:system/media/audio/notifications/SpaceSeed.ogg \
- $(LOCAL_PATH)/notifications/TaDa.ogg:system/media/audio/notifications/TaDa.ogg \
- $(LOCAL_PATH)/notifications/Tinkerbell.ogg:system/media/audio/notifications/Tinkerbell.ogg \
- $(LOCAL_PATH)/notifications/tweeters.ogg:system/media/audio/notifications/tweeters.ogg \
- $(LOCAL_PATH)/notifications/vega.ogg:system/media/audio/notifications/vega.ogg
+ $(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index 898939e..4f467d9 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -31,6 +31,7 @@
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -348,7 +349,7 @@
if (mRunnable == null) {
mRunnable = this::invalidateSelf;
}
- scheduleSelf(mRunnable, nextUpdate);
+ scheduleSelf(mRunnable, nextUpdate + SystemClock.uptimeMillis());
} else if (nextUpdate == FINISHED) {
// This means the animation was drawn in software mode and ended.
postOnAnimationEnd();
@@ -430,23 +431,6 @@
return mState.mAutoMirrored;
}
- @Override
- public boolean setVisible(boolean visible, boolean restart) {
- if (!super.setVisible(visible, restart)) {
- return false;
- }
-
- if (mState.mNativePtr == 0) {
- throw new IllegalStateException("called setVisible on empty AnimatedImageDrawable");
- }
-
- if (!visible) {
- nMarkInvisible(mState.mNativePtr);
- }
-
- return true;
- }
-
// Animatable overrides
/**
* Return whether the animation is currently running.
@@ -616,7 +600,5 @@
@FastNative
private static native long nNativeByteSize(long nativePtr);
@FastNative
- private static native void nMarkInvisible(long nativePtr);
- @FastNative
private static native void nSetMirrored(long nativePtr, boolean mirror);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
index cc80560..624321c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
@@ -48,6 +48,8 @@
private static final String KEYSTORE_PUBLIC_KEY_CLASS_NAME =
PACKAGE_NAME + ".AndroidKeyStorePublicKey";
+ private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede";
+
AndroidKeyStoreBCWorkaroundProvider() {
super("AndroidKeyStoreBCWorkaround",
1.0,
@@ -93,7 +95,7 @@
putSymmetricCipherImpl("AES/CTR/NoPadding",
PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");
- if ("true".equals(System.getProperty("supports3DES"))) {
+ if ("true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY))) {
putSymmetricCipherImpl("DESede/CBC/NoPadding",
PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 9b7695d..c048e82 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -64,10 +64,13 @@
private static final String PACKAGE_NAME = "android.security.keystore";
+ private static final String DESEDE_SYSTEM_PROPERTY =
+ "ro.hardware.keystore_desede";
+
public AndroidKeyStoreProvider() {
super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
- boolean supports3DES = "true".equals(System.getProperty("supports3DES"));
+ boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY));
// java.security.KeyStore
put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 3e9853c..2b5a37b 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -353,6 +353,10 @@
if (spec.isCriticalToDeviceEncryption()) {
flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
}
+
+ if (spec.isStrongBoxBacked()) {
+ flags |= KeyStore.FLAG_STRONGBOX;
+ }
} else {
throw new KeyStoreException(
"Unsupported protection parameter class:" + param.getClass().getName()
@@ -720,6 +724,9 @@
if (params.isCriticalToDeviceEncryption()) {
flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
}
+ if (params.isStrongBoxBacked()) {
+ flags |= KeyStore.FLAG_STRONGBOX;
+ }
Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + entryAlias;
@@ -737,19 +744,76 @@
}
}
- private void setWrappedKeyEntry(String alias, byte[] wrappedKeyBytes, String wrappingKeyAlias,
+ private void setWrappedKeyEntry(String alias, WrappedKeyEntry entry,
java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
if (param != null) {
throw new KeyStoreException("Protection parameters are specified inside wrapped keys");
}
byte[] maskingKey = new byte[32];
- KeymasterArguments args = new KeymasterArguments(); // TODO: populate wrapping key args.
+
+
+ KeymasterArguments args = new KeymasterArguments();
+ String[] parts = entry.getTransformation().split("/");
+
+ String algorithm = parts[0];
+ if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
+ args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
+ } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
+ args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
+ }
+
+ if (parts.length > 1) {
+ String mode = parts[1];
+ if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(mode)) {
+ args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
+ } else if (KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(mode)) {
+ args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CBC);
+ } else if (KeyProperties.BLOCK_MODE_CTR.equalsIgnoreCase(mode)) {
+ args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
+ } else if (KeyProperties.BLOCK_MODE_GCM.equalsIgnoreCase(mode)) {
+ args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
+ }
+ }
+
+ if (parts.length > 2) {
+ String padding = parts[2];
+ if (KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
+ // Noop
+ } else if (KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
+ args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
+ } else if (KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) {
+ args.addEnums(KeymasterDefs.KM_TAG_PADDING,
+ KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
+ } else if (KeyProperties.ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) {
+ args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
+ }
+ }
+
+ KeyGenParameterSpec spec = (KeyGenParameterSpec) entry.getAlgorithmParameterSpec();
+ if (spec.isDigestsSpecified()) {
+ String digest = spec.getDigests()[0];
+ if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) {
+ // Noop
+ } else if (KeyProperties.DIGEST_MD5.equalsIgnoreCase(digest)) {
+ args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
+ } else if (KeyProperties.DIGEST_SHA1.equalsIgnoreCase(digest)) {
+ args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
+ } else if (KeyProperties.DIGEST_SHA224.equalsIgnoreCase(digest)) {
+ args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
+ } else if (KeyProperties.DIGEST_SHA256.equalsIgnoreCase(digest)) {
+ args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
+ } else if (KeyProperties.DIGEST_SHA384.equalsIgnoreCase(digest)) {
+ args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
+ } else if (KeyProperties.DIGEST_SHA512.equalsIgnoreCase(digest)) {
+ args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
+ }
+ }
int errorCode = mKeyStore.importWrappedKey(
Credentials.USER_SECRET_KEY + alias,
- wrappedKeyBytes,
- Credentials.USER_PRIVATE_KEY + wrappingKeyAlias,
+ entry.getWrappedKeyBytes(),
+ Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(),
maskingKey,
args,
GateKeeper.getSecureUserId(),
@@ -996,7 +1060,7 @@
setSecretKeyEntry(alias, secE.getSecretKey(), param);
} else if (entry instanceof WrappedKeyEntry) {
WrappedKeyEntry wke = (WrappedKeyEntry) entry;
- setWrappedKeyEntry(alias, wke.getWrappedKeyBytes(), wke.getWrappingKeyAlias(), param);
+ setWrappedKeyEntry(alias, wke, param);
} else {
throw new KeyStoreException(
"Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry"
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index fdcad85..081042b 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -232,6 +232,7 @@
private final boolean mCriticalToDeviceEncryption;
private final boolean mUserConfirmationRequired;
private final boolean mUnlockedDeviceRequired;
+ private final boolean mIsStrongBoxBacked;
private KeyProtection(
Date keyValidityStart,
@@ -251,7 +252,8 @@
long boundToSecureUserId,
boolean criticalToDeviceEncryption,
boolean userConfirmationRequired,
- boolean unlockedDeviceRequired) {
+ boolean unlockedDeviceRequired,
+ boolean isStrongBoxBacked) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -272,6 +274,7 @@
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
mUserConfirmationRequired = userConfirmationRequired;
mUnlockedDeviceRequired = unlockedDeviceRequired;
+ mIsStrongBoxBacked = isStrongBoxBacked;
}
/**
@@ -529,6 +532,14 @@
}
/**
+ * Returns {@code true} if the key is protected by a Strongbox security chip.
+ * @hide
+ */
+ public boolean isStrongBoxBacked() {
+ return mIsStrongBoxBacked;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -552,6 +563,7 @@
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
private boolean mCriticalToDeviceEncryption = false;
+ private boolean mIsStrongBoxBacked = false;
/**
* Creates a new instance of the {@code Builder}.
@@ -962,6 +974,16 @@
}
/**
+ * Sets whether this key should be protected by a StrongBox security chip.
+ * @hide
+ */
+ @NonNull
+ public Builder setIsStrongBoxBacked(boolean isStrongBoxBacked) {
+ mIsStrongBoxBacked = isStrongBoxBacked;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -986,7 +1008,8 @@
mBoundToSecureUserId,
mCriticalToDeviceEncryption,
mUserConfirmationRequired,
- mUnlockedDeviceRequired);
+ mUnlockedDeviceRequired,
+ mIsStrongBoxBacked);
}
}
}
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index d701269..b37f2cf 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -108,6 +108,12 @@
// *OR* will post itself for the next vsync automatically, use this
// only to avoid calling draw()
bool canDrawThisFrame = true;
+ // Sentinel for animatedImageDelay meaning there is no need to post such
+ // a message.
+ static constexpr nsecs_t kNoAnimatedImageDelay = -1;
+ // This is used to post a message to redraw when it is time to draw the
+ // next frame of an AnimatedImageDrawable.
+ nsecs_t animatedImageDelay = kNoAnimatedImageDelay;
} out;
// This flag helps to disable projection for receiver nodes that do not have any backward
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index c529f87..007961a 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -22,13 +22,12 @@
#include <SkPicture.h>
#include <SkRefCnt.h>
#include <SkTLazy.h>
-#include <SkTime.h>
namespace android {
AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed)
: mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) {
- mTimeToShowNextSnapshot = mSkAnimatedImage->currentFrameDuration();
+ mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration());
}
void AnimatedImageDrawable::syncProperties() {
@@ -62,28 +61,42 @@
}
// Only called on the RenderThread while UI thread is locked.
-bool AnimatedImageDrawable::isDirty() {
- const double currentTime = SkTime::GetMSecs();
- const double lastWallTime = mLastWallTime;
+bool AnimatedImageDrawable::isDirty(nsecs_t* outDelay) {
+ *outDelay = 0;
+ const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC);
+ const nsecs_t lastWallTime = mLastWallTime;
mLastWallTime = currentTime;
if (!mRunning) {
- mDidDraw = false;
return false;
}
std::unique_lock lock{mSwapLock};
- if (mDidDraw) {
- mCurrentTime += currentTime - lastWallTime;
- mDidDraw = false;
- }
+ mCurrentTime += currentTime - lastWallTime;
if (!mNextSnapshot.valid()) {
// Need to trigger onDraw in order to start decoding the next frame.
+ *outDelay = mTimeToShowNextSnapshot - mCurrentTime;
return true;
}
- return nextSnapshotReady() && mCurrentTime >= mTimeToShowNextSnapshot;
+ if (mTimeToShowNextSnapshot > mCurrentTime) {
+ *outDelay = mTimeToShowNextSnapshot - mCurrentTime;
+ } else if (nextSnapshotReady()) {
+ // We have not yet updated mTimeToShowNextSnapshot. Read frame duration
+ // directly from mSkAnimatedImage.
+ lock.unlock();
+ std::unique_lock imageLock{mImageLock};
+ *outDelay = ms2ns(mSkAnimatedImage->currentFrameDuration());
+ return true;
+ } else {
+ // The next snapshot has not yet been decoded, but we've already passed
+ // time to draw it. There's not a good way to know when decoding will
+ // finish, so request an update immediately.
+ *outDelay = 0;
+ }
+
+ return false;
}
// Only called on the AnimatedImageThread.
@@ -91,7 +104,7 @@
Snapshot snap;
{
std::unique_lock lock{mImageLock};
- snap.mDuration = mSkAnimatedImage->decodeNextFrame();
+ snap.mDurationMS = mSkAnimatedImage->decodeNextFrame();
snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
}
@@ -105,7 +118,7 @@
std::unique_lock lock{mImageLock};
mSkAnimatedImage->reset();
snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
- snap.mDuration = mSkAnimatedImage->currentFrameDuration();
+ snap.mDurationMS = mSkAnimatedImage->currentFrameDuration();
}
return snap;
@@ -127,8 +140,6 @@
canvas->scale(-1, 1);
}
- mDidDraw = true;
-
const bool starting = mStarting;
mStarting = false;
@@ -157,12 +168,12 @@
std::unique_lock lock{mSwapLock};
if (mCurrentTime >= mTimeToShowNextSnapshot) {
mSnapshot = mNextSnapshot.get();
- const double timeToShowCurrentSnap = mTimeToShowNextSnapshot;
- if (mSnapshot.mDuration == SkAnimatedImage::kFinished) {
+ const nsecs_t timeToShowCurrentSnap = mTimeToShowNextSnapshot;
+ if (mSnapshot.mDurationMS == SkAnimatedImage::kFinished) {
finalFrame = true;
mRunning = false;
} else {
- mTimeToShowNextSnapshot += mSnapshot.mDuration;
+ mTimeToShowNextSnapshot += ms2ns(mSnapshot.mDurationMS);
if (mCurrentTime >= mTimeToShowNextSnapshot) {
// This would mean showing the current frame very briefly. It's
// possible that not being displayed for a time resulted in
@@ -192,7 +203,7 @@
}
}
-double AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
+int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
SkAutoCanvasRestore acr(canvas, false);
if (mStagingProperties.mAlpha != SK_AlphaOPAQUE || mStagingProperties.mColorFilter.get()) {
SkPaint paint;
@@ -211,69 +222,69 @@
// to redraw.
std::unique_lock lock{mImageLock};
canvas->drawDrawable(mSkAnimatedImage.get());
- return 0.0;
+ return 0;
}
if (mStarting) {
mStarting = false;
- double duration = 0.0;
+ int durationMS = 0;
{
std::unique_lock lock{mImageLock};
mSkAnimatedImage->reset();
- duration = mSkAnimatedImage->currentFrameDuration();
+ durationMS = mSkAnimatedImage->currentFrameDuration();
}
{
std::unique_lock lock{mSwapLock};
- mLastWallTime = 0.0;
- mTimeToShowNextSnapshot = duration;
+ mLastWallTime = 0;
+ // The current time will be added later, below.
+ mTimeToShowNextSnapshot = ms2ns(durationMS);
}
}
bool update = false;
{
- const double currentTime = SkTime::GetMSecs();
+ const nsecs_t currentTime = systemTime(CLOCK_MONOTONIC);
std::unique_lock lock{mSwapLock};
// mLastWallTime starts off at 0. If it is still 0, just update it to
// the current time and avoid updating
- if (mLastWallTime == 0.0) {
+ if (mLastWallTime == 0) {
mCurrentTime = currentTime;
// mTimeToShowNextSnapshot is already set to the duration of the
// first frame.
mTimeToShowNextSnapshot += currentTime;
- } else if (mRunning && mDidDraw) {
+ } else if (mRunning) {
mCurrentTime += currentTime - mLastWallTime;
update = mCurrentTime >= mTimeToShowNextSnapshot;
}
mLastWallTime = currentTime;
}
- double duration = 0.0;
+ int durationMS = 0;
{
std::unique_lock lock{mImageLock};
if (update) {
- duration = mSkAnimatedImage->decodeNextFrame();
+ durationMS = mSkAnimatedImage->decodeNextFrame();
}
canvas->drawDrawable(mSkAnimatedImage.get());
}
- mDidDraw = true;
-
std::unique_lock lock{mSwapLock};
if (update) {
- if (duration == SkAnimatedImage::kFinished) {
+ if (durationMS == SkAnimatedImage::kFinished) {
mRunning = false;
- return duration;
+ return SkAnimatedImage::kFinished;
}
- const double timeToShowCurrentSnapshot = mTimeToShowNextSnapshot;
- mTimeToShowNextSnapshot += duration;
+ const nsecs_t timeToShowCurrentSnapshot = mTimeToShowNextSnapshot;
+ mTimeToShowNextSnapshot += ms2ns(durationMS);
if (mCurrentTime >= mTimeToShowNextSnapshot) {
// As in onDraw, prevent speedy catch-up behavior.
mCurrentTime = timeToShowCurrentSnapshot;
}
}
- return mTimeToShowNextSnapshot;
+
+ return ns2ms(mTimeToShowNextSnapshot - mCurrentTime);
}
} // namespace android
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index a92b62d..115c45a 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -19,6 +19,7 @@
#include <cutils/compiler.h>
#include <utils/Macros.h>
#include <utils/RefBase.h>
+#include <utils/Timers.h>
#include <SkAnimatedImage.h>
#include <SkCanvas.h>
@@ -50,12 +51,15 @@
AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed);
/**
- * This updates the internal time and returns true if the animation needs
- * to be redrawn.
+ * This updates the internal time and returns true if the image needs
+ * to be redrawn this frame.
*
* This is called on RenderThread, while the UI thread is locked.
+ *
+ * @param outDelay Nanoseconds in the future when the following frame
+ * will need to be drawn. 0 if not running.
*/
- bool isDirty();
+ bool isDirty(nsecs_t* outDelay);
int getStagingAlpha() const { return mStagingProperties.mAlpha; }
void setStagingAlpha(int alpha) { mStagingProperties.mAlpha = alpha; }
@@ -68,7 +72,9 @@
virtual SkRect onGetBounds() override { return mSkAnimatedImage->getBounds(); }
// Draw to software canvas, and return time to next draw.
- double drawStaging(SkCanvas* canvas);
+ // 0 means the animation is not running.
+ // -1 means the animation advanced to the final frame.
+ int drawStaging(SkCanvas* canvas);
// Returns true if the animation was started; false otherwise (e.g. it was
// already running)
@@ -84,11 +90,9 @@
mEndListener = std::move(listener);
}
- void markInvisible() { mDidDraw = false; }
-
struct Snapshot {
sk_sp<SkPicture> mPic;
- int mDuration;
+ int mDurationMS;
Snapshot() = default;
@@ -124,16 +128,13 @@
bool nextSnapshotReady() const;
// When to switch from mSnapshot to mNextSnapshot.
- double mTimeToShowNextSnapshot = 0.0;
+ nsecs_t mTimeToShowNextSnapshot = 0;
// The current time for the drawable itself.
- double mCurrentTime = 0.0;
+ nsecs_t mCurrentTime = 0;
// The wall clock of the last time we called isDirty.
- double mLastWallTime = 0.0;
-
- // Whether we drew since the last call to isDirty.
- bool mDidDraw = false;
+ nsecs_t mLastWallTime = 0;
// Locked when assigning snapshots and times. Operations while this is held
// should be short.
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index aa14699..82179a3 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -93,12 +93,18 @@
bool isDirty = false;
for (auto& animatedImage : mAnimatedImages) {
+ nsecs_t timeTilNextFrame = TreeInfo::Out::kNoAnimatedImageDelay;
// If any animated image in the display list needs updated, then damage the node.
- if (animatedImage->isDirty()) {
+ if (animatedImage->isDirty(&timeTilNextFrame)) {
isDirty = true;
}
- if (animatedImage->isRunning()) {
- info.out.hasAnimations = true;
+
+ if (animatedImage->isRunning() &&
+ timeTilNextFrame != TreeInfo::Out::kNoAnimatedImageDelay) {
+ auto& delay = info.out.animatedImageDelay;
+ if (delay == TreeInfo::Out::kNoAnimatedImageDelay || timeTilNextFrame < delay) {
+ delay = timeTilNextFrame;
+ }
}
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f4d8051..2ddf55b 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -140,6 +140,7 @@
IContextFactory* contextFactory,
std::unique_ptr<IRenderPipeline> renderPipeline)
: mRenderThread(thread)
+ , mGenerationID(0)
, mOpaque(!translucent)
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
, mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo())
@@ -196,6 +197,7 @@
mSwapHistory.clear();
} else {
mRenderThread.removeFrameCallback(this);
+ mGenerationID++;
}
}
@@ -204,6 +206,7 @@
}
bool CanvasContext::pauseSurface() {
+ mGenerationID++;
return mRenderThread.removeFrameCallback(this);
}
@@ -211,6 +214,7 @@
if (mStopped != stopped) {
mStopped = stopped;
if (mStopped) {
+ mGenerationID++;
mRenderThread.removeFrameCallback(this);
mRenderPipeline->onStop();
} else if (mIsDirty && hasSurface()) {
@@ -383,6 +387,7 @@
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
}
+ bool postedFrameCallback = false;
if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
if (CC_UNLIKELY(!Properties::enableRTAnimations)) {
info.out.requiresUiRedraw = true;
@@ -391,6 +396,24 @@
// If animationsNeedsRedraw is set don't bother posting for an RT anim
// as we will just end up fighting the UI thread.
mRenderThread.postFrameCallback(this);
+ postedFrameCallback = true;
+ }
+ }
+
+ if (!postedFrameCallback &&
+ info.out.animatedImageDelay != TreeInfo::Out::kNoAnimatedImageDelay) {
+ // Subtract the time of one frame so it can be displayed on time.
+ const nsecs_t kFrameTime = mRenderThread.timeLord().frameIntervalNanos();
+ if (info.out.animatedImageDelay <= kFrameTime) {
+ mRenderThread.postFrameCallback(this);
+ } else {
+ const auto delay = info.out.animatedImageDelay - kFrameTime;
+ int genId = mGenerationID;
+ mRenderThread.queue().postDelayed(delay, [this, genId]() {
+ if (mGenerationID == genId) {
+ mRenderThread.postFrameCallback(this);
+ }
+ });
}
}
}
@@ -398,6 +421,7 @@
void CanvasContext::stopDrawing() {
mRenderThread.removeFrameCallback(this);
mAnimationContext->pauseAnimators();
+ mGenerationID++;
}
void CanvasContext::notifyFramePending() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index c2cc72a..e52b644 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -213,6 +213,9 @@
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
+ // Incremented each time the CanvasContext is stopped. Used to ignore
+ // delayed messages that are triggered after stopping.
+ int mGenerationID;
// CanvasContext is dirty if it has received an update that it has not
// painted onto its surface.
bool mIsDirty = false;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 778e768..60df514 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -95,6 +95,7 @@
// Grab a copy of everything we need
CanvasContext* context = mContext;
std::function<void(int64_t)> callback = std::move(mFrameCallback);
+ mFrameCallback = nullptr;
// From this point on anything in "this" is *UNSAFE TO ACCESS*
if (canUnblockUiThread) {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 1f00c78..02bf4e3 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1584,6 +1584,20 @@
*/
public static final int BUFFER_FLAG_PARTIAL_FRAME = 8;
+ /**
+ * This indicates that the buffer contains non-media data for the
+ * muxer to process.
+ *
+ * All muxer data should start with a FOURCC header that determines the type of data.
+ *
+ * For example, when it contains Exif data sent to a MediaMuxer track of
+ * {@link MediaFormat#MIMETYPE_IMAGE_ANDROID_HEIC} type, the data must start with
+ * Exif header ("Exif\0\0"), followed by the TIFF header (See JEITA CP-3451C Section 4.5.2.)
+ *
+ * @hide
+ */
+ public static final int BUFFER_FLAG_MUXER_DATA = 16;
+
/** @hide */
@IntDef(
flag = true,
@@ -1593,6 +1607,7 @@
BUFFER_FLAG_CODEC_CONFIG,
BUFFER_FLAG_END_OF_STREAM,
BUFFER_FLAG_PARTIAL_FRAME,
+ BUFFER_FLAG_MUXER_DATA,
})
@Retention(RetentionPolicy.SOURCE)
public @interface BufferFlag {}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 384326f..7c68b55 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -87,7 +87,7 @@
* <tr><td>{@link #KEY_AAC_DRC_ATTENUATION_FACTOR}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the DRC attenuation factor.</td></tr>
* <tr><td>{@link #KEY_AAC_DRC_HEAVY_COMPRESSION}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies whether to use heavy compression.</td></tr>
* <tr><td>{@link #KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the maximum number of channels the decoder outputs.</td></tr>
- * <tr><td>{@link #KEY_AAC_DRC_EFFECT_TYPE}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the DRC effect type to use.</td></tr>
+ * <tr><td>{@link #KEY_AAC_DRC_EFFECT_TYPE}</td><td>Integer</td><td><b>decoder-only</b>, optional, if content is AAC audio, specifies the MPEG-D DRC effect type to use.</td></tr>
* <tr><td>{@link #KEY_CHANNEL_MASK}</td><td>Integer</td><td>optional, a mask of audio channel assignments</td></tr>
* <tr><td>{@link #KEY_FLAC_COMPRESSION_LEVEL}</td><td>Integer</td><td><b>encoder-only</b>, optional, if content is FLAC audio, specifies the desired compression level.</td></tr>
* </table>
@@ -515,9 +515,12 @@
* The gain is derived as the difference between the Target Reference Level and the
* Program Reference Level. The latter can be given in the bitstream and indicates the actual
* loudness value of the program item.
+ * <p>The Target Reference Level controls loudness normalization for both MPEG-4 DRC and
+ * MPEG-D DRC.
* <p>The value is given as an integer value between
- * 0 and 127, and is calculated as -0.25 * Target Reference Level in dBFS.
- * Therefore, it represents the range of Full Scale (0 dBFS) to -31.75 dBFS.
+ * 40 and 127, and is calculated as -4 * Target Reference Level in LKFS.
+ * Therefore, it represents the range of -10 to -31.75 LKFS.
+ * <p>The default value on mobile devices is 64 (-16 LKFS).
* <p>This key is only used during decoding.
*/
public static final String KEY_AAC_DRC_TARGET_REFERENCE_LEVEL = "aac-target-ref-level";
@@ -542,19 +545,18 @@
* clipping<br>
* The value 6 (General compression) can be used for enabling MPEG-D DRC without particular
* DRC effect type request.<br>
- * The default is DRC effect type "None".
+ * The default DRC effect type is 3 ("Limited playback range") on mobile devices.
* <p>This key is only used during decoding.
*/
public static final String KEY_AAC_DRC_EFFECT_TYPE = "aac-drc-effect-type";
/**
* A key describing the target reference level that was assumed at the encoder for
- * calculation of attenuation gains for clipping prevention. This information can be provided
- * if it is known, otherwise a worst-case assumption is used.
- * <p>The value is given as an integer value between
- * 0 and 127, and is calculated as -0.25 * Target Reference Level in dBFS.
- * Therefore, it represents the range of Full Scale (0 dBFS) to -31.75 dBFS.
- * The default value is the worst-case assumption of 127.
+ * calculation of attenuation gains for clipping prevention.
+ * <p>If it is known, this information can be provided as an integer value between
+ * 0 and 127, which is calculated as -4 * Encoded Target Level in LKFS.
+ * If the Encoded Target Level is unknown, the value can be set to -1.
+ * <p>The default value is -1 (unknown).
* <p>The value is ignored when heavy compression is used (see
* {@link #KEY_AAC_DRC_HEAVY_COMPRESSION}).
* <p>This key is only used during decoding.
@@ -576,11 +578,12 @@
* factor is used to enable the negative gains, to prevent loud signal from surprising
* the listener. In applications which generally need a low dynamic range, both the boost factor
* and the attenuation factor are used in order to enable all DRC gains.
- * <p>In order to prevent clipping, it is also recommended to apply the attenuation factors
+ * <p>In order to prevent clipping, it is also recommended to apply the attenuation gains
* in case of a downmix and/or loudness normalization to high target reference levels.
* <p>Both the boost and the attenuation factor parameters are given as integer values
* between 0 and 127, representing the range of the factor of 0 (i.e. don't apply)
- * to 1 (i.e. fully apply boost/attenuation factors respectively).
+ * to 1 (i.e. fully apply boost/attenuation gains respectively).
+ * <p>The default value is 127 (fully apply boost DRC gains).
* <p>This key is only used during decoding.
*/
public static final String KEY_AAC_DRC_BOOST_FACTOR = "aac-drc-boost-level";
@@ -590,6 +593,7 @@
* actual listening requirements.
* See {@link #KEY_AAC_DRC_BOOST_FACTOR} for a description of the role of this attenuation
* factor and the value range.
+ * <p>The default value is 127 (fully apply attenuation DRC gains).
* <p>This key is only used during decoding.
*/
public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level";
@@ -609,7 +613,7 @@
* Light compression usually contains clipping prevention for stereo downmixing while heavy
* compression, if additionally provided in the bitstream, is usually stronger, and contains
* clipping prevention for stereo and mono downmixing.
- * <p>The default is light compression.
+ * <p>The default is 1 (heavy compression).
* <p>This key is only used during decoding.
*/
public static final String KEY_AAC_DRC_HEAVY_COMPRESSION = "aac-drc-heavy-compression";
diff --git a/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml b/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml
index 061f9fe..44b1866 100644
--- a/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml
+++ b/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml
@@ -17,50 +17,12 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="ic_rotate_to_landscape"
- android:height="48dp"
- android:width="48dp"
- android:viewportHeight="48"
- android:viewportWidth="48"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
android:tint="?android:attr/colorControlNormal" >
- <group
- android:name="device"
- android:translateX="24"
- android:translateY="24" >
- <group
- android:name="device_pivot"
- android:translateX="-24.15"
- android:translateY="-24.25" >
- <group
- android:name="landscape"
- android:translateX="24"
- android:translateY="24"
- android:scaleX="0.909"
- android:scaleY="0.909"
- android:rotation="45" >
- <path
- android:name="device_merged"
- android:pathData="M -21.9799957275,-10.0 c 0.0,0.0 -0.0200042724609,20.0 -0.0200042724609,20.0 c 0.0,2.19999694824 1.80000305176,4.0 4.0,4.0 c 0.0,0.0 36.0,0.0 36.0,0.0 c 2.19999694824,0.0 4.0,-1.80000305176 4.0,-4.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,-2.19999694824 -1.80000305176,-4.0 -4.0,-4.0 c 0.0,0.0 -36.0,0.0 -36.0,0.0 c -2.19999694824,0.0 -3.97999572754,1.80000305176 -3.97999572754,4.0 Z M 14.0,10.0 c 0.0,0.0 -28.0,0.0 -28.0,0.0 c 0.0,0.0 0.0,-20.0 0.0,-20.0 c 0.0,0.0 28.0,0.0 28.0,0.0 c 0.0,0.0 0.0,20.0 0.0,20.0 Z"
- android:fillColor="#FFFFFFFF" />
- </group>
- </group>
- </group>
- <group
- android:name="arrows"
- android:translateX="24"
- android:translateY="24" >
- <group
- android:name="arrows_pivot"
- android:translateX="-24.0798"
- android:translateY="-24.23" >
- <group
- android:name="arrows_0"
- android:translateX="12.2505"
- android:translateY="37.2145" >
- <path
- android:name="bottom_merged"
- android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
- android:fillColor="#FFFFFFFF" />
- </group>
- </group>
- </group>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.72,23H11C5.49,23 1,18.51 1,13h2c0,3.78 2.63,6.95 6.15,7.79L8.13,19L9.87,18L12.72,23zM13,1h-1.72l2.85,5L15.87,5l-1.02,-1.79C18.37,4.05 21,7.22 21,11h2C23,5.49 18.51,1 13,1zM10.23,6L18,13.76L13.77,18L6,10.24L10.23,6C10.23,6 10.23,6 10.23,6M10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82l-7.77,-7.77C11.26,4.2 10.75,4 10.23,4L10.23,4z"/>
</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_settings_print.xml b/packages/SettingsLib/res/drawable/ic_settings_print.xml
index 0eab402..68b627c 100644
--- a/packages/SettingsLib/res/drawable/ic_settings_print.xml
+++ b/packages/SettingsLib/res/drawable/ic_settings_print.xml
@@ -14,15 +14,12 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19,8H5c-1.66,0-3,1.34-3,3v5c0,0.55,0.45,1,1,1h3v3c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1v-3h3c0.55,0,1-0.45,1-1v-5
-C22,9.34,20.66,8,19,8z M16,19H8v-5h8V19z
-M19,12c-0.55,0-1-0.45-1-1s0.45-1,1-1s1,0.45,1,1S19.55,12,19,12z M17,3H7
-C6.45,3,6,3.45,6,4v3h12V4C18,3.45,17.55,3,17,3z"/>
+ android:fillColor="#FF000000"
+ android:pathData="M19,8h-1V3H6v5H5c-1.66,0 -3,1.34 -3,3v6h4v4h12v-4h4v-6C22,9.34 20.66,8 19,8zM16,19H8v-4h8V19zM16,8H8V5h8V8zM18,12.5c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1s1,0.45 1,1S18.55,12.5 18,12.5z"/>
</vector>
diff --git a/packages/SettingsLib/res/layout/zen_mode_radio_button.xml b/packages/SettingsLib/res/layout/zen_mode_radio_button.xml
index 4c0faed..9ded283 100644
--- a/packages/SettingsLib/res/layout/zen_mode_radio_button.xml
+++ b/packages/SettingsLib/res/layout/zen_mode_radio_button.xml
@@ -17,10 +17,10 @@
<RadioButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/checkbox"
- android:layout_width="40dp"
+ android:layout_height="48dp"
+ android:layout_width="48dp"
android:layout_marginStart="7dp"
android:layout_marginEnd="4dp"
- android:layout_height="48dp"
android:layout_alignParentStart="true"
android:gravity="center"
android:paddingTop="10dp"
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index a0dfb5d..4c21e61 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -110,7 +110,7 @@
}
public boolean isConnectable() {
- return true;
+ return false;
}
public boolean isAutoConnectable() {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 15df0a8..85bbd59 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 166;
+ private static final int SETTINGS_VERSION = 167;
private final int mUserId;
@@ -3770,6 +3770,28 @@
currentVersion = 166;
}
+ if (currentVersion == 166) {
+ // Version 166: add default values for hush gesture used and manual ringer
+ // toggle
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ Setting currentHushUsedSetting = secureSettings.getSettingLocked(
+ Secure.HUSH_GESTURE_USED);
+ if (currentHushUsedSetting.isNull()) {
+ secureSettings.insertSettingLocked(
+ Settings.Secure.HUSH_GESTURE_USED, "0", null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+
+ Setting currentRingerToggleCountSetting = secureSettings.getSettingLocked(
+ Secure.MANUAL_RINGER_TOGGLE_COUNT);
+ if (currentRingerToggleCountSetting.isNull()) {
+ secureSettings.insertSettingLocked(
+ Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, "0", null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ currentVersion = 167;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index b4c2ba8..6c5cebc 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -22,7 +22,7 @@
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:visibility="gone">
- <FrameLayout
+ <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
@@ -46,5 +46,5 @@
android:contentDescription="@string/accessibility_clear_all"
android:text="@string/clear_all_notifications_text"
android:textColor="?attr/wallpaperTextColor"/>
- </FrameLayout>
+ </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
</com.android.systemui.statusbar.FooterView>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 654f407..edf56af 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1069,7 +1069,7 @@
<string name="manage_notifications_text">Manage notifications</string>
<!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
- <string name="dnd_suppressing_shade_text">Do Not Disturb is hiding notifications</string>
+ <string name="dnd_suppressing_shade_text">Notifications paused by Do Not Disturb</string>
<!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
<string name="media_projection_action_text">Start now</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplier.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplier.java
new file mode 100644
index 0000000..9f7d0b2
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplier.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
+
+import java.util.ArrayList;
+
+/**
+ * Helper class to apply surface transactions in sync with RenderThread.
+ */
+public class SyncRtSurfaceTransactionApplier {
+
+ private final Surface mTargetSurface;
+ private final ViewRootImpl mTargetViewRootImpl;
+ private final float[] mTmpFloat9 = new float[9];
+
+ /**
+ * @param targetView The view in the surface that acts as synchronization anchor.
+ */
+ public SyncRtSurfaceTransactionApplier(View targetView) {
+ mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
+ mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null;
+ }
+
+ /**
+ * Schedules applying surface parameters on the next frame.
+ *
+ * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
+ * this method to avoid synchronization issues.
+ */
+ public void scheduleApply(SurfaceParams... params) {
+ if (mTargetViewRootImpl == null) {
+ return;
+ }
+ mTargetViewRootImpl.registerRtFrameCallback(frame -> {
+ if (mTargetSurface == null || !mTargetSurface.isValid()) {
+ return;
+ }
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (int i = params.length - 1; i >= 0; i--) {
+ SurfaceParams surfaceParams = params[i];
+ SurfaceControl surface = surfaceParams.surface;
+ t.deferTransactionUntilSurface(surface, mTargetSurface, frame);
+ t.setMatrix(surface, surfaceParams.matrix, mTmpFloat9);
+ t.setWindowCrop(surface, surfaceParams.windowCrop);
+ t.setAlpha(surface, surfaceParams.alpha);
+ t.setLayer(surface, surfaceParams.layer);
+ t.show(surface);
+ }
+ t.setEarlyWakeup();
+ t.apply();
+ });
+
+ // Make sure a frame gets scheduled.
+ mTargetViewRootImpl.getView().invalidate();
+ }
+
+ public static class SurfaceParams {
+
+ /**
+ * Constructs surface parameters to be applied when the current view state gets pushed to
+ * RenderThread.
+ *
+ * @param surface The surface to modify.
+ * @param alpha Alpha to apply.
+ * @param matrix Matrix to apply.
+ * @param windowCrop Crop to apply.
+ */
+ public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
+ Rect windowCrop, int layer) {
+ this.surface = surface.mSurfaceControl;
+ this.alpha = alpha;
+ this.matrix = new Matrix(matrix);
+ this.windowCrop = new Rect(windowCrop);
+ this.layer = layer;
+ }
+
+ final SurfaceControl surface;
+ final float alpha;
+ final Matrix matrix;
+ final Rect windowCrop;
+ final int layer;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 31fd47f..62cd13b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -708,6 +708,11 @@
return mStrongAuthTracker.isUnlockingWithFingerprintAllowed();
}
+ public boolean isUserInLockdown(int userId) {
+ return mStrongAuthTracker.getStrongAuthForUser(userId)
+ == LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+ }
+
public boolean needsSlowUnlockTransition() {
return mNeedsSlowUnlockTransition;
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index 9a8512d..f9bf4f5 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -23,14 +23,18 @@
import android.view.View;
import com.android.systemui.ConfigurationChangedReceiver;
+import com.android.systemui.Dumpable;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIApplication;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Holds a map of root views to FragmentHostStates and generates them as needed.
* Also dispatches the configuration changes to all current FragmentHostStates.
*/
-public class FragmentService implements ConfigurationChangedReceiver {
+public class FragmentService implements ConfigurationChangedReceiver, Dumpable {
private static final String TAG = "FragmentService";
@@ -65,6 +69,14 @@
}
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Dumping fragments:");
+ for (FragmentHostState state : mHosts.values()) {
+ state.mFragmentHostManager.getFragmentManager().dump(" ", fd, pw, args);
+ }
+ }
+
private class FragmentHostState {
private final View mView;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 4b65288..d232108 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -690,7 +690,7 @@
}
private Action getLockdownAction() {
- return new SinglePressAction(com.android.systemui.R.drawable.ic_lock_lockdown,
+ return new SinglePressAction(R.drawable.ic_lock_lockdown,
R.string.global_action_lockdown) {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 368fa67..ff0c11d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -47,6 +47,7 @@
import android.os.SystemProperties;
import android.os.UserManager;
import android.os.RemoteException;
+import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -65,6 +66,7 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -223,12 +225,15 @@
= new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
+ Log.d(TAG, "View attached");
if (view == mLayout) {
mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
mLayoutAttachedToWindow = true;
if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) {
+ Log.d(TAG, "recents_swipe_up_onboarding tip attached");
mHasDismissedSwipeUpTip = false;
} else {
+ Log.d(TAG, "recents_quick_scrub_onboarding tip attached");
mHasDismissedQuickScrubTip = false;
}
}
@@ -236,9 +241,11 @@
@Override
public void onViewDetachedFromWindow(View view) {
+ Log.d(TAG, "View detached");
if (view == mLayout) {
mLayoutAttachedToWindow = false;
if (view.getTag().equals(R.string.recents_quick_scrub_onboarding)) {
+ Log.d(TAG, "recents_quick_scrub_onboarding tip detached");
mHasDismissedQuickScrubTip = true;
if (hasDismissedQuickScrubOnboardingOnce()) {
// If user dismisses the quick scrub tip twice, we consider user has seen it
@@ -321,22 +328,29 @@
return;
}
+ Log.d(TAG, "Connecting to launcher");
if (!mOverviewProxyListenerRegistered) {
+ Log.d(TAG, "Registering mOverviewProxyListener");
mOverviewProxyService.addCallback(mOverviewProxyListener);
mOverviewProxyListenerRegistered = true;
}
if (!mTaskListenerRegistered) {
+ Log.d(TAG, "Registering mTaskListener");
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
mTaskListenerRegistered = true;
}
}
public void onDisconnectedFromLauncher() {
+ Log.d(TAG, "Disconnecting to launcher");
+
if (mOverviewProxyListenerRegistered) {
+ Log.d(TAG, "Unregistering mOverviewProxyListener");
mOverviewProxyService.removeCallback(mOverviewProxyListener);
mOverviewProxyListenerRegistered = false;
}
if (mTaskListenerRegistered) {
+ Log.d(TAG, "Unregistering mTaskListener");
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskListener);
mTaskListenerRegistered = false;
}
@@ -364,6 +378,8 @@
// Only show in portrait.
int orientation = mContext.getResources().getConfiguration().orientation;
if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
+ Log.d(TAG, "Show " + (stringRes == R.string.recents_swipe_up_onboarding
+ ? "recents_swipe_up_onboarding" : "recents_quick_scrub_onboarding") + " tip");
mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
mWindowManager.addView(mLayout, getWindowLayoutParams());
@@ -392,6 +408,7 @@
public void hide(boolean animate) {
if (mLayoutAttachedToWindow) {
+ Log.d(TAG, "Hide tip, animated: " + animate);
if (animate) {
mLayout.animate()
.alpha(0f)
@@ -412,6 +429,24 @@
mNavBarHeight = navBarHeight;
}
+ public void dump(PrintWriter pw) {
+ pw.println("RecentsOnboarding {");
+ pw.println(" mTaskListenerRegistered: " + mTaskListenerRegistered);
+ pw.println(" mOverviewProxyListenerRegistered: " + mOverviewProxyListenerRegistered);
+ pw.println(" mLayoutAttachedToWindow: " + mLayoutAttachedToWindow);
+ pw.println(" mHasDismissedSwipeUpTip: " + mHasDismissedSwipeUpTip);
+ pw.println(" mHasDismissedQuickScrubTip: " + mHasDismissedQuickScrubTip);
+ pw.println(" mNumAppsLaunchedSinceSwipeUpTipDismiss: "
+ + mNumAppsLaunchedSinceSwipeUpTipDismiss);
+ pw.println(" hasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding());
+ pw.println(" hasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding());
+ pw.println(" hasDismissedQuickScrubOnboardingOnce: "
+ + hasDismissedQuickScrubOnboardingOnce());
+ pw.println(" getOpenedOverviewCount: " + getOpenedOverviewCount());
+ pw.println(" getOpenedOverviewFromHomeCount: " + getOpenedOverviewFromHomeCount());
+ pw.println(" }");
+ }
+
private WindowManager.LayoutParams getWindowLayoutParams() {
int flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -433,6 +468,7 @@
}
private void setHasSeenSwipeUpOnboarding(boolean hasSeenSwipeUpOnboarding) {
+ Log.d(TAG, "setHasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding);
Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING, hasSeenSwipeUpOnboarding);
if (hasSeenSwipeUpOnboarding && hasSeenQuickScrubOnboarding()) {
onDisconnectedFromLauncher();
@@ -444,6 +480,7 @@
}
private void setHasSeenQuickScrubOnboarding(boolean hasSeenQuickScrubOnboarding) {
+ Log.d(TAG, "setHasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding);
Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING,
hasSeenQuickScrubOnboarding);
if (hasSeenQuickScrubOnboarding && hasSeenSwipeUpOnboarding()) {
@@ -457,6 +494,8 @@
private void setHasDismissedQuickScrubOnboardingOnce(
boolean hasDismissedQuickScrubOnboardingOnce) {
+ Log.d(TAG,
+ "setHasDismissedQuickScrubOnboardingOnce: " + hasDismissedQuickScrubOnboardingOnce);
Prefs.putBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE,
hasDismissedQuickScrubOnboardingOnce);
}
@@ -466,6 +505,7 @@
}
private void setOpenedOverviewFromHomeCount(int openedOverviewFromHomeCount) {
+ Log.d(TAG, "setOpenedOverviewFromHomeCount: " + openedOverviewFromHomeCount);
Prefs.putInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, openedOverviewFromHomeCount);
}
@@ -474,6 +514,7 @@
}
private void setOpenedOverviewCount(int openedOverviewCount) {
+ Log.d(TAG, "setOpenedOverviewCount: " + openedOverviewCount);
Prefs.putInt(mContext, OVERVIEW_OPENED_COUNT, openedOverviewCount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 8d89314..3eb3160 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -778,10 +778,19 @@
mHandle.setAlpha(minimized ? 0f : 1f);
mDockedStackMinimized = minimized;
} else if (mDockedStackMinimized != minimized) {
- mMinimizedSnapAlgorithm = null;
mDockedStackMinimized = minimized;
- initializeSnapAlgorithm();
- if (mIsInMinimizeInteraction != minimized) {
+ if (mDisplayRotation != mDefaultDisplay.getRotation()) {
+ // Splitscreen to minimize is about to starts after rotating landscape to seascape,
+ // update insets, display info and snap algorithm targets
+ SystemServicesProxy.getInstance(mContext).getStableInsets(mStableInsets);
+ repositionSnapTargetBeforeMinimized();
+ updateDisplayInfo();
+ } else {
+ mMinimizedSnapAlgorithm = null;
+ initializeSnapAlgorithm();
+ }
+ if (mIsInMinimizeInteraction != minimized || mCurrentAnimator != null) {
+ cancelFlingAnimation();
if (minimized) {
// Relayout to recalculate the divider shadow when minimizing
requestLayout();
@@ -1017,7 +1026,6 @@
if (mDockSide == DOCKED_RIGHT) {
mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize)
- mDockedTaskRect.left + mDividerSize, 0);
- mOtherTaskRect.offset(mStableInsets.left, 0);
}
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedTaskRect,
mOtherTaskRect, null);
@@ -1031,7 +1039,6 @@
if (mDockSide == DOCKED_RIGHT) {
mDockedTaskRect.offset(Math.max(position, mStableInsets.left - mDividerSize)
- mDockedTaskRect.left + mDividerSize, 0);
- mOtherTaskRect.offset(mStableInsets.left, 0);
}
calculateBoundsForPosition(taskPosition, DockedDividerUtils.invertDockSide(mDockSide),
mOtherTaskRect);
@@ -1048,7 +1055,6 @@
// Move a right-docked-app to line up with the divider while dragging it
if (mDockSide == DOCKED_RIGHT) {
mDockedTaskRect.offset(position - mStableInsets.left + mDividerSize, 0);
- mOtherTaskRect.offset(mStableInsets.left, 0);
}
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
mOtherTaskRect, mOtherInsetRect);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsInfo.java
index cfc4da4..7999a6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsInfo.java
@@ -186,6 +186,11 @@
}
@Override
+ public boolean shouldBeSaved() {
+ return false;
+ }
+
+ @Override
public View getContentView() {
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 011be88..4da1558 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -84,8 +84,7 @@
if (view instanceof EmptyShadeView) {
EmptyShadeView emptyShadeView = (EmptyShadeView) view;
boolean visible = this.clipTopAmount <= mEmptyText.getPaddingTop() * 0.6f;
- emptyShadeView.performVisibilityAnimation(
- visible && !emptyShadeView.willBeGone());
+ emptyShadeView.setContentVisible(visible && emptyShadeView.isVisible());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index b010199..d03da8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -2286,6 +2286,11 @@
@Override
public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
long duration) {
+ if (getVisibility() == GONE) {
+ // If we are GONE, the hideSensitive parameter will not be calculated and always be
+ // false, which is incorrect, let's wait until a real call comes in later.
+ return;
+ }
boolean oldShowingPublic = mShowingPublic;
mShowingPublic = mSensitive && hideSensitive;
if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/FooterView.java
index 0f4b621..dc5bb9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FooterView.java
@@ -98,7 +98,7 @@
if (view instanceof FooterView) {
FooterView footerView = (FooterView) view;
boolean visible = this.clipTopAmount < mClearAllTopPadding;
- footerView.performVisibilityAnimation(visible && !footerView.willBeGone());
+ footerView.setContentVisible(visible && footerView.isVisible());
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 724bd22..952c961 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -1384,6 +1384,13 @@
smartReplyContainer.setVisibility(View.GONE);
return null;
}
+ // If we are keeping the notification around while sending we don't want to add the buttons.
+ boolean hideSmartReplies = entry.notification.getNotification()
+ .extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false);
+ if (hideSmartReplies) {
+ smartReplyContainer.setVisibility(View.GONE);
+ return null;
+ }
SmartReplyView smartReplyView = null;
if (smartReplyContainer.getChildCount() == 0) {
smartReplyView = SmartReplyView.inflate(mContext, smartReplyContainer);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index f14ca71..30fa0c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -113,6 +113,8 @@
Dependency.get(ForegroundServiceController.class);
protected final NotificationListener mNotificationListener =
Dependency.get(NotificationListener.class);
+ private final SmartReplyController mSmartReplyController =
+ Dependency.get(SmartReplyController.class);
protected IStatusBarService mBarService;
protected NotificationPresenter mPresenter;
@@ -127,6 +129,13 @@
protected boolean mDisableNotificationAlerts;
protected NotificationListContainer mListContainer;
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
+ /**
+ * Notifications with keys in this set are not actually around anymore. We kept them around
+ * when they were canceled in response to a remote input interaction. This allows us to show
+ * what you replied and allows you to continue typing into it.
+ */
+ private final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
+
private final class NotificationClicker implements View.OnClickListener {
@@ -220,6 +229,8 @@
}
pw.print(" mUseHeadsUp=");
pw.println(mUseHeadsUp);
+ pw.print(" mKeysKeptForRemoteInput: ");
+ pw.println(mKeysKeptForRemoteInput);
}
public NotificationEntryManager(Context context) {
@@ -374,6 +385,12 @@
final NotificationVisibility nv = NotificationVisibility.obtain(n.getKey(), rank, count,
true);
NotificationData.Entry entry = mNotificationData.get(n.getKey());
+
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mKeysKeptForRemoteInput.contains(n.getKey())) {
+ mKeysKeptForRemoteInput.remove(n.getKey());
+ }
+
mRemoteInputManager.onPerformRemoveNotification(n, entry);
final String pkg = n.getPackageName();
final String tag = n.getTag();
@@ -491,10 +508,35 @@
}
if (updated) {
Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key);
- mRemoteInputManager.getKeysKeptForRemoteInput().add(entry.key);
+ addKeyKeptForRemoteInput(entry.key);
return;
}
}
+
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && shouldKeepForSmartReply(entry)
+ && entry.row != null && !entry.row.isDismissed()) {
+ // Turn off the spinner and hide buttons when an app cancels the notification.
+ StatusBarNotification newSbn = rebuildNotificationForCanceledSmartReplies(entry);
+ boolean updated = false;
+ try {
+ updateNotificationInternal(newSbn, null);
+ updated = true;
+ } catch (InflationException e) {
+ // Ignore just don't keep the notification around.
+ }
+ // Treat the reply as longer sending.
+ mSmartReplyController.stopSending(entry);
+ if (updated) {
+ Log.w(TAG, "Keeping notification around after sending smart reply " + entry.key);
+ addKeyKeptForRemoteInput(entry.key);
+ return;
+ }
+ }
+
+ // Actually removing notification so smart reply controller can forget about it.
+ mSmartReplyController.stopSending(entry);
+
if (deferRemoval) {
mLatestRankingMap = ranking;
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
@@ -536,18 +578,21 @@
Notification.Builder b = Notification.Builder
.recoverBuilder(mContext, sbn.getNotification().clone());
- CharSequence[] oldHistory = sbn.getNotification().extras
- .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
- CharSequence[] newHistory;
- if (oldHistory == null) {
- newHistory = new CharSequence[1];
- } else {
- newHistory = new CharSequence[oldHistory.length + 1];
- System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
+ if (remoteInputText != null) {
+ CharSequence[] oldHistory = sbn.getNotification().extras
+ .getCharSequenceArray(Notification.EXTRA_REMOTE_INPUT_HISTORY);
+ CharSequence[] newHistory;
+ if (oldHistory == null) {
+ newHistory = new CharSequence[1];
+ } else {
+ newHistory = new CharSequence[oldHistory.length + 1];
+ System.arraycopy(oldHistory, 0, newHistory, 1, oldHistory.length);
+ }
+ newHistory[0] = String.valueOf(remoteInputText);
+ b.setRemoteInputHistory(newHistory);
}
- newHistory[0] = String.valueOf(remoteInputText);
- b.setRemoteInputHistory(newHistory);
b.setShowRemoteInputSpinner(showSpinner);
+ b.setHideSmartReplies(true);
Notification newNotification = b.build();
@@ -563,6 +608,17 @@
return newSbn;
}
+ @VisibleForTesting
+ StatusBarNotification rebuildNotificationForCanceledSmartReplies(
+ NotificationData.Entry entry) {
+ return rebuildNotificationWithRemoteInput(entry, null /* remoteInputTest */,
+ false /* showSpinner */);
+ }
+
+ private boolean shouldKeepForSmartReply(NotificationData.Entry entry) {
+ return entry != null && mSmartReplyController.isSendingSmartReply(entry.key);
+ }
+
private boolean shouldKeepForRemoteInput(NotificationData.Entry entry) {
if (entry == null) {
return false;
@@ -792,6 +848,7 @@
}
mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
mRemoteInputManager.onUpdateNotification(entry);
+ mSmartReplyController.stopSending(entry);
if (key.equals(mGutsManager.getKeyToRemoveOnGutsClosed())) {
mGutsManager.setKeyToRemoveOnGutsClosed(null);
@@ -955,6 +1012,20 @@
return mHeadsUpManager.isHeadsUp(key);
}
+ public boolean isNotificationKeptForRemoteInput(String key) {
+ return mKeysKeptForRemoteInput.contains(key);
+ }
+
+ public void removeKeyKeptForRemoteInput(String key) {
+ mKeysKeptForRemoteInput.remove(key);
+ }
+
+ public void addKeyKeptForRemoteInput(String key) {
+ if (FORCE_REMOTE_INPUT_HISTORY) {
+ mKeysKeptForRemoteInput.add(key);
+ }
+ }
+
/**
* Callback for NotificationEntryManager.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index eb46fba..cfd5d83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -63,12 +63,12 @@
public void setGutsParent(NotificationGuts listener);
/**
- * @return the view to be shown in the notification guts.
+ * Return the view to be shown in the notification guts.
*/
public View getContentView();
/**
- * @return the actual height of the content.
+ * Return the actual height of the content.
*/
public int getActualHeight();
@@ -83,16 +83,21 @@
public boolean handleCloseControls(boolean save, boolean force);
/**
- * @return whether the notification associated with these guts is set to be removed.
+ * Return whether the notification associated with these guts is set to be removed.
*/
public boolean willBeRemoved();
/**
- * @return whether these guts are a leavebehind (e.g. {@link NotificationSnooze}).
+ * Return whether these guts are a leavebehind (e.g. {@link NotificationSnooze}).
*/
public default boolean isLeavebehind() {
return false;
}
+
+ /**
+ * Return whether something changed and needs to be saved, possibly requiring a bouncer.
+ */
+ boolean shouldBeSaved();
}
public interface OnGutsClosedListener {
@@ -201,12 +206,19 @@
setExposed(true /* exposed */, needsFalsingProtection);
}
+ /**
+ * Hide controls if they are visible
+ * @param leavebehinds true if leavebehinds should be closed
+ * @param controls true if controls should be closed
+ * @param x x coordinate to animate the close circular reveal with
+ * @param y y coordinate to animate the close circular reveal with
+ * @param force whether the guts should be force-closed regardless of state.
+ */
public void closeControls(boolean leavebehinds, boolean controls, int x, int y, boolean force) {
if (mGutsContent != null) {
- if (mGutsContent.isLeavebehind() && leavebehinds) {
- closeControls(x, y, true /* save */, force);
- } else if (!mGutsContent.isLeavebehind() && controls) {
- closeControls(x, y, true /* save */, force);
+ if ((mGutsContent.isLeavebehind() && leavebehinds)
+ || (!mGutsContent.isLeavebehind() && controls)) {
+ closeControls(x, y, mGutsContent.shouldBeSaved(), force);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 98e9268..2b7ab10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -486,6 +486,11 @@
}
@Override
+ public boolean shouldBeSaved() {
+ return hasImportanceChanged();
+ }
+
+ @Override
public View getContentView() {
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 0144f42..a2d0c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -75,7 +75,7 @@
mPresenter.getHandler().post(() -> {
processForRemoteInput(sbn.getNotification(), mContext);
String key = sbn.getKey();
- mRemoteInputManager.getKeysKeptForRemoteInput().remove(key);
+ mEntryManager.removeKeyKeptForRemoteInput(key);
boolean isUpdate =
mEntryManager.getNotificationData().get(key) != null;
// In case we don't allow child notifications, we ignore children of
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index c4cc494..1287ced 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -39,7 +39,7 @@
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.OverviewProxyService;
@@ -68,7 +68,6 @@
Dependency.get(DeviceProvisionedController.class);
private final UserManager mUserManager;
private final IStatusBarService mBarService;
- private final LockPatternUtils mLockPatternUtils;
private boolean mShowLockscreenNotifications;
private boolean mAllowLockscreenRemoteInput;
@@ -162,7 +161,6 @@
mCurrentUserId = ActivityManager.getCurrentUser();
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- mLockPatternUtils = new LockPatternUtils(mContext);
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -274,7 +272,7 @@
if (userId == UserHandle.USER_ALL) {
userId = mCurrentUserId;
}
- return mLockPatternUtils.isUserInLockdown(userId);
+ return KeyguardUpdateMonitor.getInstance(mContext).isUserInLockdown(userId);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java
index 01ec461..8e8e718 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLogger.java
@@ -176,10 +176,9 @@
if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
return;
}
- NotificationVisibility[] newlyVisibleAr =
- newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
- NotificationVisibility[] noLongerVisibleAr =
- noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
+ final NotificationVisibility[] newlyVisibleAr = cloneVisibilitiesAsArr(newlyVisible);
+ final NotificationVisibility[] noLongerVisibleAr = cloneVisibilitiesAsArr(noLongerVisible);
+
mUiOffloadThread.submit(() -> {
try {
mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
@@ -202,6 +201,8 @@
Log.d(TAG, "failed setNotificationsShown: ", e);
}
}
+ recycleAllVisibilityObjects(newlyVisibleAr);
+ recycleAllVisibilityObjects(noLongerVisibleAr);
});
}
@@ -213,6 +214,28 @@
array.clear();
}
+ private void recycleAllVisibilityObjects(NotificationVisibility[] array) {
+ final int N = array.length;
+ for (int i = 0 ; i < N; i++) {
+ if (array[i] != null) {
+ array[i].recycle();
+ }
+ }
+ }
+
+ private NotificationVisibility[] cloneVisibilitiesAsArr(Collection<NotificationVisibility> c) {
+
+ final NotificationVisibility[] array = new NotificationVisibility[c.size()];
+ int i = 0;
+ for(NotificationVisibility nv: c) {
+ if (nv != null) {
+ array[i] = nv.clone();
+ }
+ i++;
+ }
+ return array;
+ }
+
@VisibleForTesting
public Runnable getVisibilityReporter() {
return mVisibilityReporter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index a333654..9e87a0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -77,12 +77,6 @@
protected final NotificationLockscreenUserManager mLockscreenUserManager =
Dependency.get(NotificationLockscreenUserManager.class);
- /**
- * Notifications with keys in this set are not actually around anymore. We kept them around
- * when they were canceled in response to a remote input interaction. This allows us to show
- * what you replied and allows you to continue typing into it.
- */
- protected final ArraySet<String> mKeysKeptForRemoteInput = new ArraySet<>();
protected final Context mContext;
private final UserManager mUserManager;
@@ -290,7 +284,8 @@
mRemoteInputController.addCallback(new RemoteInputController.Callback() {
@Override
public void onRemoteInputSent(NotificationData.Entry entry) {
- if (FORCE_REMOTE_INPUT_HISTORY && mKeysKeptForRemoteInput.contains(entry.key)) {
+ if (FORCE_REMOTE_INPUT_HISTORY
+ && mEntryManager.isNotificationKeptForRemoteInput(entry.key)) {
mEntryManager.removeNotification(entry.key, null);
} else if (mRemoteInputEntriesToRemoveOnCollapse.contains(entry)) {
// We're currently holding onto this notification, but from the apps point of
@@ -340,10 +335,6 @@
if (mRemoteInputController.isRemoteInputActive(entry)) {
mRemoteInputController.removeRemoteInput(entry, null);
}
- if (FORCE_REMOTE_INPUT_HISTORY
- && mKeysKeptForRemoteInput.contains(n.getKey())) {
- mKeysKeptForRemoteInput.remove(n.getKey());
- }
}
public void removeRemoteInputEntriesKeptUntilCollapsed() {
@@ -368,8 +359,6 @@
pw.println("NotificationRemoteInputManager state:");
pw.print(" mRemoteInputEntriesToRemoveOnCollapse: ");
pw.println(mRemoteInputEntriesToRemoveOnCollapse);
- pw.print(" mKeysKeptForRemoteInput: ");
- pw.println(mKeysKeptForRemoteInput);
}
public void bindRow(ExpandableNotificationRow row) {
@@ -377,10 +366,6 @@
row.setRemoteViewClickHandler(mOnClickHandler);
}
- public Set<String> getKeysKeptForRemoteInput() {
- return mKeysKeptForRemoteInput;
- }
-
@VisibleForTesting
public Set<NotificationData.Entry> getRemoteInputEntriesToRemoveOnCollapse() {
return mRemoteInputEntriesToRemoveOnCollapse;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index aea0127..d84d3dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -431,6 +431,11 @@
return true;
}
+ @Override
+ public boolean shouldBeSaved() {
+ return true;
+ }
+
public class NotificationSnoozeOption implements SnoozeOption {
private SnoozeCriterion mCriterion;
private int mMinutesToSnoozeFor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 1637849..341c692 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Resources;
+import android.os.Trace;
import android.service.notification.NotificationListenerService;
import android.util.Log;
import android.view.View;
@@ -283,6 +284,7 @@
* Updates expanded, dimmed and locked states of notification rows.
*/
public void updateRowStates() {
+ Trace.beginSection("NotificationViewHierarchyManager#updateRowStates");
final int N = mListContainer.getContainerChildCount();
int visibleNotifications = 0;
@@ -352,6 +354,9 @@
row.showAppOpsIcons(entry.mActiveAppOps);
}
+ Trace.beginSection("NotificationPresenter#onUpdateRowStates");
mPresenter.onUpdateRowStates();
+ Trace.endSection();
+ Trace.endSection();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 67da68c..5ba75de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -17,10 +17,12 @@
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
+import android.util.ArraySet;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.Dependency;
+import java.util.Set;
/**
* Handles when smart replies are added to a notification
@@ -28,18 +30,20 @@
*/
public class SmartReplyController {
private IStatusBarService mBarService;
- private NotificationEntryManager mNotificationEntryManager;
+ private Set<String> mSendingKeys = new ArraySet<>();
public SmartReplyController() {
mBarService = Dependency.get(IStatusBarService.class);
- mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
}
public void smartReplySent(NotificationData.Entry entry, int replyIndex, CharSequence reply) {
+ NotificationEntryManager notificationEntryManager
+ = Dependency.get(NotificationEntryManager.class);
StatusBarNotification newSbn =
- mNotificationEntryManager.rebuildNotificationWithRemoteInput(entry, reply,
+ notificationEntryManager.rebuildNotificationWithRemoteInput(entry, reply,
true /* showSpinner */);
- mNotificationEntryManager.updateNotification(newSbn, null /* ranking */);
+ notificationEntryManager.updateNotification(newSbn, null /* ranking */);
+ mSendingKeys.add(entry.key);
try {
mBarService.onNotificationSmartReplySent(entry.notification.getKey(),
@@ -49,6 +53,14 @@
}
}
+ /**
+ * Have we posted an intent to an app about sending a smart reply from the
+ * notification with this key.
+ */
+ public boolean isSendingSmartReply(String key) {
+ return mSendingKeys.contains(key);
+ }
+
public void smartRepliesAdded(final NotificationData.Entry entry, int replyCount) {
try {
mBarService.onNotificationSmartRepliesAdded(entry.notification.getKey(),
@@ -57,4 +69,10 @@
// Nothing to do, system going down
}
}
+
+ public void stopSending(final NotificationData.Entry entry) {
+ if (entry != null) {
+ mSendingKeys.remove(entry.notification.getKey());
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index b2eb18e..c5b3560 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -16,13 +16,13 @@
package com.android.systemui.statusbar;
-import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Interpolator;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Interpolators;
/**
@@ -33,11 +33,19 @@
protected View mContent;
protected View mSecondaryView;
- private boolean mIsVisible;
- private boolean mIsSecondaryVisible;
- private boolean mAnimating;
- private boolean mSecondaryAnimating;
+ private boolean mIsVisible = true;
+ private boolean mContentVisible = true;
+ private boolean mIsSecondaryVisible = true;
private int mDuration = 260;
+ private boolean mContentAnimating;
+ private final Runnable mContentVisibilityEndRunnable = () -> {
+ mContentAnimating = false;
+ if (getVisibility() != View.GONE && !mIsVisible) {
+ setVisibility(GONE);
+ setWillBeGone(false);
+ notifyHeightChanged(false /* needsAnimation */);
+ }
+ };
public StackScrollerDecorView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -48,7 +56,8 @@
super.onFinishInflate();
mContent = findContentView();
mSecondaryView = findSecondaryView();
- setInvisible();
+ setVisible(false /* nowVisible */, false /* animate */);
+ setSecondaryVisible(false /* nowVisible */, false /* animate */);
}
@Override
@@ -62,72 +71,86 @@
return true;
}
- public void performVisibilityAnimation(boolean nowVisible) {
- performVisibilityAnimation(nowVisible, null /* onFinishedRunnable */);
- }
-
- public void performVisibilityAnimation(boolean nowVisible, Runnable onFinishedRunnable) {
- boolean oldVisible = isVisible();
- animateText(mContent, nowVisible, oldVisible, new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mAnimating = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimating = false;
- mIsVisible = nowVisible;
- if (onFinishedRunnable != null) {
- onFinishedRunnable.run();
- }
- }
- });
- }
-
- public void performSecondaryVisibilityAnimation(boolean nowVisible) {
- performSecondaryVisibilityAnimation(nowVisible, null /* onFinishedRunnable */);
- }
-
- public void performSecondaryVisibilityAnimation(boolean nowVisible,
- Runnable onFinishedRunnable) {
- boolean oldVisible = isSecondaryVisible();
- animateText(mSecondaryView, nowVisible, oldVisible, new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mSecondaryAnimating = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mSecondaryAnimating = false;
- mIsSecondaryVisible = nowVisible;
- if (onFinishedRunnable != null) {
- onFinishedRunnable.run();
- }
- }
- });
- }
-
/**
- * Check whether the secondary view is visible or not.<p/>
+ * Set the content of this view to be visible in an animated way.
*
- * @see #isVisible()
+ * @param contentVisible True if the content should be visible or false if it should be hidden.
*/
- public boolean isSecondaryVisible() {
- return mSecondaryView != null && (mIsSecondaryVisible ^ mSecondaryAnimating);
+ public void setContentVisible(boolean contentVisible) {
+ setContentVisible(contentVisible, true /* animate */);
+ }
+ /**
+ * Set the content of this view to be visible.
+ * @param contentVisible True if the content should be visible or false if it should be hidden.
+ * @param animate Should an animation be performed.
+ */
+ private void setContentVisible(boolean contentVisible, boolean animate) {
+ if (mContentVisible != contentVisible) {
+ mContentAnimating = animate;
+ setViewVisible(mContent, contentVisible, animate, mContentVisibilityEndRunnable);
+ mContentVisible = contentVisible;
+ } if (!mContentAnimating) {
+ mContentVisibilityEndRunnable.run();
+ }
+ }
+
+ public boolean isContentVisible() {
+ return mContentVisible;
}
/**
- * Check whether the whole view is visible or not.<p/>
- * The view is considered visible if it matches one of following:
- * <ul>
- * <li> It's visible and there is no ongoing animation. </li>
- * <li> It's not visible but is animating, thus being eventually visible. </li>
- * </ul>
+ * Make this view visible. If {@code false} is passed, the view will fade out it's content
+ * and set the view Visibility to GONE. If only the content should be changed
+ * {@link #setContentVisible(boolean)} can be used.
+ *
+ * @param nowVisible should the view be visible
+ * @param animate should the change be animated.
+ */
+ public void setVisible(boolean nowVisible, boolean animate) {
+ if (mIsVisible != nowVisible) {
+ mIsVisible = nowVisible;
+ if (animate) {
+ if (nowVisible) {
+ setVisibility(VISIBLE);
+ setWillBeGone(false);
+ notifyHeightChanged(false /* needsAnimation */);
+ } else {
+ setWillBeGone(true);
+ }
+ setContentVisible(nowVisible, true /* animate */);
+ } else {
+ setVisibility(nowVisible ? VISIBLE : GONE);
+ setContentVisible(nowVisible, false /* animate */);
+ setWillBeGone(false);
+ notifyHeightChanged(false /* needsAnimation */);
+ }
+ }
+ }
+
+ /**
+ * Set the secondary view of this layout to visible.
+ *
+ * @param nowVisible should the secondary view be visible
+ * @param animate should the change be animated
+ */
+ public void setSecondaryVisible(boolean nowVisible, boolean animate) {
+ if (mIsSecondaryVisible != nowVisible) {
+ setViewVisible(mSecondaryView, nowVisible, animate, null /* endRunnable */);
+ mIsSecondaryVisible = nowVisible;
+ }
+ }
+
+ @VisibleForTesting
+ boolean isSecondaryVisible() {
+ return mIsSecondaryVisible;
+ }
+
+ /**
+ * Is this view visible. If a view is currently animating to gone, it will
+ * return {@code false}.
*/
public boolean isVisible() {
- return mIsVisible ^ mAnimating;
+ return mIsVisible;
}
void setDuration(int duration) {
@@ -135,43 +158,35 @@
}
/**
- * Animate the text to a new visibility.
- *
- * @param view Target view, maybe content view or dissmiss view
- * @param nowVisible Should it now be visible
- * @param oldVisible Is it visible currently
- * @param listener A listener that doing flag settings or other actions
+ * Animate a view to a new visibility.
+ * @param view Target view, maybe content view or dismiss view.
+ * @param nowVisible Should it now be visible.
+ * @param animate Should this be done in an animated way.
+ * @param endRunnable A runnable that is run when the animation is done.
*/
- private void animateText(View view, boolean nowVisible, boolean oldVisible,
- AnimatorListenerAdapter listener) {
+ private void setViewVisible(View view, boolean nowVisible,
+ boolean animate, Runnable endRunnable) {
if (view == null) {
return;
}
-
- if (nowVisible != oldVisible) {
- // Animate text
- float endValue = nowVisible ? 1.0f : 0.0f;
- Interpolator interpolator;
- if (nowVisible) {
- interpolator = Interpolators.ALPHA_IN;
- } else {
- interpolator = Interpolators.ALPHA_OUT;
+ // cancel any previous animations
+ view.animate().cancel();
+ float endValue = nowVisible ? 1.0f : 0.0f;
+ if (!animate) {
+ view.setAlpha(endValue);
+ if (endRunnable != null) {
+ endRunnable.run();
}
- view.animate()
- .alpha(endValue)
- .setInterpolator(interpolator)
- .setDuration(mDuration)
- .setListener(listener);
+ return;
}
- }
- public void setInvisible() {
- mContent.setAlpha(0.0f);
- if (mSecondaryView != null) {
- mSecondaryView.setAlpha(0.0f);
- }
- mIsVisible = false;
- mIsSecondaryVisible = false;
+ // Animate the view alpha
+ Interpolator interpolator = nowVisible ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT;
+ view.animate()
+ .alpha(endValue)
+ .setInterpolator(interpolator)
+ .setDuration(mDuration)
+ .withEndAction(endRunnable);
}
@Override
@@ -180,13 +195,13 @@
Runnable onFinishedRunnable,
AnimatorListenerAdapter animationListener) {
// TODO: Use duration
- performVisibilityAnimation(false);
+ setContentVisible(false);
}
@Override
public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear) {
// TODO: use delay and duration
- performVisibilityAnimation(true);
+ setContentVisible(true);
}
@Override
@@ -194,13 +209,6 @@
return false;
}
- public void cancelAnimation() {
- mContent.animate().cancel();
- if (mSecondaryView != null) {
- mSecondaryView.animate().cancel();
- }
- }
-
protected abstract View findContentView();
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index cfbb4d9..a68d75a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -28,11 +28,11 @@
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
-import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.ViewRootImpl;
import com.android.systemui.Interpolators;
+import com.android.systemui.shared.system.SurfaceControlCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationListContainer;
import com.android.systemui.statusbar.StatusBarState;
@@ -41,6 +41,8 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import java.util.ArrayList;
+
/**
* A class that allows activities to be launched in a seamless way where the notification
* transforms nicely into the starting window.
@@ -81,7 +83,7 @@
}
AnimationRunner animationRunner = new AnimationRunner(sourceNotification);
return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION,
- 0 /* statusBarTransitionDelay */);
+ ANIMATION_DURATION - 150 /* statusBarTransitionDelay */);
}
public boolean isAnimationPending() {
@@ -109,12 +111,13 @@
private final ExpandableNotificationRow mSourceNotification;
private final ExpandAnimationParameters mParams;
private final Rect mWindowCrop = new Rect();
- private boolean mLeashShown;
private boolean mInstantCollapsePanel = true;
+ private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier;
public AnimationRunner(ExpandableNotificationRow sourceNofitication) {
mSourceNotification = sourceNofitication;
mParams = new ExpandAnimationParameters();
+ mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification);
}
@Override
@@ -240,24 +243,12 @@
}
private void applyParamsToWindow(RemoteAnimationTarget app) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- if (!mLeashShown) {
- t.show(app.leash);
- mLeashShown = true;
- }
Matrix m = new Matrix();
m.postTranslate(0, (float) (mParams.top - app.position.y));
- t.setMatrix(app.leash, m, new float[9]);
mWindowCrop.set(mParams.left, 0, mParams.right, mParams.getHeight());
- t.setWindowCrop(app.leash, mWindowCrop);
- ViewRootImpl viewRootImpl = mSourceNotification.getViewRootImpl();
- if (viewRootImpl != null) {
- Surface systemUiSurface = viewRootImpl.mSurface;
- t.deferTransactionUntilSurface(app.leash, systemUiSurface,
- systemUiSurface.getNextFrameNumber());
- }
- t.setEarlyWakeup();
- t.apply();
+ SurfaceParams params = new SurfaceParams(new SurfaceControlCompat(app.leash),
+ 1f /* alpha */, m, mWindowCrop, app.prefixOrderIndex);
+ mSyncRtTransactionApplier.scheduleApply(params);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
index 178c813..c1ffc22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -35,9 +35,7 @@
@Override
public void initFrom(View view, TransformInfo transformInfo) {
super.initFrom(view, transformInfo);
- if (view instanceof TextView) {
- mText = (TextView) view;
- }
+ mText = (TextView) view;
}
@Override
@@ -94,6 +92,9 @@
return false;
}
TextViewTransformState otherTvs = (TextViewTransformState) otherState;
+ if (!TextUtils.equals(mText.getText(), otherTvs.mText.getText())) {
+ return false;
+ }
int lineCount = mText.getLineCount();
return lineCount == 1 && lineCount == otherTvs.mText.getLineCount()
&& getEllipsisCount() == otherTvs.getEllipsisCount()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index ee83250..f7b7eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -165,7 +165,9 @@
showNotificationIconArea(animate);
}
}
- if ((diff1 & DISABLE_CLOCK) != 0) {
+ // The clock may have already been hidden, but we might want to shift its
+ // visibility to GONE from INVISIBLE or vice versa
+ if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
if ((state1 & DISABLE_CLOCK) != 0) {
hideClock(animate);
} else {
@@ -212,13 +214,24 @@
}
public void hideClock(boolean animate) {
- animateHiddenState(mClockView, View.GONE, animate);
+ animateHiddenState(mClockView, clockHiddenMode(), animate);
}
public void showClock(boolean animate) {
animateShow(mClockView, animate);
}
+ /**
+ * If panel is expanded/expanding it usually means QS shade is opening, so
+ * don't set the clock GONE otherwise it'll mess up the animation.
+ */
+ private int clockHiddenMode() {
+ if (!mStatusBar.isClosed() && !mKeyguardMonitor.isShowing()) {
+ return View.INVISIBLE;
+ }
+ return View.GONE;
+ }
+
public void hideNotificationIconArea(boolean animate) {
animateHide(mNotificationIconAreaInner, animate);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 48eb3e8..c74d09d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -54,8 +54,8 @@
private static final String TAG = "KeyguardBouncer";
static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
- private static final float EXPANSION_HIDDEN = 1f;
- private static final float EXPANSION_VISIBLE = 0f;
+ static final float EXPANSION_HIDDEN = 1f;
+ static final float EXPANSION_VISIBLE = 0f;
protected final Context mContext;
protected final ViewMediatorCallback mCallback;
@@ -86,6 +86,7 @@
private boolean mShowingSoon;
private int mBouncerPromptReason;
private boolean mIsAnimatingAway;
+ private boolean mIsScrimmed;
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
@@ -103,17 +104,17 @@
}
public void show(boolean resetSecuritySelection) {
- show(resetSecuritySelection, true /* animated */);
+ show(resetSecuritySelection, true /* scrimmed */);
}
/**
* Shows the bouncer.
*
* @param resetSecuritySelection Cleans keyguard view
- * @param animated true when the bouncer show show animated, false when the user will be
- * dragging it and animation should be deferred.
+ * @param isScrimmed true when the bouncer show show scrimmed, false when the user will be
+ * dragging it and translation should be deferred.
*/
- public void show(boolean resetSecuritySelection, boolean animated) {
+ public void show(boolean resetSecuritySelection, boolean isScrimmed) {
final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
// In split system user mode, we never unlock system user.
@@ -126,9 +127,10 @@
// are valid.
// Later, at the end of the animation, when the bouncer is at the top of the screen,
// onFullyShown() will be called and FalsingManager will stop recording touches.
- if (animated) {
+ if (isScrimmed) {
setExpansion(EXPANSION_VISIBLE);
}
+ mIsScrimmed = isScrimmed;
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
@@ -164,6 +166,10 @@
mCallback.onBouncerVisiblityChanged(true /* shown */);
}
+ public boolean isShowingScrimmed() {
+ return isShowing() && mIsScrimmed;
+ }
+
/**
* This method must be called at the end of the bouncer animation when
* the translation is performed manually by the user, otherwise FalsingManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 64fed7a..98672b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1174,6 +1174,8 @@
dumpButton(pw, "menu", getMenuButton());
dumpButton(pw, "a11y", getAccessibilityButton());
+ mRecentsOnboarding.dump(pw);
+
pw.println(" }");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index a3905b7..2f18aad9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2199,7 +2199,7 @@
@Override
protected boolean isClearAllVisible() {
- return mNotificationStackScroller.isFooterViewVisible();
+ return mNotificationStackScroller.isFooterViewContentVisible();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index bef6944..e4eeec1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -948,17 +948,6 @@
return mClosing || mLaunchingNotification;
}
- /**
- * Bouncer might need a scrim when you double tap on notifications or edit QS.
- * On other cases, when you drag up the bouncer with the finger or just fling,
- * the scrim should be hidden to avoid occluding the clock.
- *
- * @return true when we need a scrim to show content on top of the notification panel.
- */
- public boolean needsScrimming() {
- return !isTracking() && !isCollapsing() && !isFullyCollapsed();
- }
-
public boolean isTracking() {
return mTracking;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 5c14015..b0d72c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -45,6 +45,7 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AlarmManager;
+import android.app.IWallpaperManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -747,6 +748,14 @@
Slog.e(TAG, "Failed to register VR mode state listener: " + e);
}
+ IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
+ ServiceManager.getService(Context.WALLPAPER_SERVICE));
+ try {
+ wallpaperManager.setInAmbientMode(false /* ambientMode */, false /* animated */);
+ } catch (RemoteException e) {
+ // Just pass, nothing critical.
+ }
+
// end old BaseStatusBar.start().
// Lastly, call to the icon policy to install/update all the icons.
@@ -1453,11 +1462,11 @@
@VisibleForTesting
protected void updateFooter() {
- boolean showFooterView = mState != StatusBarState.KEYGUARD
- && mEntryManager.getNotificationData().getActiveNotifications().size() != 0
+ boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
+ boolean showFooterView = (showDismissView ||
+ mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
+ && mState != StatusBarState.KEYGUARD
&& !mRemoteInputManager.getController().isRemoteInputActive();
- boolean showDismissView = mClearAllEnabled && mState != StatusBarState.KEYGUARD
- && hasActiveClearableNotifications();
mStackScroller.updateFooterView(showFooterView, showDismissView);
}
@@ -3888,7 +3897,6 @@
mKeyguardIndicationController.setDozing(mDozing);
mNotificationPanel.setDozing(mDozing, animate);
updateQsExpansionEnabled();
- mViewHierarchyManager.updateRowStates();
Trace.endSection();
}
@@ -3977,12 +3985,12 @@
private void showBouncerIfKeyguard() {
if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
&& !mKeyguardViewMediator.isHiding()) {
- showBouncer(true /* animated */);
+ showBouncer(true /* scrimmed */);
}
}
- protected void showBouncer(boolean animated) {
- mStatusBarKeyguardViewManager.showBouncer(animated);
+ protected void showBouncer(boolean scrimmed) {
+ mStatusBarKeyguardViewManager.showBouncer(scrimmed);
}
private void instantExpandNotificationsPanel() {
@@ -4096,7 +4104,7 @@
public void onTrackingStopped(boolean expand) {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
if (!expand && !mUnlockMethodCache.canSkipBouncer()) {
- showBouncer(false /* animated */);
+ showBouncer(false /* scrimmed */);
}
}
}
@@ -4235,7 +4243,7 @@
@Override
public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
mLeaveOpenOnKeyguardHide = true;
- showBouncer(true /* animated */);
+ showBouncer(true /* scrimmed */);
mPendingRemoteInputView = clicked;
}
@@ -4676,16 +4684,18 @@
FingerprintUnlockController.MODE_WAKE_AND_UNLOCK) {
dozing = false;
}
- mDozing = dozing;
- mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
- mStatusBarWindowManager.setDozing(mDozing);
- mStatusBarKeyguardViewManager.setDozing(mDozing);
- if (mAmbientIndicationContainer instanceof DozeReceiver) {
- ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
+ if (mDozing != dozing) {
+ mDozing = dozing;
+ mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn);
+ mStatusBarWindowManager.setDozing(mDozing);
+ mStatusBarKeyguardViewManager.setDozing(mDozing);
+ if (mAmbientIndicationContainer instanceof DozeReceiver) {
+ ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
+ }
+ mEntryManager.updateNotifications();
+ updateDozingState();
+ updateReportRejectedTouchVisibility();
}
- mEntryManager.updateNotifications();
- updateDozingState();
- updateReportRejectedTouchVisibility();
Trace.endSection();
}
@@ -4705,7 +4715,7 @@
// Bouncer needs the front scrim when it's on top of an activity,
// tapping on a notification, editing QS or being dismissed by
// FLAG_DISMISS_KEYGUARD_ACTIVITY.
- ScrimState state = mIsOccluded || mNotificationPanel.needsScrimming()
+ ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
|| mStatusBarKeyguardViewManager.willDismissWithAction()
|| mStatusBarKeyguardViewManager.isFullscreenBouncer() ?
ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
@@ -5161,8 +5171,7 @@
removeNotification(parentToCancelFinal);
}
if (shouldAutoCancel(sbn)
- || mRemoteInputManager.getKeysKeptForRemoteInput().contains(
- notificationKey)) {
+ || mEntryManager.isNotificationKeptForRemoteInput(notificationKey)) {
// Automatically remove all notifications that we may have kept around longer
removeNotification(sbn);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index b517d11..6a6a7dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,6 +31,7 @@
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -158,7 +159,8 @@
mNotificationPanelView.setBouncerTop(mBouncer.getTop());
}
- private void onPanelExpansionChanged(float expansion, boolean tracking) {
+ @VisibleForTesting
+ void onPanelExpansionChanged(float expansion, boolean tracking) {
// We don't want to translate the bounce when:
// • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to
// conserve the original animation.
@@ -166,13 +168,14 @@
// • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY
// • Full-screen user switcher is displayed.
if (mNotificationPanelView.isUnlockHintRunning()) {
- mBouncer.setExpansion(1);
- } else if (mOccluded || mBouncer.willDismissWithAction()
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+ } else if (mBouncer.willDismissWithAction() || mBouncer.isShowingScrimmed()
|| mStatusBar.isFullScreenUserSwitcherState()) {
- mBouncer.setExpansion(0);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
} else if (mShowing && !mDozing) {
mBouncer.setExpansion(expansion);
- if (expansion != 1 && tracking && mStatusBar.isKeyguardCurrentlySecure()
+ if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking
+ && mStatusBar.isKeyguardCurrentlySecure()
&& !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
mBouncer.show(false /* resetSecuritySelection */, false /* animated */);
}
@@ -215,9 +218,9 @@
cancelPendingWakeupAction();
}
- public void showBouncer(boolean animated) {
- if (mShowing) {
- mBouncer.show(false /* resetSecuritySelection */, animated);
+ public void showBouncer(boolean scrimmed) {
+ if (mShowing && !mBouncer.isShowing()) {
+ mBouncer.show(false /* resetSecuritySelection */, scrimmed);
}
updateStates();
}
@@ -725,6 +728,10 @@
return mBouncer.willDismissWithAction();
}
+ public boolean bouncerNeedsScrimming() {
+ return mBouncer.isShowingScrimmed();
+ }
+
public void dump(PrintWriter pw) {
pw.println("StatusBarKeyguardViewManager:");
pw.println(" mShowing: " + mShowing);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index cc802a8..585787e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -207,6 +207,7 @@
b.setText(choice);
OnDismissAction action = () -> {
+ smartReplyController.smartReplySent(entry, replyIndex, b.getText());
Bundle results = new Bundle();
results.putString(remoteInput.getResultKey(), choice.toString());
Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -217,7 +218,6 @@
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Unable to send smart reply", e);
}
- smartReplyController.smartReplySent(entry, replyIndex, b.getText());
mSmartReplyContainer.setVisibility(View.GONE);
return false; // do not defer
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index ee70019..bd56d79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -3922,10 +3922,6 @@
}
public void goToFullShade(long delay) {
- if (mFooterView != null) {
- mFooterView.setInvisible();
- }
- mEmptyShadeView.setInvisible();
mGoToFullShadeNeedsAnimation = true;
mGoToFullShadeDelay = delay;
mNeedsAnimation = true;
@@ -4073,17 +4069,7 @@
}
public void updateEmptyShadeView(boolean visible) {
- int oldVisibility = mEmptyShadeView.willBeGone() ? GONE : mEmptyShadeView.getVisibility();
- int newVisibility = visible ? VISIBLE : GONE;
-
- boolean changedVisibility = oldVisibility != newVisibility;
- if (changedVisibility) {
- if (newVisibility != GONE) {
- showFooterView(mEmptyShadeView);
- } else {
- hideFooterView(mEmptyShadeView, true);
- }
- }
+ mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
int oldTextRes = mEmptyShadeView.getTextResource();
int newTextRes = mStatusBar.areNotificationsHidden()
@@ -4097,48 +4083,9 @@
if (mFooterView == null) {
return;
}
- int oldVisibility = mFooterView.willBeGone() ? GONE : mFooterView.getVisibility();
- int newVisibility = visible ? VISIBLE : GONE;
- if (oldVisibility != newVisibility) {
- if (newVisibility != GONE) {
- showFooterView(mFooterView);
- } else {
- hideFooterView(mFooterView, mFooterView.isButtonVisible());
- }
- }
- if (mFooterView.isSecondaryVisible() != showDismissView) {
- mFooterView.performSecondaryVisibilityAnimation(showDismissView);
- }
- }
-
- private void showFooterView(StackScrollerDecorView footerView) {
- if (footerView.willBeGone()) {
- footerView.cancelAnimation();
- } else {
- footerView.setInvisible();
- }
- footerView.setVisibility(VISIBLE);
- footerView.setWillBeGone(false);
- updateContentHeight();
- notifyHeightChangeListener(footerView);
- }
-
- private void hideFooterView(StackScrollerDecorView footerView, boolean isButtonVisible) {
- Runnable onHideFinishRunnable = new Runnable() {
- @Override
- public void run() {
- footerView.setVisibility(GONE);
- footerView.setWillBeGone(false);
- updateContentHeight();
- notifyHeightChangeListener(footerView);
- }
- };
- if (isButtonVisible && mIsExpanded && mAnimationsEnabled) {
- footerView.setWillBeGone(true);
- footerView.performVisibilityAnimation(false, onHideFinishRunnable);
- } else {
- onHideFinishRunnable.run();
- }
+ boolean animate = mIsExpanded && mAnimationsEnabled;
+ mFooterView.setVisible(visible, animate);
+ mFooterView.setSecondaryVisible(showDismissView, animate);
}
public void setDismissAllInProgress(boolean dismissAllInProgress) {
@@ -4170,8 +4117,8 @@
&& !mFooterView.willBeGone();
}
- public boolean isFooterViewVisible() {
- return mFooterView != null && mFooterView.isVisible();
+ public boolean isFooterViewContentVisible() {
+ return mFooterView != null && mFooterView.isContentVisible();
}
public int getFooterViewHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 4e8fcac..a75d40f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -364,7 +364,7 @@
// This item is added, initialize it's properties.
ExpandableViewState viewState = finalState
.getViewStateForView(changingView);
- if (viewState == null) {
+ if (viewState == null || viewState.gone) {
// The position for this child was never generated, let's continue.
continue;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 6b322c7..d76b7f0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -36,6 +36,7 @@
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.app.KeyguardManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -445,6 +446,7 @@
}
}
Events.writeEvent(mContext, Events.EVENT_RINGER_TOGGLE, newRingerMode);
+ incrementManualToggleCount();
updateRingerH();
provideTouchFeedbackH(newRingerMode);
mController.setRingerMode(newRingerMode, false);
@@ -453,6 +455,11 @@
updateRingerH();
}
+ private void incrementManualToggleCount() {
+ ContentResolver cr = mContext.getContentResolver();
+ int ringerCount = Settings.Secure.getInt(cr, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, 0);
+ Settings.Secure.putInt(cr, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, ringerCount + 1);
+ }
private void provideTouchFeedbackH(int newRingerMode) {
VibrationEffect effect = null;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/FooterViewTest.java
index 96b0255..e6fdfa4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/FooterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/FooterViewTest.java
@@ -23,39 +23,22 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.drawable.Icon;
-import android.os.UserHandle;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -90,34 +73,18 @@
@Test
public void testPerformVisibilityAnimation() {
- mView.setInvisible();
+ mView.setVisible(false /* visible */, false /* animate */);
assertFalse(mView.isVisible());
- Runnable test = new Runnable() {
- @Override
- public void run() {
- assertEquals(1.0f, mView.findContentView().getAlpha());
- assertEquals(0.0f, mView.findSecondaryView().getAlpha());
- assertTrue(mView.isVisible());
- }
- };
- mView.performVisibilityAnimation(true, test);
+ mView.setVisible(true /* visible */, true /* animate */);
}
@Test
public void testPerformSecondaryVisibilityAnimation() {
- mView.setInvisible();
+ mView.setSecondaryVisible(false /* visible */, false /* animate */);
assertFalse(mView.isSecondaryVisible());
- Runnable test = new Runnable() {
- @Override
- public void run() {
- assertEquals(0.0f, mView.findContentView().getAlpha());
- assertEquals(1.0f, mView.findSecondaryView().getAlpha());
- assertTrue(mView.isSecondaryVisible());
- }
- };
- mView.performSecondaryVisibilityAnimation(true, test);
+ mView.setSecondaryVisible(true /* visible */, true /* animate */);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
index f05cf6b..afe16cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java
@@ -19,6 +19,7 @@
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -97,6 +98,7 @@
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private MetricsLogger mMetricsLogger;
+ @Mock private SmartReplyController mSmartReplyController;
private NotificationData.Entry mEntry;
private StatusBarNotification mSbn;
@@ -158,6 +160,7 @@
mDeviceProvisionedController);
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
+ mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController);
mCountDownLatch = new CountDownLatch(1);
@@ -262,6 +265,7 @@
verify(mMediaManager).onNotificationRemoved(mSbn.getKey());
verify(mRemoteInputManager).onRemoveNotification(mEntry);
+ verify(mSmartReplyController).stopSending(mEntry);
verify(mForegroundServiceController).removeNotification(mSbn);
verify(mListContainer).cleanUpViewState(mRow);
verify(mPresenter).updateNotificationViews();
@@ -272,6 +276,20 @@
}
@Test
+ public void testRemoveNotification_blockedBySendingSmartReply() throws Exception {
+ com.android.systemui.util.Assert.isNotMainThread();
+
+ mEntry.row = mRow;
+ mEntryManager.getNotificationData().add(mEntry);
+ when(mSmartReplyController.isSendingSmartReply(mEntry.key)).thenReturn(true);
+
+ mEntryManager.removeNotification(mSbn.getKey(), mRankingMap);
+
+ assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+ assertTrue(mEntryManager.isNotificationKeptForRemoteInput(mEntry.key));
+ }
+
+ @Test
public void testUpdateAppOps_foregroundNoti() {
com.android.systemui.util.Assert.isNotMainThread();
@@ -365,6 +383,8 @@
Assert.assertEquals("A Reply", messages[0]);
Assert.assertFalse(newSbn.getNotification().extras
.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ Assert.assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
}
@Test
@@ -377,6 +397,8 @@
Assert.assertEquals("A Reply", messages[0]);
Assert.assertTrue(newSbn.getNotification().extras
.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ Assert.assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
}
@Test
@@ -394,4 +416,15 @@
Assert.assertEquals("Reply 2", messages[0]);
Assert.assertEquals("A Reply", messages[1]);
}
+
+ @Test
+ public void testRebuildNotificationForCanceledSmartReplies() {
+ // Try rebuilding to remove spinner and hide buttons.
+ StatusBarNotification newSbn =
+ mEntryManager.rebuildNotificationForCanceledSmartReplies(mEntry);
+ Assert.assertFalse(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false));
+ Assert.assertTrue(newSbn.getNotification().extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index c6397e6..26f91b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -60,7 +60,6 @@
private NotificationListener mListener;
private StatusBarNotification mSbn;
- private Set<String> mKeysKeptForRemoteInput;
@Before
public void setUp() {
@@ -69,11 +68,8 @@
mDependency.injectTestDependency(NotificationRemoteInputManager.class,
mRemoteInputManager);
- mKeysKeptForRemoteInput = new HashSet<>();
-
when(mPresenter.getHandler()).thenReturn(Handler.createAsync(Looper.myLooper()));
when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
- when(mRemoteInputManager.getKeysKeptForRemoteInput()).thenReturn(mKeysKeptForRemoteInput);
mListener = new NotificationListener(mContext);
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
@@ -91,10 +87,9 @@
@Test
public void testPostNotificationRemovesKeyKeptForRemoteInput() {
- mKeysKeptForRemoteInput.add(mSbn.getKey());
mListener.onNotificationPosted(mSbn, mRanking);
TestableLooper.get(this).processAllMessages();
- assertTrue(mKeysKeptForRemoteInput.isEmpty());
+ verify(mEntryManager).removeKeyKeptForRemoteInput(mSbn.getKey());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java
index bbb03d7..42bf290 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLoggerTest.java
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar;
+import static org.junit.Assert.assertArrayEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -25,6 +27,7 @@
import android.app.Notification;
import android.os.Handler;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
@@ -43,6 +46,9 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -64,9 +70,10 @@
private NotificationData.Entry mEntry;
private StatusBarNotification mSbn;
private TestableNotificationLogger mLogger;
+ private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mDependency.injectTestDependency(NotificationListener.class, mListener);
@@ -84,17 +91,33 @@
@Test
public void testOnChildLocationsChangedReportsVisibilityChanged() throws Exception {
+ NotificationVisibility[] newlyVisibleKeys = {
+ NotificationVisibility.obtain(mEntry.key, 0, 1, true)
+ };
+ NotificationVisibility[] noLongerVisibleKeys = {};
+ doAnswer((Answer) invocation -> {
+ try {
+ assertArrayEquals(newlyVisibleKeys,
+ (NotificationVisibility[]) invocation.getArguments()[0]);
+ assertArrayEquals(noLongerVisibleKeys,
+ (NotificationVisibility[]) invocation.getArguments()[1]);
+ } catch (AssertionError error) {
+ mErrorQueue.offer(error);
+ }
+ return null;
+ }
+ ).when(mBarService).onNotificationVisibilityChanged(any(NotificationVisibility[].class),
+ any(NotificationVisibility[].class));
+
when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
TestableLooper.get(this).processAllMessages();
waitForUiOffloadThread();
- NotificationVisibility[] newlyVisibleKeys = {
- NotificationVisibility.obtain(mEntry.key, 0, 1, true)
- };
- NotificationVisibility[] noLongerVisibleKeys = {};
- verify(mBarService).onNotificationVisibilityChanged(newlyVisibleKeys, noLongerVisibleKeys);
+ if(!mErrorQueue.isEmpty()) {
+ throw mErrorQueue.poll();
+ }
// |mEntry| won't change visibility, so it shouldn't be reported again:
Mockito.reset(mBarService);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 8b2f6cd..7a2cb3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -86,11 +86,9 @@
@Test
public void testPerformOnRemoveNotification() {
when(mController.isRemoteInputActive(mEntry)).thenReturn(true);
- mRemoteInputManager.getKeysKeptForRemoteInput().add(mEntry.key);
mRemoteInputManager.onPerformRemoveNotification(mSbn, mEntry);
verify(mController).removeRemoteInput(mEntry, null);
- assertTrue(mRemoteInputManager.getKeysKeptForRemoteInput().isEmpty());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 84dceae..e91530d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -14,6 +14,8 @@
package com.android.systemui.statusbar;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
@@ -74,7 +76,7 @@
}
@Test
- public void testSendSmartReply_updatesRemoteInput() throws RemoteException {
+ public void testSendSmartReply_updatesRemoteInput() {
StatusBarNotification sbn = mock(StatusBarNotification.class);
when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
when(mNotificationEntryManager.rebuildNotificationWithRemoteInput(
@@ -118,4 +120,21 @@
verify(mIStatusBarService).onNotificationSmartRepliesAdded(TEST_NOTIFICATION_KEY,
TEST_CHOICE_COUNT);
}
+
+ @Test
+ public void testSendSmartReply_reportsSending() {
+ SmartReplyController controller = new SmartReplyController();
+ controller.smartReplySent(mEntry, TEST_CHOICE_INDEX, TEST_CHOICE_TEXT);
+
+ assertTrue(controller.isSendingSmartReply(TEST_NOTIFICATION_KEY));
+ }
+
+ @Test
+ public void testSendingSmartReply_afterRemove_shouldReturnFalse() {
+ SmartReplyController controller = new SmartReplyController();
+ controller.isSendingSmartReply(TEST_NOTIFICATION_KEY);
+ controller.stopSending(mEntry);
+
+ assertFalse(controller.isSendingSmartReply(TEST_NOTIFICATION_KEY));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index 73f05c4..12b14c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -326,6 +328,14 @@
}
@Test
+ public void testIsShowingScrimmed() {
+ mBouncer.show(false /* resetSecuritySelection */, true /* animate */);
+ assertThat(mBouncer.isShowingScrimmed()).isTrue();
+ mBouncer.show(false /* resetSecuritySelection */, false /* animate */);
+ assertThat(mBouncer.isShowingScrimmed()).isFalse();
+ }
+
+ @Test
public void testWillDismissWithAction() {
mBouncer.ensureView();
Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
new file mode 100644
index 0000000..e2e5b32
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.ViewGroup;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
+
+ @Mock
+ private ViewMediatorCallback mViewMediatorCallback;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private KeyguardBouncer mBouncer;
+ @Mock
+ private StatusBar mStatusBar;
+ @Mock
+ private ViewGroup mContainer;
+ @Mock
+ private NotificationPanelView mNotificationPanelView;
+ @Mock
+ private FingerprintUnlockController mFingerprintUnlockController;
+ @Mock
+ private DismissCallbackRegistry mDismissCallbackRegistry;
+ private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mDependency.injectMockDependency(StatusBarWindowManager.class);
+ mStatusBarKeyguardViewManager = new TestableStatusBarKeyguardViewManager(getContext(),
+ mViewMediatorCallback, mLockPatternUtils);
+ mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
+ mNotificationPanelView, mFingerprintUnlockController, mDismissCallbackRegistry);
+ mStatusBarKeyguardViewManager.show(null);
+ }
+
+ @Test
+ public void dismissWithAction_AfterKeyguardGoneSetToFalse() {
+ KeyguardHostView.OnDismissAction action = () -> false;
+ Runnable cancelAction = () -> {};
+ mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
+ false /* afterKeyguardGone */);
+ verify(mBouncer).showWithDismissAction(eq(action), eq(cancelAction));
+ }
+
+ @Test
+ public void showBouncer_onlyWhenShowing() {
+ mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
+ mStatusBar.showBouncer(true /* scrimmed */);
+ verify(mBouncer, never()).show(anyBoolean(), anyBoolean());
+ verify(mBouncer, never()).show(anyBoolean());
+ }
+
+ @Test
+ public void showBouncer_notWhenBouncerAlreadyShowing() {
+ mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
+ when(mBouncer.isSecure()).thenReturn(true);
+ mStatusBar.showBouncer(true /* scrimmed */);
+ verify(mBouncer, never()).show(anyBoolean(), anyBoolean());
+ verify(mBouncer, never()).show(anyBoolean());
+ }
+
+ @Test
+ public void showBouncer_showsTheBouncer() {
+ mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
+ verify(mBouncer).show(anyBoolean(), eq(true));
+ }
+
+ @Test
+ public void onPanelExpansionChanged_neverHidesFullscreenBouncer() {
+ // TODO: StatusBar should not be here, mBouncer.isFullscreenBouncer() should do the same.
+ when(mStatusBar.isFullScreenUserSwitcherState()).thenReturn(true);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
+ true /* tracking */);
+ verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
+ }
+
+ @Test
+ public void onPanelExpansionChanged_neverHidesScrimmedBouncer() {
+ when(mBouncer.isShowingScrimmed()).thenReturn(true);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
+ true /* tracking */);
+ verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
+ }
+
+ @Test
+ public void onPanelExpansionChanged_neverShowsDuringHintAnimation() {
+ when(mNotificationPanelView.isUnlockHintRunning()).thenReturn(true);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
+ true /* tracking */);
+ verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_HIDDEN));
+ }
+
+ @Test
+ public void onPanelExpansionChanged_propagatesToBouncer() {
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
+ true /* tracking */);
+ verify(mBouncer).setExpansion(eq(0.5f));
+ }
+
+ @Test
+ public void onPanelExpansionChanged_showsBouncerWhenSwiping() {
+ when(mStatusBar.isKeyguardCurrentlySecure()).thenReturn(true);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
+ true /* tracking */);
+ verify(mBouncer).show(eq(false), eq(false));
+
+ // But not when it's already visible
+ reset(mBouncer);
+ when(mBouncer.isShowing()).thenReturn(true);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */, true /* tracking */);
+ verify(mBouncer, never()).show(eq(false), eq(false));
+
+ // Or animating away
+ reset(mBouncer);
+ when(mBouncer.isAnimatingAway()).thenReturn(true);
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */, true /* tracking */);
+ verify(mBouncer, never()).show(eq(false), eq(false));
+ }
+
+ private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
+
+ public TestableStatusBarKeyguardViewManager(Context context,
+ ViewMediatorCallback callback,
+ LockPatternUtils lockPatternUtils) {
+ super(context, callback, lockPatternUtils);
+ }
+
+ @Override
+ public void registerStatusBar(StatusBar statusBar, ViewGroup container,
+ NotificationPanelView notificationPanelView,
+ FingerprintUnlockController fingerprintUnlockController,
+ DismissCallbackRegistry dismissCallbackRegistry) {
+ super.registerStatusBar(statusBar, container, notificationPanelView,
+ fingerprintUnlockController, dismissCallbackRegistry);
+ mBouncer = StatusBarKeyguardViewManagerTest.this.mBouncer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
index eeb4209..5400e3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
@@ -18,6 +18,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -28,12 +29,10 @@
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.TestableDependency;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FooterView;
import com.android.systemui.statusbar.NotificationBlockingHelperManager;
@@ -169,12 +168,11 @@
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
when(view.willBeGone()).thenReturn(true);
- when(view.isSecondaryVisible()).thenReturn(true);
mStackScroller.updateFooterView(true, false);
- verify(view).setVisibility(View.VISIBLE);
- verify(view).performSecondaryVisibilityAnimation(false);
+ verify(view).setVisible(eq(true), anyBoolean());
+ verify(view).setSecondaryVisible(eq(false), anyBoolean());
}
@Test
@@ -182,11 +180,10 @@
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
when(view.willBeGone()).thenReturn(true);
- when(view.isSecondaryVisible()).thenReturn(false);
mStackScroller.updateFooterView(true, true);
- verify(view).setVisibility(View.VISIBLE);
- verify(view).performSecondaryVisibilityAnimation(true);
+ verify(view).setVisible(eq(true), anyBoolean());
+ verify(view).setSecondaryVisible(eq(true), anyBoolean());
}
}
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 8fa6b3e..9ff8e7d 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -450,6 +450,9 @@
// Number of radio mode changes to DBS (Dual band simultaneous).
optional int32 num_radio_mode_change_to_dbs = 115;
+
+ // Number of times the firmware picked a SoftAp channel not satisfying user band preference.
+ optional int32 num_soft_ap_user_band_preference_unsatisfied = 116;
}
// Information that gets logged for every WiFi connection.
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 1aeb3b9..8119054 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -228,8 +228,8 @@
mWindow = null;
return;
}
- decor.setFocusable(true);
- decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
+ container.setFocusable(true);
+ container.setOnClickListener(v -> mCallback.onResponsePicked(response));
if (!mFullScreen) {
final Point maxSize = mTempPoint;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6f572df..4c2a940 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -64,6 +64,7 @@
import com.android.internal.util.FastPrintWriter;
import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityManagerService.NeededUriGrants;
@@ -2012,6 +2013,25 @@
+ why + " of " + r + " in app " + r.app);
else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
+ why + " of " + r.shortName);
+
+ // For b/34123235: Services within the system server won't start until SystemServer
+ // does Looper.loop(), so we shouldn't try to start/bind to them too early in the boot
+ // process. However, since there's a little point of showing the ANR dialog in that case,
+ // let's suppress the timeout until PHASE_THIRD_PARTY_APPS_CAN_START.
+ //
+ // (Note there are multiple services start at PHASE_THIRD_PARTY_APPS_CAN_START too,
+ // which technically could also trigger this timeout if there's a system server
+ // that takes a long time to handle PHASE_THIRD_PARTY_APPS_CAN_START, but that shouldn't
+ // happen.)
+ boolean timeoutNeeded = true;
+ if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
+ && (r.app != null) && (r.app.pid == android.os.Process.myPid())) {
+
+ Slog.w(TAG, "Too early to start/bind service in system_server: Phase=" + mAm.mBootPhase
+ + " " + r.getComponentName());
+ timeoutNeeded = false;
+ }
+
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
@@ -2022,13 +2042,15 @@
if (r.app != null) {
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
- if (r.app.executingServices.size() == 1) {
+ if (timeoutNeeded && r.app.executingServices.size() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
- scheduleServiceTimeoutLocked(r.app);
+ if (timeoutNeeded) {
+ scheduleServiceTimeoutLocked(r.app);
+ }
}
r.executeFg |= fg;
r.executeNesting++;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70648c6..113f452 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1850,6 +1850,11 @@
*/
boolean mBooted = false;
+ /**
+ * Current boot phase.
+ */
+ int mBootPhase;
+
WindowManagerService mWindowManager;
final ActivityThread mSystemThread;
@@ -2881,6 +2886,7 @@
@Override
public void onBootPhase(int phase) {
+ mService.mBootPhase = phase;
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 818a609..aaa5161 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -1759,10 +1760,16 @@
// In this case the home stack isn't resizeable even though we are in split-screen
// mode. We still want the primary splitscreen stack to be visible as there will be
// a slight hint of it in the status bar area above the non-resizeable home
- // activity.
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- && other.getActivityType() == ACTIVITY_TYPE_HOME) {
- return true;
+ // activity. In addition, if the fullscreen assistant is over primary splitscreen
+ // stack, the stack should still be visible in the background as long as the recents
+ // animation is running.
+ final int activityType = other.getActivityType();
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ if (activityType == ACTIVITY_TYPE_HOME
+ || (activityType == ACTIVITY_TYPE_ASSISTANT
+ && mWindowManager.getRecentsAnimationController() != null)) {
+ return true;
+ }
}
if (other.isStackTranslucent(starting)) {
// Can be visible behind a translucent fullscreen stack.
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 5764382..ddf9552 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -132,6 +132,8 @@
if (showingChanged) {
dismissDockedStackIfNeeded();
setKeyguardGoingAway(false);
+ mWindowManager.setKeyguardOrAodShowingOnDefaultDisplay(
+ isKeyguardOrAodShowing(DEFAULT_DISPLAY));
if (keyguardShowing) {
mDismissalRequested = false;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6c79c1a..7c9a3ae 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1320,6 +1320,11 @@
}
String enabledSurroundFormats = Settings.Global.getString(
cr, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS);
+ if (enabledSurroundFormats == null) {
+ // Never allow enabledSurroundFormats as a null, which could happen when
+ // ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS is not appear in settings DB.
+ enabledSurroundFormats = "";
+ }
if (!forceUpdate && TextUtils.equals(enabledSurroundFormats, mEnabledSurroundFormats)) {
// Update enabled surround formats to AudioPolicyManager only when forceUpdate
// is true or enabled surround formats changed.
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index d51a196..c0beb37 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -16,7 +16,7 @@
package com.android.server.connectivity;
-import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
@@ -24,6 +24,7 @@
import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
+import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -184,6 +185,7 @@
public static Uri[] getPrivateDnsSettingsUris() {
return new Uri[]{
+ Settings.Global.getUriFor(PRIVATE_DNS_DEFAULT_MODE),
Settings.Global.getUriFor(PRIVATE_DNS_MODE),
Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
};
@@ -485,8 +487,10 @@
}
private static String getPrivateDnsMode(ContentResolver cr) {
- final String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
- return !TextUtils.isEmpty(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE;
+ String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
+ if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
+ if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
+ return mode;
}
private static String getStringSetting(ContentResolver cr, String which) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index c9f92d2..0b84bd9 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -1499,8 +1499,10 @@
try {
userId = getUserOrWorkProfileId(clientPackage, userId);
if (userId != mCurrentUserId) {
+ int firstSdkInt = Build.VERSION.FIRST_SDK_INT;
+ if (firstSdkInt == 0) firstSdkInt = Build.VERSION.SDK_INT;
File baseDir;
- if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
+ if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
baseDir = Environment.getUserSystemDirectory(userId);
} else {
baseDir = Environment.getDataVendorDeDirectory(userId);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 5d71cc7..f1951b1 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -33,6 +33,7 @@
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
@@ -176,7 +177,11 @@
List<Integer> recoveryAgents = mRecoverableKeyStoreDb.getRecoveryAgents(mUserId);
for (int uid : recoveryAgents) {
- syncKeysForAgent(uid);
+ try {
+ syncKeysForAgent(uid);
+ } catch (IOException e) {
+ Log.e(TAG, "IOException during sync for agent " + uid, e);
+ }
}
if (recoveryAgents.isEmpty()) {
Log.w(TAG, "No recovery agent initialized for user " + mUserId);
@@ -189,13 +194,13 @@
&& mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
}
- private void syncKeysForAgent(int recoveryAgentUid) {
- boolean recreateCurrentVersion = false;
+ private void syncKeysForAgent(int recoveryAgentUid) throws IOException {
+ boolean shouldRecreateCurrentVersion = false;
if (!shouldCreateSnapshot(recoveryAgentUid)) {
- recreateCurrentVersion =
+ shouldRecreateCurrentVersion =
(mRecoverableKeyStoreDb.getSnapshotVersion(mUserId, recoveryAgentUid) != null)
&& (mRecoverySnapshotStorage.get(recoveryAgentUid) == null);
- if (recreateCurrentVersion) {
+ if (shouldRecreateCurrentVersion) {
Log.d(TAG, "Recreating most recent snapshot");
} else {
Log.d(TAG, "Key sync not needed.");
@@ -203,12 +208,12 @@
}
}
- PublicKey publicKey;
String rootCertAlias =
mRecoverableKeyStoreDb.getActiveRootOfTrust(mUserId, recoveryAgentUid);
rootCertAlias = mTestOnlyInsecureCertificateHelper
.getDefaultCertificateAliasIfEmpty(rootCertAlias);
+ PublicKey publicKey;
CertPath certPath = mRecoverableKeyStoreDb.getRecoveryServiceCertPath(mUserId,
recoveryAgentUid, rootCertAlias);
if (certPath != null) {
@@ -260,19 +265,22 @@
Log.e(TAG, "Failed to load recoverable keys for sync", e);
return;
} catch (InsecureUserException e) {
- Log.wtf(TAG, "A screen unlock triggered the key sync flow, so user must have "
+ Log.e(TAG, "A screen unlock triggered the key sync flow, so user must have "
+ "lock screen. This should be impossible.", e);
return;
} catch (BadPlatformKeyException e) {
- Log.wtf(TAG, "Loaded keys for same generation ID as platform key, so "
+ Log.e(TAG, "Loaded keys for same generation ID as platform key, so "
+ "BadPlatformKeyException should be impossible.", e);
return;
+ } catch (IOException e) {
+ Log.e(TAG, "Local database error.", e);
+ return;
}
-
// Only include insecure key material for test
if (mTestOnlyInsecureCertificateHelper.isTestOnlyCertificateAlias(rootCertAlias)) {
rawKeys = mTestOnlyInsecureCertificateHelper.keepOnlyWhitelistedInsecureKeys(rawKeys);
}
+
SecretKey recoveryKey;
try {
recoveryKey = generateRecoveryKey();
@@ -323,6 +331,7 @@
Log.e(TAG,"Could not encrypt with recovery key", e);
return;
}
+
KeyDerivationParams keyDerivationParams;
if (useScryptToHashCredential) {
keyDerivationParams = KeyDerivationParams.createScryptParams(
@@ -330,7 +339,7 @@
} else {
keyDerivationParams = KeyDerivationParams.createSha256Params(salt);
}
- KeyChainProtectionParams metadata = new KeyChainProtectionParams.Builder()
+ KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder()
.setUserSecretType(TYPE_LOCKSCREEN)
.setLockScreenUiFormat(getUiFormat(mCredentialType, mCredential))
.setKeyDerivationParams(keyDerivationParams)
@@ -338,13 +347,11 @@
.build();
ArrayList<KeyChainProtectionParams> metadataList = new ArrayList<>();
- metadataList.add(metadata);
-
- // If application keys are not updated, snapshot will not be created on next unlock.
- mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false);
+ metadataList.add(keyChainProtectionParams);
KeyChainSnapshot.Builder keyChainSnapshotBuilder = new KeyChainSnapshot.Builder()
- .setSnapshotVersion(getSnapshotVersion(recoveryAgentUid, recreateCurrentVersion))
+ .setSnapshotVersion(
+ getSnapshotVersion(recoveryAgentUid, shouldRecreateCurrentVersion))
.setMaxAttempts(TRUSTED_HARDWARE_MAX_ATTEMPTS)
.setCounterId(counterId)
.setServerParams(vaultHandle)
@@ -360,25 +367,38 @@
}
mRecoverySnapshotStorage.put(recoveryAgentUid, keyChainSnapshotBuilder.build());
mSnapshotListenersStorage.recoverySnapshotAvailable(recoveryAgentUid);
+
+ mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false);
}
@VisibleForTesting
- int getSnapshotVersion(int recoveryAgentUid, boolean recreateCurrentVersion) {
+ int getSnapshotVersion(int recoveryAgentUid, boolean shouldRecreateCurrentVersion)
+ throws IOException {
Long snapshotVersion = mRecoverableKeyStoreDb.getSnapshotVersion(mUserId, recoveryAgentUid);
- if (recreateCurrentVersion) {
+ if (shouldRecreateCurrentVersion) {
// version shouldn't be null at this moment.
snapshotVersion = snapshotVersion == null ? 1 : snapshotVersion;
} else {
snapshotVersion = snapshotVersion == null ? 1 : snapshotVersion + 1;
}
- mRecoverableKeyStoreDb.setSnapshotVersion(mUserId, recoveryAgentUid, snapshotVersion);
+
+ long updatedRows = mRecoverableKeyStoreDb.setSnapshotVersion(mUserId, recoveryAgentUid,
+ snapshotVersion);
+ if (updatedRows < 0) {
+ Log.e(TAG, "Failed to set the snapshot version in the local DB.");
+ throw new IOException("Failed to set the snapshot version in the local DB.");
+ }
return snapshotVersion.intValue();
}
- private long generateAndStoreCounterId(int recoveryAgentUid) {
+ private long generateAndStoreCounterId(int recoveryAgentUid) throws IOException {
long counter = new SecureRandom().nextLong();
- mRecoverableKeyStoreDb.setCounterId(mUserId, recoveryAgentUid, counter);
+ long updatedRows = mRecoverableKeyStoreDb.setCounterId(mUserId, recoveryAgentUid, counter);
+ if (updatedRows < 0) {
+ Log.e(TAG, "Failed to set the snapshot version in the local DB.");
+ throw new IOException("Failed to set counterId in the local DB.");
+ }
return counter;
}
@@ -388,7 +408,7 @@
private Map<String, SecretKey> getKeysToSync(int recoveryAgentUid)
throws InsecureUserException, KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
- InvalidKeyException, InvalidAlgorithmParameterException {
+ InvalidKeyException, InvalidAlgorithmParameterException, IOException {
PlatformDecryptionKey decryptKey = mPlatformKeyManager.getDecryptKey(mUserId);;
Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys(
mUserId, recoveryAgentUid, decryptKey.getGenerationId());
@@ -440,7 +460,7 @@
*
* @return The salt.
*/
- private byte[] generateSalt() {
+ private static byte[] generateSalt() {
byte[] salt = new byte[SALT_LENGTH_BYTES];
new SecureRandom().nextBytes(salt);
return salt;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
index 57fb74d..8e6f9cb 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncUtils.java
@@ -37,7 +37,7 @@
import javax.crypto.SecretKey;
/**
- * Utility functions for the flow where the RecoveryManager syncs keys with remote storage.
+ * Utility functions for the flow where the RecoveryController syncs keys with remote storage.
*
* @hide
*/
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 52394d2..9ca052b 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -157,11 +157,13 @@
* @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
* @throws KeyStoreException if there is an error in AndroidKeyStore.
* @throws InsecureUserException if the user does not have a lock screen set.
+ * @throws IOException if there was an issue with local database update.
*
* @hide
*/
- public void regenerate(int userId)
- throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException {
+ @VisibleForTesting
+ void regenerate(int userId)
+ throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException {
if (!isAvailable(userId)) {
throw new InsecureUserException(String.format(
Locale.US, "%d does not have a lock screen set.", userId));
@@ -187,11 +189,12 @@
* @throws UnrecoverableKeyException if the key could not be recovered.
* @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
* @throws InsecureUserException if the user does not have a lock screen set.
+ * @throws IOException if there was an issue with local database update.
*
* @hide
*/
public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException,
- UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
+ UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
init(userId);
try {
// Try to see if the decryption key is still accessible before using the encryption key.
@@ -239,11 +242,12 @@
* @throws UnrecoverableKeyException if the key could not be recovered.
* @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
* @throws InsecureUserException if the user does not have a lock screen set.
+ * @throws IOException if there was an issue with local database update.
*
* @hide
*/
public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException,
- UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
+ UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
init(userId);
try {
return getDecryptKeyInternal(userId);
@@ -286,11 +290,12 @@
* @param userId The ID of the user to whose lock screen the platform key must be bound.
* @throws KeyStoreException if there was an error in AndroidKeyStore.
* @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
+ * @throws IOException if there was an issue with local database update.
*
* @hide
*/
void init(int userId)
- throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException {
+ throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException {
if (!isAvailable(userId)) {
throw new InsecureUserException(String.format(
Locale.US, "%d does not have a lock screen set.", userId));
@@ -347,9 +352,13 @@
/**
* Sets the current generation ID to {@code generationId}.
+ * @throws IOException if there was an issue with local database update.
*/
- private void setGenerationId(int userId, int generationId) {
- mDatabase.setPlatformKeyGenerationId(userId, generationId);
+ private void setGenerationId(int userId, int generationId) throws IOException {
+ long updatedRows = mDatabase.setPlatformKeyGenerationId(userId, generationId);
+ if (updatedRows < 0) {
+ throw new IOException("Failed to set the platform key in the local DB.");
+ }
}
/**
@@ -370,9 +379,10 @@
* @throws NoSuchAlgorithmException if AES is unavailable. This should never happen, as it is
* available since API version 1.
* @throws KeyStoreException if there was an issue loading the keys into AndroidKeyStore.
+ * @throws IOException if there was an issue with local database update.
*/
private void generateAndLoadKey(int userId, int generationId)
- throws NoSuchAlgorithmException, KeyStoreException {
+ throws NoSuchAlgorithmException, KeyStoreException, IOException {
String encryptAlias = getEncryptAlias(userId, generationId);
String decryptAlias = getDecryptAlias(userId, generationId);
// SecretKey implementation doesn't provide reliable way to destroy the secret
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
index 396862d..c249468 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java
@@ -24,6 +24,7 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
+import android.util.Log;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@@ -40,6 +41,7 @@
*/
public class RecoverableKeyGenerator {
+ private static final String TAG = "PlatformKeyGen";
private static final int RESULT_CANNOT_INSERT_ROW = -1;
private static final String SECRET_KEY_ALGORITHM = "AES";
@@ -104,7 +106,11 @@
Locale.US, "Failed writing (%d, %s) to database.", uid, alias));
}
- mDatabase.setShouldCreateSnapshot(userId, uid, true);
+ long updatedRows = mDatabase.setShouldCreateSnapshot(userId, uid, true);
+ if (updatedRows < 0) {
+ Log.e(TAG, "Failed to set the shoudCreateSnapshot flag in the local DB.");
+ }
+
return key.getEncoded();
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 09906e4..fc5184d 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -57,6 +57,7 @@
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
+import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyStoreException;
@@ -189,11 +190,14 @@
if (activeRootAlias == null) {
Log.d(TAG, "Root of trust for recovery agent + " + uid
+ " is assigned for the first time to " + rootCertificateAlias);
- mDatabase.setActiveRootOfTrust(userId, uid, rootCertificateAlias);
} else if (!activeRootAlias.equals(rootCertificateAlias)) {
Log.i(TAG, "Root of trust for recovery agent " + uid + " is changed to "
+ rootCertificateAlias + " from " + activeRootAlias);
- mDatabase.setActiveRootOfTrust(userId, uid, rootCertificateAlias);
+ }
+ long updatedRows = mDatabase.setActiveRootOfTrust(userId, uid, rootCertificateAlias);
+ if (updatedRows < 0) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR,
+ "Failed to set the root of trust in the local DB.");
}
CertXml certXml;
@@ -236,17 +240,32 @@
// Save the chosen and validated certificate into database
try {
Log.d(TAG, "Saving the randomly chosen endpoint certificate to database");
- if (mDatabase.setRecoveryServiceCertPath(userId, uid, rootCertificateAlias,
- certPath) > 0) {
- mDatabase.setRecoveryServiceCertSerial(userId, uid, rootCertificateAlias,
- newSerial);
+ long updatedCertPathRows = mDatabase.setRecoveryServiceCertPath(userId, uid,
+ rootCertificateAlias, certPath);
+ if (updatedCertPathRows > 0) {
+ long updatedCertSerialRows = mDatabase.setRecoveryServiceCertSerial(userId, uid,
+ rootCertificateAlias, newSerial);
+ if (updatedCertSerialRows < 0) {
+ // Ideally CertPath and CertSerial should be updated together in single
+ // transaction, but since their mismatch doesn't create many problems
+ // extra complexity is unnecessary.
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR,
+ "Failed to set the certificate serial number in the local DB.");
+ }
if (mDatabase.getSnapshotVersion(userId, uid) != null) {
mDatabase.setShouldCreateSnapshot(userId, uid, true);
Log.i(TAG, "This is a certificate change. Snapshot must be updated");
} else {
Log.i(TAG, "This is a certificate change. Snapshot didn't exist");
}
- mDatabase.setCounterId(userId, uid, new SecureRandom().nextLong());
+ long updatedCounterIdRows =
+ mDatabase.setCounterId(userId, uid, new SecureRandom().nextLong());
+ if (updatedCounterIdRows < 0) {
+ Log.e(TAG, "Failed to set the counter id in the local DB.");
+ }
+ } else if (updatedCertPathRows < 0) {
+ throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR,
+ "Failed to set the certificate path in the local DB.");
}
} catch (CertificateEncodingException e) {
Log.e(TAG, "Failed to encode CertPath", e);
@@ -340,7 +359,7 @@
}
long updatedRows = mDatabase.setServerParams(userId, uid, serverParams);
- if (updatedRows < 1) {
+ if (updatedRows < 0) {
throw new ServiceSpecificException(
ERROR_SERVICE_INTERNAL_ERROR, "Database failure trying to set server params.");
}
@@ -364,7 +383,12 @@
public void setRecoveryStatus(@NonNull String alias, int status) throws RemoteException {
checkRecoverKeyStorePermission();
Preconditions.checkNotNull(alias, "alias is null");
- mDatabase.setRecoveryStatus(Binder.getCallingUid(), alias, status);
+ long updatedRows = mDatabase.setRecoveryStatus(Binder.getCallingUid(), alias, status);
+ if (updatedRows < 0) {
+ throw new ServiceSpecificException(
+ ERROR_SERVICE_INTERNAL_ERROR,
+ "Failed to set the key recovery status in the local DB.");
+ }
}
/**
@@ -400,7 +424,7 @@
}
long updatedRows = mDatabase.setRecoverySecretTypes(userId, uid, secretTypes);
- if (updatedRows < 1) {
+ if (updatedRows < 0) {
throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR,
"Database error trying to set secret types.");
}
@@ -664,7 +688,7 @@
} catch (NoSuchAlgorithmException e) {
// Impossible: all algorithms must be supported by AOSP
throw new RuntimeException(e);
- } catch (KeyStoreException | UnrecoverableKeyException e) {
+ } catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
} catch (InsecureUserException e) {
throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
@@ -713,7 +737,7 @@
} catch (NoSuchAlgorithmException e) {
// Impossible: all algorithms must be supported by AOSP
throw new RuntimeException(e);
- } catch (KeyStoreException | UnrecoverableKeyException e) {
+ } catch (KeyStoreException | UnrecoverableKeyException | IOException e) {
throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
} catch (InsecureUserException e) {
throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage());
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 7ee809a..22e77cc 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -64,7 +64,7 @@
static final String COLUMN_NAME_LAST_SYNCED_AT = "last_synced_at";
/**
- * Status of the key sync {@code RecoveryManager#setRecoveryStatus}
+ * Status of the key sync {@code RecoveryController#setRecoveryStatus}
*/
static final String COLUMN_NAME_RECOVERY_STATUS = "recovery_status";
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 01f84c4..cd9efdc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -78,6 +78,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+import android.system.Os;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArraySet;
@@ -1373,7 +1375,9 @@
try (OutputStream outStream = new FileOutputStream(outputProfilePath)) {
Streams.copy(inStream, outStream);
}
- } catch (IOException e) {
+ // Give read permissions to the other group.
+ Os.chmod(outputProfilePath, /*mode*/ 0644 );
+ } catch (IOException | ErrnoException e) {
pw.println("Error when reading the profile fd: " + e.getMessage());
e.printStackTrace(pw);
return -1;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5ee7084..d911761 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -931,7 +931,7 @@
accessibilityShortcutActivated();
break;
case MSG_BUGREPORT_TV:
- takeBugreport();
+ requestFullBugreport();
break;
case MSG_ACCESSIBILITY_TV:
if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(false)) {
@@ -1138,6 +1138,7 @@
}
getAudioManagerInternal();
mAudioManagerInternal.silenceRingerModeInternal("volume_hush");
+ Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.HUSH_GESTURE_USED, 1);
mLogger.action(MetricsProto.MetricsEvent.ACTION_HUSH_GESTURE, mRingerToggleChord);
}
@@ -4108,13 +4109,13 @@
return mAccessibilityTvScheduled;
}
- private void takeBugreport() {
+ private void requestFullBugreport() {
if ("1".equals(SystemProperties.get("ro.debuggable"))
|| Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) {
try {
ActivityManager.getService()
- .requestBugReport(ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
+ .requestBugReport(ActivityManager.BUGREPORT_OPTION_FULL);
} catch (RemoteException e) {
Slog.e(TAG, "Error taking bugreport", e);
}
@@ -5082,7 +5083,7 @@
final int fl = PolicyControl.getWindowFlags(win, attrs);
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
- final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(win, null);
+ final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
final Rect pf = mTmpParentFrame;
diff --git a/services/core/java/com/android/server/policy/PolicyControl.java b/services/core/java/com/android/server/policy/PolicyControl.java
index 3f26d86..48e72bc 100644
--- a/services/core/java/com/android/server/policy/PolicyControl.java
+++ b/services/core/java/com/android/server/policy/PolicyControl.java
@@ -65,7 +65,8 @@
public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
attrs = attrs != null ? attrs : win.getAttrs();
- int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+ int vis = win != null ? win.getSystemUiVisibility()
+ : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility);
if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index a492672..eecf17a 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.Intent;
import android.hardware.input.InputManagerInternal;
+import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
@@ -40,20 +41,21 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Slog;
import android.view.inputmethod.InputMethodManagerInternal;
-import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.statusbar.StatusBarManagerInternal;
/**
* Sends broadcasts about important power state changes.
@@ -88,6 +90,21 @@
private static final int MSG_PROFILE_TIMED_OUT = 5;
private static final int MSG_WIRED_CHARGING_STARTED = 6;
+ private static final long[] WIRELESS_VIBRATION_TIME = {
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, // ramp-up sampling rate = 40ms
+ 40, 40, 40, 40, 40, 40, 40 // ramp-down sampling rate = 40ms
+ };
+ private static final int[] WIRELESS_VIBRATION_AMPLITUDE = {
+ 1, 4, 11, 25, 44, 67, 91, 114, 123, // ramp-up amplitude (from 0 to 50%)
+ 103, 79, 55, 34, 17, 7, 2 // ramp-up amplitude
+ };
+ private static final VibrationEffect WIRELESS_CHARGING_VIBRATION_EFFECT =
+ VibrationEffect.createWaveform(WIRELESS_VIBRATION_TIME, WIRELESS_VIBRATION_AMPLITUDE,
+ -1);
+ private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build();
+
private final Object mLock = new Object();
private final Context mContext;
@@ -100,6 +117,7 @@
private final InputMethodManagerInternal mInputMethodManagerInternal;
@Nullable private final StatusBarManagerInternal mStatusBarManagerInternal;
private final TrustManager mTrustManager;
+ private final Vibrator mVibrator;
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
@@ -146,6 +164,7 @@
mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
mTrustManager = mContext.getSystemService(TrustManager.class);
+ mVibrator = mContext.getSystemService(Vibrator.class);
mHandler = new NotifierHandler(looper);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -719,14 +738,9 @@
* Plays the wireless charging sound for both wireless and non-wireless charging
*/
private void playChargingStartedSound() {
- final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
- final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
- == Settings.Global.ZEN_MODE_OFF;
final String soundPath = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.CHARGING_STARTED_SOUND);
- if (enabled && dndOff && soundPath != null) {
+ if (isChargingFeedbackEnabled() && soundPath != null) {
final Uri soundUri = Uri.parse("file://" + soundPath);
if (soundUri != null) {
final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
@@ -739,6 +753,7 @@
}
private void showWirelessChargingStarted(int batteryLevel) {
+ playWirelessChargingVibration();
playChargingStartedSound();
if (mStatusBarManagerInternal != null) {
mStatusBarManagerInternal.showChargingAnimation(batteryLevel);
@@ -755,6 +770,23 @@
mTrustManager.setDeviceLockedForUser(userId, true /*locked*/);
}
+ private void playWirelessChargingVibration() {
+ final boolean vibrateEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.CHARGING_VIBRATION_ENABLED, 0) != 0;
+ if (vibrateEnabled && isChargingFeedbackEnabled()) {
+ mVibrator.vibrate(WIRELESS_CHARGING_VIBRATION_EFFECT, VIBRATION_ATTRIBUTES);
+ }
+ }
+
+ private boolean isChargingFeedbackEnabled() {
+ final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.CHARGING_SOUNDS_ENABLED, 1) != 0;
+ final boolean dndOff = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS)
+ == Settings.Global.ZEN_MODE_OFF;
+ return enabled && dndOff;
+ }
+
private final class NotifierHandler extends Handler {
public NotifierHandler(Looper looper) {
@@ -780,6 +812,7 @@
break;
case MSG_WIRED_CHARGING_STARTED:
showWiredChargingStarted();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index f5f994a..a6ec3cf 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -674,6 +674,7 @@
mTempLayer = 0;
dc.forAllWindows((w) -> {
if (w.isOnScreen() && w.isVisibleLw()
+ && (w.mAttrs.alpha != 0)
&& !w.mWinAnimator.mEnterAnimationPending) {
mTempLayer++;
outWindows.put(mTempLayer, w);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 39a3629..cd8d677 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -692,7 +692,7 @@
// Do not minimize when dock is already minimized while keyguard is showing and not
// occluded such as unlocking the screen
- if (mMinimizedDock && mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
+ if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
return;
}
final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 16399008..cb64142 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -369,7 +369,10 @@
final WindowTracing mWindowTracing;
final private KeyguardDisableHandler mKeyguardDisableHandler;
+ // TODO: eventually unify all keyguard state in a common place instead of having it spread over
+ // AM's KeyguardController and the policy's KeyguardServiceDelegate.
boolean mKeyguardGoingAway;
+ boolean mKeyguardOrAodShowingOnDefaultDisplay;
// VR Vr2d Display Id.
int mVr2dDisplayId = INVALID_DISPLAY;
@@ -2909,6 +2912,12 @@
}
}
+ public void setKeyguardOrAodShowingOnDefaultDisplay(boolean showing) {
+ synchronized (mWindowMap) {
+ mKeyguardOrAodShowingOnDefaultDisplay = showing;
+ }
+ }
+
// -------------------------------------------------------------
// Misc IWindowSession methods
// -------------------------------------------------------------
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 91c449b..dac85b3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -409,7 +409,7 @@
final Rect mContainingFrame = new Rect();
- private final Rect mParentFrame = new Rect();
+ final Rect mParentFrame = new Rect();
/** Whether the parent frame would have been different if there was no display cutout. */
private boolean mParentFrameWasClippedByDisplayCutout;
@@ -931,6 +931,17 @@
mContainingFrame.set(contentFrame);
}
}
+
+ final TaskStack stack = getStack();
+ if (inPinnedWindowingMode() && stack != null
+ && stack.lastAnimatingBoundsWasToFullscreen()) {
+ // PIP edge case: When going from pinned to fullscreen, we apply a
+ // tempInsetFrame for the full task - but we're still at the start of the animation.
+ // To prevent a jump if there's a letterbox, restrict to the parent frame.
+ mInsetFrame.intersectUnchecked(parentFrame);
+ mContainingFrame.intersectUnchecked(parentFrame);
+ }
+
mDisplayFrame.set(mContainingFrame);
layoutXDiff = !mInsetFrame.isEmpty() ? mInsetFrame.left - mContainingFrame.left : 0;
layoutYDiff = !mInsetFrame.isEmpty() ? mInsetFrame.top - mContainingFrame.top : 0;
@@ -4404,14 +4415,6 @@
result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
- if (mWinAnimator.mChildrenDetached) {
- // If there are detached children hanging around we need to force
- // the client receiving a new Surface.
- mWinAnimator.preserveSurfaceLocked();
- result |= RELAYOUT_RES_SURFACE_CHANGED
- | RELAYOUT_RES_FIRST_TIME;
- }
-
if (mAnimatingExit) {
Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
+ mRemoveOnExit + ", mDestroying=" + mDestroying);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 4a6587b..3eef125 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -927,6 +927,13 @@
mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
allowStretching = true;
}
+
+ // Make sure that what we're animating to and from is actually the right size in case
+ // the window cannot take up the full screen.
+ mTmpStackBounds.intersectUnchecked(w.mParentFrame);
+ mTmpSourceBounds.intersectUnchecked(w.mParentFrame);
+ mTmpAnimatingBounds.intersectUnchecked(w.mParentFrame);
+
if (!mTmpSourceBounds.isEmpty()) {
// Get the final target stack bounds, if we are not animating, this is just the
// current stack bounds
@@ -1291,6 +1298,7 @@
// if we are transparent.
if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
mPendingDestroySurface.mSurfaceControl.hide();
+ mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
}
return true;
diff --git a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
index 24d925f..a2ccee4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -159,7 +159,12 @@
updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
0, PRIVATE_FLAG_IS_SCREEN_DECOR);
- assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
+
+ // TODO: fix test and re-enable assertion.
+ // initialInsets was not actually immutable and just updated to the current insets,
+ // meaning this assertion never actually tested anything. Now that WindowInsets actually is
+ // immutable, it turns out the test was broken.
+ // assertTopInsetEquals(mTestActivity, initialInsets.getSystemWindowInsetTop());
updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 243718a..71f9bb3 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -585,6 +585,9 @@
flushToDiskLocked();
pw.println("Flushed stats to disk");
return;
+ } else if ("is-app-standby-enabled".equals(arg)) {
+ pw.println(mAppStandby.mAppIdleEnabled);
+ return;
} else if (arg != null && !arg.startsWith("-")) {
// Anything else that doesn't start with '-' is a pkg to filter
pkg = arg;
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 1ec4eec..01b468a 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -19,6 +19,9 @@
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
+import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
+import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -40,6 +43,7 @@
import android.test.mock.MockContentResolver;
import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
import com.android.server.connectivity.MockableSystemProperties;
import java.net.InetAddress;
@@ -84,10 +88,9 @@
mDnsManager = new DnsManager(mCtx, mNMService, mSystemProperties);
// Clear the private DNS settings
- Settings.Global.putString(mContentResolver,
- Settings.Global.PRIVATE_DNS_MODE, "");
- Settings.Global.putString(mContentResolver,
- Settings.Global.PRIVATE_DNS_SPECIFIER, "");
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, "");
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "");
}
@Test
@@ -127,9 +130,8 @@
TEST_IFACENAME));
Settings.Global.putString(mContentResolver,
- Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- Settings.Global.putString(mContentResolver,
- Settings.Global.PRIVATE_DNS_SPECIFIER, "strictmode.com");
+ PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
mDnsManager.updatePrivateDns(new Network(TEST_NETID),
new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] {
InetAddress.parseNumericAddress("6.6.6.6"),
@@ -222,8 +224,7 @@
assertNull(lp.getPrivateDnsServerName());
// Turn private DNS mode off
- Settings.Global.putString(mContentResolver,
- Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF);
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF);
mDnsManager.updatePrivateDns(new Network(TEST_NETID),
mDnsManager.getPrivateDnsConfig());
mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
@@ -234,4 +235,29 @@
assertFalse(lp.isPrivateDnsActive());
assertNull(lp.getPrivateDnsServerName());
}
+
+ @Test
+ public void testOverrideDefaultMode() throws Exception {
+ // Hard-coded default is opportunistic mode.
+ final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mContentResolver);
+ assertTrue(cfgAuto.useTls);
+ assertEquals("", cfgAuto.hostname);
+ assertEquals(new InetAddress[0], cfgAuto.ips);
+
+ // Pretend a gservices push sets the default to "off".
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off");
+ final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mContentResolver);
+ assertFalse(cfgOff.useTls);
+ assertEquals("", cfgOff.hostname);
+ assertEquals(new InetAddress[0], cfgOff.ips);
+
+ // Strict mode still works.
+ Settings.Global.putString(
+ mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
+ final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mContentResolver);
+ assertTrue(cfgStrict.useTls);
+ assertEquals("strictmode.com", cfgStrict.hostname);
+ assertEquals(new InetAddress[0], cfgStrict.ips);
+ }
}