Merge "Moar lint rulez!"
diff --git a/api/current.txt b/api/current.txt
index 1b09710..87aaaa6 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -773,6 +773,7 @@
field public static final int isFeatureSplit = 16844123; // 0x101055b
field public static final int isGame = 16843764; // 0x10103f4
field public static final int isIndicator = 16843079; // 0x1010147
+ field public static final int isLightTheme = 16844175; // 0x101058f
field public static final int isModifier = 16843334; // 0x1010246
field public static final int isRepeatable = 16843336; // 0x1010248
field public static final int isScrollContainer = 16843342; // 0x101024e
@@ -45039,11 +45040,20 @@
ctor public TextAppearanceSpan(android.os.Parcel);
method public int describeContents();
method public java.lang.String getFamily();
+ method public java.lang.String getFontFeatureSettings();
+ method public java.lang.String getFontVariationSettings();
method public android.content.res.ColorStateList getLinkTextColor();
+ method public int getShadowColor();
+ method public float getShadowDx();
+ method public float getShadowDy();
+ method public float getShadowRadius();
method public int getSpanTypeId();
method public android.content.res.ColorStateList getTextColor();
+ method public int getTextFontWeight();
method public int getTextSize();
method public int getTextStyle();
+ method public android.graphics.Typeface getTypeface();
+ method public boolean isElegantTextHeight();
method public void updateDrawState(android.text.TextPaint);
method public void updateMeasureState(android.text.TextPaint);
method public void writeToParcel(android.os.Parcel, int);
@@ -55244,6 +55254,7 @@
public final class DelegateLastClassLoader extends dalvik.system.PathClassLoader {
ctor public DelegateLastClassLoader(java.lang.String, java.lang.ClassLoader);
ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader);
+ ctor public DelegateLastClassLoader(java.lang.String, java.lang.String, java.lang.ClassLoader, boolean);
}
public class DexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 1e9c354..10a00ee 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -200,9 +200,10 @@
message KeyValuePair {
optional int32 key = 1;
oneof value {
- int64 value_int = 2;
- string value_str = 3;
- float value_float = 4;
+ int32 value_int = 2;
+ int64 value_long = 3;
+ string value_str = 4;
+ float value_float = 5;
}
}
@@ -769,6 +770,9 @@
// Name of the wakeup alarm.
optional string tag = 2;
+
+ // Name of source package (for historical reasons, since BatteryStats tracked it).
+ optional string package_name = 3;
}
/**
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index f9f1b38..3afa08f 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -92,7 +92,8 @@
LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
int32_t uid,
- const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map) {
mLogdTimestampNs = wallClockTimestampNs;
@@ -113,7 +114,7 @@
pos[1]++;
}
- for (const auto&itr : string_map) {
+ for (const auto&itr : long_map) {
pos[2] = 1;
mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
pos[2] = 3;
@@ -122,7 +123,7 @@
pos[1]++;
}
- for (const auto&itr : float_map) {
+ for (const auto&itr : string_map) {
pos[2] = 1;
mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
pos[2] = 4;
@@ -130,6 +131,15 @@
mValues.back().mField.decorateLastPos(2);
pos[1]++;
}
+
+ for (const auto&itr : float_map) {
+ pos[2] = 1;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.first)));
+ pos[2] = 5;
+ mValues.push_back(FieldValue(Field(mTagId, pos, 2 /* depth */), Value(itr.second)));
+ mValues.back().mField.decorateLastPos(2);
+ pos[1]++;
+ }
if (!mValues.empty()) {
mValues.back().mField.decorateLastPos(1);
mValues.at(mValues.size() - 2).mField.decorateLastPos(1);
@@ -215,7 +225,8 @@
-bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
+bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map) {
if (mContext) {
@@ -233,6 +244,17 @@
}
}
+ for (const auto& itr : long_map) {
+ if (android_log_write_list_begin(mContext) < 0) {
+ return false;
+ }
+ write(itr.first);
+ write(itr.second);
+ if (android_log_write_list_end(mContext) < 0) {
+ return false;
+ }
+ }
+
for (const auto& itr : string_map) {
if (android_log_write_list_begin(mContext) < 0) {
return false;
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 9ef0bf4..0a8ac2b 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -77,7 +77,8 @@
*/
explicit LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs,
int32_t uid,
- const std::map<int32_t, int64_t>& int_map,
+ const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
@@ -122,7 +123,8 @@
bool write(float value);
bool write(const std::vector<AttributionNodeInternal>& nodes);
bool write(const AttributionNodeInternal& node);
- bool writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
+ bool writeKeyValuePairs(const std::map<int32_t, int32_t>& int_map,
+ const std::map<int32_t, int64_t>& long_map,
const std::map<int32_t, std::string>& string_map,
const std::map<int32_t, float>& float_map);
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 6e3b04c..d490701 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -91,12 +91,16 @@
TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
LogEvent event1(83, 2000);
- std::map<int32_t, int64_t> int_map;
+ std::map<int32_t, int32_t> int_map;
+ std::map<int32_t, int64_t> long_map;
std::map<int32_t, std::string> string_map;
std::map<int32_t, float> float_map;
- int_map[11] = 123L;
- int_map[22] = 345L;
+ int_map[11] = 123;
+ int_map[22] = 345;
+
+ long_map[33] = 678L;
+ long_map[44] = 890L;
string_map[1] = "test2";
string_map[2] = "test1";
@@ -104,12 +108,15 @@
float_map[111] = 2.2f;
float_map[222] = 1.1f;
- EXPECT_TRUE(event1.writeKeyValuePairs(int_map, string_map, float_map));
+ EXPECT_TRUE(event1.writeKeyValuePairs(int_map,
+ long_map,
+ string_map,
+ float_map));
event1.init();
EXPECT_EQ(83, event1.GetTagId());
const auto& items = event1.getValues();
- EXPECT_EQ((size_t)12, items.size());
+ EXPECT_EQ((size_t)16, items.size());
const FieldValue& item0 = event1.getValues()[0];
EXPECT_EQ(0x2010101, item0.mField.getField());
@@ -118,8 +125,8 @@
const FieldValue& item1 = event1.getValues()[1];
EXPECT_EQ(0x2010182, item1.mField.getField());
- EXPECT_EQ(Type::LONG, item1.mValue.getType());
- EXPECT_EQ(123L, item1.mValue.long_value);
+ EXPECT_EQ(Type::INT, item1.mValue.getType());
+ EXPECT_EQ(123, item1.mValue.int_value);
const FieldValue& item2 = event1.getValues()[2];
EXPECT_EQ(0x2010201, item2.mField.getField());
@@ -128,48 +135,68 @@
const FieldValue& item3 = event1.getValues()[3];
EXPECT_EQ(0x2010282, item3.mField.getField());
- EXPECT_EQ(Type::LONG, item3.mValue.getType());
- EXPECT_EQ(345L, item3.mValue.long_value);
+ EXPECT_EQ(Type::INT, item3.mValue.getType());
+ EXPECT_EQ(345, item3.mValue.int_value);
const FieldValue& item4 = event1.getValues()[4];
EXPECT_EQ(0x2010301, item4.mField.getField());
EXPECT_EQ(Type::INT, item4.mValue.getType());
- EXPECT_EQ(1, item4.mValue.int_value);
+ EXPECT_EQ(33, item4.mValue.int_value);
const FieldValue& item5 = event1.getValues()[5];
- EXPECT_EQ(0x2010383, item5.mField.getField());
- EXPECT_EQ(Type::STRING, item5.mValue.getType());
- EXPECT_EQ("test2", item5.mValue.str_value);
+ EXPECT_EQ(0x2010382, item5.mField.getField());
+ EXPECT_EQ(Type::LONG, item5.mValue.getType());
+ EXPECT_EQ(678L, item5.mValue.int_value);
const FieldValue& item6 = event1.getValues()[6];
EXPECT_EQ(0x2010401, item6.mField.getField());
EXPECT_EQ(Type::INT, item6.mValue.getType());
- EXPECT_EQ(2, item6.mValue.int_value);
+ EXPECT_EQ(44, item6.mValue.int_value);
const FieldValue& item7 = event1.getValues()[7];
- EXPECT_EQ(0x2010483, item7.mField.getField());
- EXPECT_EQ(Type::STRING, item7.mValue.getType());
- EXPECT_EQ("test1", item7.mValue.str_value);
+ EXPECT_EQ(0x2010482, item7.mField.getField());
+ EXPECT_EQ(Type::LONG, item7.mValue.getType());
+ EXPECT_EQ(890L, item7.mValue.int_value);
const FieldValue& item8 = event1.getValues()[8];
EXPECT_EQ(0x2010501, item8.mField.getField());
EXPECT_EQ(Type::INT, item8.mValue.getType());
- EXPECT_EQ(111, item8.mValue.int_value);
+ EXPECT_EQ(1, item8.mValue.int_value);
const FieldValue& item9 = event1.getValues()[9];
- EXPECT_EQ(0x2010584, item9.mField.getField());
- EXPECT_EQ(Type::FLOAT, item9.mValue.getType());
- EXPECT_EQ(2.2f, item9.mValue.float_value);
+ EXPECT_EQ(0x2010583, item9.mField.getField());
+ EXPECT_EQ(Type::STRING, item9.mValue.getType());
+ EXPECT_EQ("test2", item9.mValue.str_value);
const FieldValue& item10 = event1.getValues()[10];
- EXPECT_EQ(0x2018601, item10.mField.getField());
+ EXPECT_EQ(0x2010601, item10.mField.getField());
EXPECT_EQ(Type::INT, item10.mValue.getType());
- EXPECT_EQ(222, item10.mValue.int_value);
+ EXPECT_EQ(2, item10.mValue.int_value);
const FieldValue& item11 = event1.getValues()[11];
- EXPECT_EQ(0x2018684, item11.mField.getField());
- EXPECT_EQ(Type::FLOAT, item11.mValue.getType());
- EXPECT_EQ(1.1f, item11.mValue.float_value);
+ EXPECT_EQ(0x2010683, item11.mField.getField());
+ EXPECT_EQ(Type::STRING, item11.mValue.getType());
+ EXPECT_EQ("test1", item11.mValue.str_value);
+
+ const FieldValue& item12 = event1.getValues()[12];
+ EXPECT_EQ(0x2010701, item12.mField.getField());
+ EXPECT_EQ(Type::INT, item12.mValue.getType());
+ EXPECT_EQ(111, item12.mValue.int_value);
+
+ const FieldValue& item13 = event1.getValues()[13];
+ EXPECT_EQ(0x2010784, item13.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item13.mValue.getType());
+ EXPECT_EQ(2.2f, item13.mValue.float_value);
+
+ const FieldValue& item14 = event1.getValues()[14];
+ EXPECT_EQ(0x2018801, item14.mField.getField());
+ EXPECT_EQ(Type::INT, item14.mValue.getType());
+ EXPECT_EQ(222, item14.mValue.int_value);
+
+ const FieldValue& item15 = event1.getValues()[15];
+ EXPECT_EQ(0x2018884, item15.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item15.mValue.getType());
+ EXPECT_EQ(1.1f, item15.mValue.float_value);
}
TEST(LogEventTest, TestLogParsing2) {
@@ -242,12 +269,16 @@
}
TEST(LogEventTest, TestKeyValuePairsEvent) {
- std::map<int32_t, int64_t> int_map;
+ std::map<int32_t, int32_t> int_map;
+ std::map<int32_t, int64_t> long_map;
std::map<int32_t, std::string> string_map;
std::map<int32_t, float> float_map;
- int_map[11] = 123L;
- int_map[22] = 345L;
+ int_map[11] = 123;
+ int_map[22] = 345;
+
+ long_map[33] = 678L;
+ long_map[44] = 890L;
string_map[1] = "test2";
string_map[2] = "test1";
@@ -255,7 +286,7 @@
float_map[111] = 2.2f;
float_map[222] = 1.1f;
- LogEvent event1(83, 2000, 2001, 10001, int_map, string_map, float_map);
+ LogEvent event1(83, 2000, 2001, 10001, int_map, long_map, string_map, float_map);
event1.init();
EXPECT_EQ(83, event1.GetTagId());
@@ -263,7 +294,7 @@
EXPECT_EQ((int64_t)2001, event1.GetElapsedTimestampNs());
const auto& items = event1.getValues();
- EXPECT_EQ((size_t)13, items.size());
+ EXPECT_EQ((size_t)17, items.size());
const FieldValue& item0 = event1.getValues()[0];
EXPECT_EQ(0x00010000, item0.mField.getField());
@@ -277,8 +308,8 @@
const FieldValue& item2 = event1.getValues()[2];
EXPECT_EQ(0x2020182, item2.mField.getField());
- EXPECT_EQ(Type::LONG, item2.mValue.getType());
- EXPECT_EQ(123L, item2.mValue.long_value);
+ EXPECT_EQ(Type::INT, item2.mValue.getType());
+ EXPECT_EQ(123, item2.mValue.int_value);
const FieldValue& item3 = event1.getValues()[3];
EXPECT_EQ(0x2020201, item3.mField.getField());
@@ -287,48 +318,68 @@
const FieldValue& item4 = event1.getValues()[4];
EXPECT_EQ(0x2020282, item4.mField.getField());
- EXPECT_EQ(Type::LONG, item4.mValue.getType());
- EXPECT_EQ(345L, item4.mValue.long_value);
+ EXPECT_EQ(Type::INT, item4.mValue.getType());
+ EXPECT_EQ(345, item4.mValue.int_value);
const FieldValue& item5 = event1.getValues()[5];
EXPECT_EQ(0x2020301, item5.mField.getField());
EXPECT_EQ(Type::INT, item5.mValue.getType());
- EXPECT_EQ(1, item5.mValue.int_value);
+ EXPECT_EQ(33, item5.mValue.int_value);
const FieldValue& item6 = event1.getValues()[6];
- EXPECT_EQ(0x2020383, item6.mField.getField());
- EXPECT_EQ(Type::STRING, item6.mValue.getType());
- EXPECT_EQ("test2", item6.mValue.str_value);
+ EXPECT_EQ(0x2020382, item6.mField.getField());
+ EXPECT_EQ(Type::LONG, item6.mValue.getType());
+ EXPECT_EQ(678L, item6.mValue.long_value);
const FieldValue& item7 = event1.getValues()[7];
EXPECT_EQ(0x2020401, item7.mField.getField());
EXPECT_EQ(Type::INT, item7.mValue.getType());
- EXPECT_EQ(2, item7.mValue.int_value);
+ EXPECT_EQ(44, item7.mValue.int_value);
const FieldValue& item8 = event1.getValues()[8];
- EXPECT_EQ(0x2020483, item8.mField.getField());
- EXPECT_EQ(Type::STRING, item8.mValue.getType());
- EXPECT_EQ("test1", item8.mValue.str_value);
+ EXPECT_EQ(0x2020482, item8.mField.getField());
+ EXPECT_EQ(Type::LONG, item8.mValue.getType());
+ EXPECT_EQ(890L, item8.mValue.long_value);
const FieldValue& item9 = event1.getValues()[9];
EXPECT_EQ(0x2020501, item9.mField.getField());
EXPECT_EQ(Type::INT, item9.mValue.getType());
- EXPECT_EQ(111, item9.mValue.int_value);
+ EXPECT_EQ(1, item9.mValue.int_value);
const FieldValue& item10 = event1.getValues()[10];
- EXPECT_EQ(0x2020584, item10.mField.getField());
- EXPECT_EQ(Type::FLOAT, item10.mValue.getType());
- EXPECT_EQ(2.2f, item10.mValue.float_value);
+ EXPECT_EQ(0x2020583, item10.mField.getField());
+ EXPECT_EQ(Type::STRING, item10.mValue.getType());
+ EXPECT_EQ("test2", item10.mValue.str_value);
const FieldValue& item11 = event1.getValues()[11];
- EXPECT_EQ(0x2028601, item11.mField.getField());
+ EXPECT_EQ(0x2020601, item11.mField.getField());
EXPECT_EQ(Type::INT, item11.mValue.getType());
- EXPECT_EQ(222, item11.mValue.int_value);
+ EXPECT_EQ(2, item11.mValue.int_value);
const FieldValue& item12 = event1.getValues()[12];
- EXPECT_EQ(0x2028684, item12.mField.getField());
- EXPECT_EQ(Type::FLOAT, item12.mValue.getType());
- EXPECT_EQ(1.1f, item12.mValue.float_value);
+ EXPECT_EQ(0x2020683, item12.mField.getField());
+ EXPECT_EQ(Type::STRING, item12.mValue.getType());
+ EXPECT_EQ("test1", item12.mValue.str_value);
+
+ const FieldValue& item13 = event1.getValues()[13];
+ EXPECT_EQ(0x2020701, item13.mField.getField());
+ EXPECT_EQ(Type::INT, item13.mValue.getType());
+ EXPECT_EQ(111, item13.mValue.int_value);
+
+ const FieldValue& item14 = event1.getValues()[14];
+ EXPECT_EQ(0x2020784, item14.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item14.mValue.getType());
+ EXPECT_EQ(2.2f, item14.mValue.float_value);
+
+ const FieldValue& item15 = event1.getValues()[15];
+ EXPECT_EQ(0x2028801, item15.mField.getField());
+ EXPECT_EQ(Type::INT, item15.mValue.getType());
+ EXPECT_EQ(222, item15.mValue.int_value);
+
+ const FieldValue& item16 = event1.getValues()[16];
+ EXPECT_EQ(0x2028884, item16.mField.getField());
+ EXPECT_EQ(Type::FLOAT, item16.mValue.getType());
+ EXPECT_EQ(1.1f, item16.mValue.float_value);
}
@@ -337,4 +388,4 @@
} // namespace android
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
\ No newline at end of file
+#endif
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3638bc4..81df447 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4440,7 +4440,7 @@
}
private CharSequence processTextSpans(CharSequence text) {
- if (hasForegroundColor()) {
+ if (hasForegroundColor() || mInNightMode) {
return ContrastColorUtil.clearColorSpans(text);
}
return text;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 01557c5..eb5c720 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -649,7 +649,7 @@
* successful so far. Do not call setTransactionSuccessful before calling this. When this
* returns a new transaction will have been created but not marked as successful.
* @return true if the transaction was yielded
- * @deprecated if the db is locked more than once (becuase of nested transactions) then the lock
+ * @deprecated if the db is locked more than once (because of nested transactions) then the lock
* will not be yielded. Use yieldIfContendedSafely instead.
*/
@Deprecated
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 92a814c..83998cc 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -348,7 +348,6 @@
* @hide
*/
public AuthenticationResult(CryptoObject crypto) {
- // For compatibility, this extends from common base class as FingerprintManager does.
// Identifier and userId is not used for BiometricPrompt.
super(crypto, null /* identifier */, 0 /* userId */);
}
@@ -410,8 +409,8 @@
}
/**
- * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts
- * scanning for a fingerprint. It terminates when {@link
+ * This call warms up the biometric hardware, displays a system-provided dialog, and starts
+ * scanning for a biometric. It terminates when {@link
* AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link
* AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)}, or when the user
* dismisses the system-provided dialog, at which point the crypto object becomes invalid. This
@@ -453,8 +452,8 @@
}
/**
- * This call warms up the fingerprint hardware, displays a system-provided dialog, and starts
- * scanning for a fingerprint. It terminates when {@link
+ * This call warms up the biometric hardware, displays a system-provided dialog, and starts
+ * scanning for a biometric. It terminates when {@link
* AuthenticationCallback#onAuthenticationError(int, CharSequence)} is called, when {@link
* AuthenticationCallback#onAuthenticationSucceeded( AuthenticationResult)} is called, or when
* the user dismisses the system-provided dialog. This operation can be canceled by using the
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 66613ea..873a24a 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -244,17 +244,17 @@
}
/**
- * Requests a pre-enrollment auth token to tie enrollment to the confirmation of
+ * Requests an auth token to tie sensitive operations to the confirmation of
* existing device credentials (e.g. pin/pattern/password).
*
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public long preEnroll() {
+ public long generateChallenge() {
long result = 0;
if (mService != null) {
try {
- result = mService.preEnroll(mToken);
+ result = mService.generateChallenge(mToken);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -263,16 +263,46 @@
}
/**
- * Finishes enrollment and cancels the current auth token.
+ * Invalidates the current auth token.
*
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public int postEnroll() {
+ public int revokeChallenge() {
int result = 0;
if (mService != null) {
try {
- result = mService.postEnroll(mToken);
+ result = mService.revokeChallenge(mToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(MANAGE_BIOMETRIC)
+ public void setRequireAttention(boolean requireAttention, byte[] token) {
+ if (mService != null) {
+ try {
+ mService.setRequireAttention(requireAttention, token);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(MANAGE_BIOMETRIC)
+ public boolean getRequireAttention(byte[] token) {
+ boolean result = true;
+ if (mService != null) {
+ try {
+ mService.getRequireAttention(token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 50d0744..6681bd7 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -66,10 +66,10 @@
boolean isHardwareDetected(long deviceId, String opPackageName);
// Get a pre-enrollment authentication token
- long preEnroll(IBinder token);
+ long generateChallenge(IBinder token);
// Finish an enrollment sequence and invalidate the authentication token
- int postEnroll(IBinder token);
+ int revokeChallenge(IBinder token);
// Determine if a user has at least one enrolled face
boolean hasEnrolledFaces(int userId, String opPackageName);
@@ -94,4 +94,8 @@
// Enumerate all faces
void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver);
+
+ int setRequireAttention(boolean requireAttention, in byte [] token);
+
+ boolean getRequireAttention(in byte [] token);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index aa178fb..8fd9d4f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7689,6 +7689,15 @@
BOOLEAN_VALIDATOR;
/**
+ * Whether or not face unlock is allowed for apps (through BiometricPrompt).
+ * @hide
+ */
+ public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled";
+
+ private static final Validator FACE_UNLOCK_APP_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
@@ -8189,6 +8198,7 @@
NFC_PAYMENT_DEFAULT_COMPONENT,
AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
FACE_UNLOCK_KEYGUARD_ENABLED,
+ FACE_UNLOCK_APP_ENABLED,
ASSIST_GESTURE_ENABLED,
ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
ASSIST_GESTURE_WAKE_ENABLED,
@@ -8337,6 +8347,7 @@
VALIDATORS.put(AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_VALIDATOR);
VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR);
+ VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_ENABLED, ASSIST_GESTURE_ENABLED_VALIDATOR);
VALIDATORS.put(ASSIST_GESTURE_SILENCE_ALERTS_ENABLED,
ASSIST_GESTURE_SILENCE_ALERTS_ENABLED_VALIDATOR);
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index c5fabaf..0d29da0 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1610,13 +1610,14 @@
public boolean equals(Object o) {
if (o instanceof Spanned &&
toString().equals(o.toString())) {
- Spanned other = (Spanned) o;
+ final Spanned other = (Spanned) o;
// Check span data
- Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] thisSpans = getSpans(0, length(), Object.class);
if (mSpanCount == otherSpans.length) {
for (int i = 0; i < mSpanCount; ++i) {
- Object thisSpan = mSpans[i];
- Object otherSpan = otherSpans[i];
+ final Object thisSpan = thisSpans[i];
+ final Object otherSpan = otherSpans[i];
if (thisSpan == this) {
if (other != otherSpan ||
getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
diff --git a/core/java/android/text/SpannableStringInternal.java b/core/java/android/text/SpannableStringInternal.java
index 7acd539..a986633 100644
--- a/core/java/android/text/SpannableStringInternal.java
+++ b/core/java/android/text/SpannableStringInternal.java
@@ -16,12 +16,13 @@
package android.text;
+import android.annotation.UnsupportedAppUsage;
+
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import libcore.util.EmptyArray;
-import android.annotation.UnsupportedAppUsage;
import java.lang.reflect.Array;
/* package */ abstract class SpannableStringInternal
@@ -502,13 +503,14 @@
public boolean equals(Object o) {
if (o instanceof Spanned &&
toString().equals(o.toString())) {
- Spanned other = (Spanned) o;
+ final Spanned other = (Spanned) o;
// Check span data
- Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
+ final Object[] thisSpans = getSpans(0, length(), Object.class);
if (mSpanCount == otherSpans.length) {
for (int i = 0; i < mSpanCount; ++i) {
- Object thisSpan = mSpans[i];
- Object otherSpan = otherSpans[i];
+ final Object thisSpan = thisSpans[i];
+ final Object otherSpan = otherSpans[i];
if (thisSpan == this) {
if (other != otherSpan ||
getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index c17cfd5..2dc4f60 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -16,11 +16,13 @@
package android.text.style;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.LeakyTypefaceStorage;
import android.graphics.Typeface;
+import android.graphics.fonts.Font;
import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
@@ -38,6 +40,21 @@
private final ColorStateList mTextColorLink;
private final Typeface mTypeface;
+ private final int mTextFontWeight;
+
+ private final float mShadowRadius;
+ private final float mShadowDx;
+ private final float mShadowDy;
+ private final int mShadowColor;
+
+ private final boolean mHasElegantTextHeight;
+ private final boolean mElegantTextHeight;
+ private final boolean mHasLetterSpacing;
+ private final float mLetterSpacing;
+
+ private final String mFontFeatureSettings;
+ private final String mFontVariationSettings;
+
/**
* Uses the specified TextAppearance resource to determine the
* text appearance. The <code>appearance</code> should be, for example,
@@ -104,6 +121,34 @@
}
}
+ mTextFontWeight = a.getInt(com.android.internal.R.styleable
+ .TextAppearance_textFontWeight, -1);
+
+ mShadowRadius = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_shadowRadius, 0.0f);
+ mShadowDx = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_shadowDx, 0.0f);
+ mShadowDy = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_shadowDy, 0.0f);
+ mShadowColor = a.getInt(com.android.internal.R.styleable
+ .TextAppearance_shadowColor, 0);
+
+ mHasElegantTextHeight = a.hasValue(com.android.internal.R.styleable
+ .TextAppearance_elegantTextHeight);
+ mElegantTextHeight = a.getBoolean(com.android.internal.R.styleable
+ .TextAppearance_elegantTextHeight, false);
+
+ mHasLetterSpacing = a.hasValue(com.android.internal.R.styleable
+ .TextAppearance_letterSpacing);
+ mLetterSpacing = a.getFloat(com.android.internal.R.styleable
+ .TextAppearance_letterSpacing, 0.0f);
+
+ mFontFeatureSettings = a.getString(com.android.internal.R.styleable
+ .TextAppearance_fontFeatureSettings);
+
+ mFontVariationSettings = a.getString(com.android.internal.R.styleable
+ .TextAppearance_fontVariationSettings);
+
a.recycle();
if (colorList >= 0) {
@@ -129,6 +174,21 @@
mTextColor = color;
mTextColorLink = linkColor;
mTypeface = null;
+
+ mTextFontWeight = -1;
+
+ mShadowRadius = 0.0f;
+ mShadowDx = 0.0f;
+ mShadowDy = 0.0f;
+ mShadowColor = 0;
+
+ mHasElegantTextHeight = false;
+ mElegantTextHeight = false;
+ mHasLetterSpacing = false;
+ mLetterSpacing = 0.0f;
+
+ mFontFeatureSettings = null;
+ mFontVariationSettings = null;
}
public TextAppearanceSpan(Parcel src) {
@@ -146,6 +206,21 @@
mTextColorLink = null;
}
mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
+
+ mTextFontWeight = src.readInt();
+
+ mShadowRadius = src.readFloat();
+ mShadowDx = src.readFloat();
+ mShadowDy = src.readFloat();
+ mShadowColor = src.readInt();
+
+ mHasElegantTextHeight = src.readBoolean();
+ mElegantTextHeight = src.readBoolean();
+ mHasLetterSpacing = src.readBoolean();
+ mLetterSpacing = src.readFloat();
+
+ mFontFeatureSettings = src.readString();
+ mFontVariationSettings = src.readString();
}
public int getSpanTypeId() {
@@ -183,6 +258,21 @@
dest.writeInt(0);
}
LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
+
+ dest.writeInt(mTextFontWeight);
+
+ dest.writeFloat(mShadowRadius);
+ dest.writeFloat(mShadowDx);
+ dest.writeFloat(mShadowDy);
+ dest.writeInt(mShadowColor);
+
+ dest.writeBoolean(mHasElegantTextHeight);
+ dest.writeBoolean(mElegantTextHeight);
+ dest.writeBoolean(mHasLetterSpacing);
+ dest.writeFloat(mLetterSpacing);
+
+ dest.writeString(mFontFeatureSettings);
+ dest.writeString(mFontVariationSettings);
}
/**
@@ -225,6 +315,81 @@
return mStyle;
}
+ /**
+ * Returns the text font weight specified by this span, or <code>-1</code>
+ * if it does not specify one.
+ */
+ public int getTextFontWeight() {
+ return mTextFontWeight;
+ }
+
+ /**
+ * Returns the typeface specified by this span, or <code>null</code>
+ * if it does not specify one.
+ */
+ @Nullable
+ public Typeface getTypeface() {
+ return mTypeface;
+ }
+
+ /**
+ * Returns the color of the text shadow specified by this span, or <code>0</code>
+ * if it does not specify one.
+ */
+ public int getShadowColor() {
+ return mShadowColor;
+ }
+
+ /**
+ * Returns the horizontal offset of the text shadow specified by this span, or <code>0.0f</code>
+ * if it does not specify one.
+ */
+ public float getShadowDx() {
+ return mShadowDx;
+ }
+
+ /**
+ * Returns the vertical offset of the text shadow specified by this span, or <code>0.0f</code>
+ * if it does not specify one.
+ */
+ public float getShadowDy() {
+ return mShadowDy;
+ }
+
+ /**
+ * Returns the blur radius of the text shadow specified by this span, or <code>0.0f</code>
+ * if it does not specify one.
+ */
+ public float getShadowRadius() {
+ return mShadowRadius;
+ }
+
+ /**
+ * Returns the font feature settings specified by this span, or <code>null</code>
+ * if it does not specify one.
+ */
+ @Nullable
+ public String getFontFeatureSettings() {
+ return mFontFeatureSettings;
+ }
+
+ /**
+ * Returns the font variation settings specified by this span, or <code>null</code>
+ * if it does not specify one.
+ */
+ @Nullable
+ public String getFontVariationSettings() {
+ return mFontVariationSettings;
+ }
+
+ /**
+ * Returns the value of elegant height metrics flag specified by this span,
+ * or <code>false</code> if it does not specify one.
+ */
+ public boolean isElegantTextHeight() {
+ return mElegantTextHeight;
+ }
+
@Override
public void updateDrawState(TextPaint ds) {
updateMeasureState(ds);
@@ -236,6 +401,10 @@
if (mTextColorLink != null) {
ds.linkColor = mTextColorLink.getColorForState(ds.drawableState, 0);
}
+
+ if (mShadowColor != 0) {
+ ds.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
+ }
}
@Override
@@ -267,7 +436,16 @@
}
if (styledTypeface != null) {
- int fake = style & ~styledTypeface.getStyle();
+ final Typeface readyTypeface;
+ if (mTextFontWeight >= 0) {
+ final int weight = Math.min(Font.FONT_WEIGHT_MAX, mTextFontWeight);
+ final boolean italic = (style & Typeface.ITALIC) != 0;
+ readyTypeface = ds.setTypeface(Typeface.create(styledTypeface, weight, italic));
+ } else {
+ readyTypeface = styledTypeface;
+ }
+
+ int fake = style & ~readyTypeface.getStyle();
if ((fake & Typeface.BOLD) != 0) {
ds.setFakeBoldText(true);
@@ -277,11 +455,27 @@
ds.setTextSkewX(-0.25f);
}
- ds.setTypeface(styledTypeface);
+ ds.setTypeface(readyTypeface);
}
if (mTextSize > 0) {
ds.setTextSize(mTextSize);
}
+
+ if (mHasElegantTextHeight) {
+ ds.setElegantTextHeight(mElegantTextHeight);
+ }
+
+ if (mHasLetterSpacing) {
+ ds.setLetterSpacing(mLetterSpacing);
+ }
+
+ if (mFontFeatureSettings != null) {
+ ds.setFontFeatureSettings(mFontFeatureSettings);
+ }
+
+ if (mFontVariationSettings != null) {
+ ds.setFontVariationSettings(mFontVariationSettings);
+ }
}
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 0986b89..42690ce 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -974,6 +974,25 @@
}
}
+ /** The root of everything */
+ public @NonNull RenderNode getRootNode() {
+ return mRootNode;
+ }
+
+ private boolean mForceDark = false;
+
+ /**
+ * Whether or not the force-dark feature should be used for this renderer.
+ */
+ public boolean setForceDark(boolean enable) {
+ if (mForceDark != enable) {
+ mForceDark = enable;
+ nSetForceDark(mNativeProxy, enable);
+ return true;
+ }
+ return false;
+ }
+
/**
* Basic synchronous renderer. Currently only used to render the Magnifier, so use with care.
* TODO: deduplicate against ThreadedRenderer.
@@ -1253,4 +1272,5 @@
private static native void nSetIsolatedProcess(boolean enabled);
private static native void nSetContextPriority(int priority);
private static native void nAllocateBuffers(long nativeProxy, Surface window);
+ private static native void nSetForceDark(long nativeProxy, boolean enabled);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1eb35c5..78e6dd8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15255,6 +15255,10 @@
* a value of 'true' will not override any 'false' value in its parent chain nor will
* it prevent any 'false' in any of its children.
*
+ * The default behavior of force dark is also influenced by the Theme's
+ * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute.
+ * If a theme is isLightTheme="false", then force dark is globally disabled for that theme.
+ *
* @param allow Whether or not to allow force dark.
*
* @hide
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5bc44ce..bef8e8f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -43,6 +43,7 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -1077,6 +1078,7 @@
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
+ updateForceDarkMode();
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;
@@ -1085,6 +1087,27 @@
}
}
+ private int getNightMode() {
+ return mContext.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ }
+
+ private void updateForceDarkMode() {
+ if (mAttachInfo.mThreadedRenderer == null) return;
+
+ boolean nightMode = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
+ TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
+ boolean isLightTheme = a.getBoolean(R.styleable.Theme_isLightTheme, false);
+ a.recycle();
+
+ boolean changed = mAttachInfo.mThreadedRenderer.setForceDark(nightMode);
+ changed |= mAttachInfo.mThreadedRenderer.getRootNode().setAllowForceDark(isLightTheme);
+
+ if (changed) {
+ // TODO: Don't require regenerating all display lists to apply this setting
+ invalidateWorld(mView);
+ }
+ }
+
@UnsupportedAppUsage
public View getView() {
return mView;
@@ -4077,6 +4100,8 @@
mForceNextWindowRelayout = true;
requestLayout();
}
+
+ updateForceDarkMode();
}
/**
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 3c59bd1..7a5b604 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1064,6 +1064,12 @@
proxy->allocateBuffers(surface);
}
+static void android_view_ThreadedRenderer_setForceDark(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jboolean enable) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ proxy->setForceDark(enable);
+}
+
// ----------------------------------------------------------------------------
// FrameMetricsObserver
// ----------------------------------------------------------------------------
@@ -1177,6 +1183,7 @@
{ "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
{ "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
{ "nAllocateBuffers", "(JLandroid/view/Surface;)V", (void*)android_view_ThreadedRenderer_allocateBuffers },
+ { "nSetForceDark", "(JZ)V", (void*)android_view_ThreadedRenderer_setForceDark },
};
static JavaVM* mJvm = nullptr;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ade0b11..85a52d5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4463,14 +4463,6 @@
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
- <service android:name="com.android.internal.backup.LocalTransportService"
- android:permission="android.permission.CONFIRM_FULL_BACKUP"
- android:exported="false">
- <intent-filter>
- <action android:name="android.backup.TRANSPORT_HOST" />
- </intent-filter>
- </service>
-
<service android:name="com.android.server.MountServiceIdler"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cc99a4e..cdaff18 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2912,6 +2912,7 @@
<!-- @hide For use by platform and tools only. Developers should not specify this value. -->
<public name="usesNonSdkApi" />
<public name="minimumUiTimeout" />
+ <public name="isLightTheme" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index 8909293..b0d29bd 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -73,7 +73,7 @@
@Test
public void testComponentNameValidator() {
assertTrue(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate(
- "android/com.android.internal.backup.LocalTransport"));
+ "com.android.localtransport/.LocalTransport"));
assertFalse(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate("rectangle"));
}
@@ -90,7 +90,7 @@
@Test
public void testNullableComponentNameValidator_onValidComponentName_returnsTrue() {
assertTrue(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(
- "android/com.android.internal.backup.LocalTransport"));
+ "com.android.localtransport/.LocalTransport"));
}
@Test
@@ -185,7 +185,7 @@
@Test
public void testComponentNameListValidator() {
Validator v = new SettingsValidators.ComponentNameListValidator(",");
- assertTrue(v.validate("android/com.android.internal.backup.LocalTransport,"
+ assertTrue(v.validate("com.android.localtransport/.LocalTransport,"
+ "com.google.android.gms/.backup.migrate.service.D2dTransport"));
assertFalse(v.validate("com.google.5android,android"));
}
@@ -200,7 +200,7 @@
@Test
public void testPackageNameListValidator() {
Validator v = new SettingsValidators.PackageNameListValidator(",");
- assertTrue(v.validate("com.android.internal.backup.LocalTransport,com.google.android.gms"));
+ assertTrue(v.validate("com.android.localtransport.LocalTransport,com.google.android.gms"));
assertFalse(v.validate("5com.android.internal.backup.LocalTransport,android"));
}
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
index ae6a7f6..b0d2de1 100644
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -28,7 +28,7 @@
<!-- Whitelist of what components are permitted as backup data transports. The
'service' attribute here is a flattened ComponentName string. -->
<backup-transport-whitelisted-service
- service="android/com.android.internal.backup.LocalTransportService" />
+ service="com.android.localtransport/.LocalTransportService" />
<!-- Whitelist of bundled applications which all handle URLs to their websites by default -->
<app-link package="com.android.carrierdefaultapp" />
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 492c236..e6ac060 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -34,7 +34,6 @@
import android.provider.FontRequest;
import android.provider.FontsContract;
import android.text.FontConfig;
-import android.util.ArrayMap;
import android.util.Base64;
import android.util.LongSparseArray;
import android.util.LruCache;
@@ -1112,13 +1111,6 @@
}
}
- // Following methods are left for layoutlib
- // TODO: Remove once layoutlib stop calling buildSystemFallback
- /** @hide */
- public static void buildSystemFallback(String xmlPath, String fontDir,
- ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) {
- }
-
static {
final HashMap<String, Typeface> systemFontMap = new HashMap<>();
initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 11dad2e..494e513 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -229,6 +229,7 @@
"ResourceCache.cpp",
"SkiaCanvas.cpp",
"Snapshot.cpp",
+ "TreeInfo.cpp",
"VectorDrawable.cpp",
"protos/graphicsstats.proto",
],
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 17bec19..a699e2f 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -61,6 +61,7 @@
bool Properties::disableVsync = false;
bool Properties::skpCaptureEnabled = false;
bool Properties::forceDarkMode = false;
+bool Properties::enableForceDarkSupport = false;
bool Properties::enableRTAnimations = true;
bool Properties::runningInEmulator = false;
@@ -149,6 +150,9 @@
forceDarkMode = property_get_bool(PROPERTY_FORCE_DARK, false);
+ // TODO: make this on by default
+ enableForceDarkSupport = property_get_bool(PROPERTY_ENABLE_FORCE_DARK, false);
+
return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
(prevDebugStencilClip != debugStencilClip);
}
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index ea017a7..542bc71 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -192,6 +192,8 @@
#define PROPERTY_FORCE_DARK "debug.hwui.force_dark"
+#define PROPERTY_ENABLE_FORCE_DARK "debug.hwui.force_dark_enabled"
+
///////////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////////
@@ -266,6 +268,7 @@
static bool skpCaptureEnabled;
static bool forceDarkMode;
+ static bool enableForceDarkSupport;
// For experimentation b/68769804
ANDROID_API static bool enableRTAnimations;
diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp
new file mode 100644
index 0000000..808a12a
--- /dev/null
+++ b/libs/hwui/TreeInfo.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TreeInfo.h"
+
+#include "renderthread/CanvasContext.h"
+
+namespace android::uirenderer {
+
+TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
+ : mode(mode)
+ , prepareTextures(mode == MODE_FULL)
+ , canvasContext(canvasContext)
+ , disableForceDark(canvasContext.useForceDark() ? 0 : 1) {}
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index caa5762..a0d9605 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -16,8 +16,8 @@
#pragma once
-#include "utils/Macros.h"
#include "Properties.h"
+#include "utils/Macros.h"
#include <utils/Timers.h>
@@ -40,7 +40,7 @@
virtual void onError(const std::string& message) = 0;
protected:
- virtual ~ErrorHandler() {}
+ virtual ~ErrorHandler() = default;
};
class TreeObserver {
@@ -52,7 +52,7 @@
virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;
protected:
- virtual ~TreeObserver() {}
+ virtual ~TreeObserver() = default;
};
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
@@ -71,8 +71,7 @@
MODE_RT_ONLY,
};
- TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
- : mode(mode), prepareTextures(mode == MODE_FULL), canvasContext(canvasContext) {}
+ TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext);
TraversalMode mode;
// TODO: Remove this? Currently this is used to signal to stop preparing
@@ -94,7 +93,7 @@
bool updateWindowPositions = false;
- int disableForceDark = Properties::forceDarkMode ? 0 : 1;
+ int disableForceDark;
struct Out {
bool hasFunctors = false;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2315cb9..2307ee4 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -182,6 +182,23 @@
mFrameCompleteCallbacks.push_back(std::move(func));
}
+ void setForceDark(bool enable) {
+ mUseForceDark = enable;
+ }
+
+ bool useForceDark() {
+ // The force-dark override has the highest priority, followed by the disable setting
+ // for the feature as a whole, followed last by whether or not this context has had
+ // force dark set (typically automatically done via UIMode)
+ if (Properties::forceDarkMode) {
+ return true;
+ }
+ if (!Properties::enableForceDarkSupport) {
+ return false;
+ }
+ return mUseForceDark;
+ }
+
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
@@ -228,6 +245,7 @@
bool mOpaque;
bool mWideColorGamut = false;
+ bool mUseForceDark = false;
LightInfo mLightInfo;
LightGeometry mLightGeometry = {{0, 0, 0}, 0};
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 6106e24..54219b5 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -298,6 +298,12 @@
});
}
+void RenderProxy::setForceDark(bool enable) {
+ mRenderThread.queue().post([this, enable]() {
+ mContext->setForceDark(enable);
+ });
+}
+
int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
SkBitmap* bitmap) {
auto& thread = RenderThread::getInstance();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d22f56e..d29fcc4 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -119,7 +119,7 @@
ANDROID_API void addFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
- ANDROID_API long getDroppedFrameReportCount();
+ ANDROID_API void setForceDark(bool enable);
ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
int bottom, SkBitmap* bitmap);
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 7b7b800..84d246f 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -271,7 +271,10 @@
addTask(new Task(CALL_COMPLETED_SKIP_TO_NEXT, false) {
@Override
void process() {
- // TODO: switch to next data source and play
+ if (getState() == PLAYER_STATE_PLAYING) {
+ pause();
+ }
+ playNextDataSource();
}
});
}
diff --git a/packages/LocalTransport/Android.mk b/packages/LocalTransport/Android.mk
new file mode 100644
index 0000000..3484b0f
--- /dev/null
+++ b/packages/LocalTransport/Android.mk
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := LocalTransport
+LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/LocalTransport/AndroidManifest.xml b/packages/LocalTransport/AndroidManifest.xml
new file mode 100644
index 0000000..196be1e
--- /dev/null
+++ b/packages/LocalTransport/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2018 Google Inc.
+ *
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.localtransport"
+ android:sharedUserId="android.uid.system" >
+
+
+ <application android:allowBackup="false" >
+ <!-- This service does not need to be exported because it shares uid with the system server
+ which is the only client. -->
+ <service android:name=".LocalTransportService"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.backup.TRANSPORT_HOST" />
+ </intent-filter>
+ </service>
+
+ </application>
+</manifest>
diff --git a/packages/LocalTransport/proguard.flags b/packages/LocalTransport/proguard.flags
new file mode 100644
index 0000000..c1f51b8
--- /dev/null
+++ b/packages/LocalTransport/proguard.flags
@@ -0,0 +1,5 @@
+-keep class com.android.localTransport.LocalTransport
+-keep class com.android.localTransport.LocalTransportParameters
+-keep class com.android.localTransport.LocalTransportService
+
+
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
similarity index 97%
rename from core/java/com/android/internal/backup/LocalTransport.java
rename to packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index d0f0272..0bf8bc1 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.backup;
+package com.android.localtransport;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -26,7 +26,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
-import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
@@ -56,7 +55,7 @@
private static final boolean DEBUG = false;
private static final String TRANSPORT_DIR_NAME
- = "com.android.internal.backup.LocalTransport";
+ = "com.android.localtransport.LocalTransport";
private static final String TRANSPORT_DESTINATION_STRING
= "Backing up to debug-only private cache";
@@ -75,10 +74,10 @@
private static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;
private Context mContext;
- private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
- private File mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
- private File mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR);
- private File mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR);
+ private File mDataDir;
+ private File mCurrentSetDir;
+ private File mCurrentSetIncrementalDir;
+ private File mCurrentSetFullDir;
private PackageInfo[] mRestorePackages = null;
private int mRestorePackage = -1; // Index into mRestorePackages
@@ -101,6 +100,11 @@
private final LocalTransportParameters mParameters;
private void makeDataDirs() {
+ mDataDir = mContext.getFilesDir();
+ mCurrentSetDir = new File(mDataDir, Long.toString(CURRENT_SET_TOKEN));
+ mCurrentSetIncrementalDir = new File(mCurrentSetDir, INCREMENTAL_DIR);
+ mCurrentSetFullDir = new File(mCurrentSetDir, FULL_DATA_DIR);
+
mCurrentSetDir.mkdirs();
mCurrentSetFullDir.mkdir();
mCurrentSetIncrementalDir.mkdir();
diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
similarity index 97%
rename from core/java/com/android/internal/backup/LocalTransportParameters.java
rename to packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 2427d39..784be22 100644
--- a/core/java/com/android/internal/backup/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.internal.backup;
+package com.android.localtransport;
import android.util.KeyValueSettingObserver;
import android.content.ContentResolver;
diff --git a/core/java/com/android/internal/backup/LocalTransportService.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
similarity index 96%
rename from core/java/com/android/internal/backup/LocalTransportService.java
rename to packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
index 69c48e2..ac4f418 100644
--- a/core/java/com/android/internal/backup/LocalTransportService.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.backup;
+package com.android.localtransport;
import android.app.Service;
import android.content.Intent;
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 3859092..bd9a6ec 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -446,7 +446,6 @@
<string name="alarm_template_far" msgid="3779172822607461675">"अलार्म <xliff:g id="WHEN">%1$s</xliff:g> को बजेगा"</string>
<string name="zen_mode_duration_settings_title" msgid="229547412251222757">"अवधि"</string>
<string name="zen_mode_duration_always_prompt_title" msgid="6478923750878945501">"हर बार पूछें"</string>
- <!-- no translation found for zen_mode_forever (2704305038191592967) -->
- <skip />
+ <string name="zen_mode_forever" msgid="2704305038191592967">"जब तक आप इसे बंद नहीं करते"</string>
<string name="time_unit_just_now" msgid="6363336622778342422">"अभी-अभी"</string>
</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index c53417b..de86789 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -55,7 +55,7 @@
<bool name="def_networks_available_notification_on">true</bool>
<bool name="def_backup_enabled">false</bool>
- <string name="def_backup_transport" translatable="false">android/com.android.internal.backup.LocalTransport</string>
+ <string name="def_backup_transport" translatable="false">com.android.localtransport/.LocalTransport</string>
<!-- Default value for whether or not to pulse the notification LED when there is a
pending notification -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 63978ba..3d193db 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3285,8 +3285,8 @@
if (currentVersion == 133) {
// Version 133: Add default end button behavior
final SettingsState systemSettings = getSystemSettingsLocked(userId);
- if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR) ==
- null) {
+ if (systemSettings.getSettingLocked(Settings.System.END_BUTTON_BEHAVIOR)
+ .isNull()) {
String defaultEndButtonBehavior = Integer.toString(getContext()
.getResources().getInteger(R.integer.def_end_button_behavior));
systemSettings.insertSettingLocked(Settings.System.END_BUTTON_BEHAVIOR,
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index a3b5395..0215fda 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -61,13 +61,14 @@
public static final float SWIPED_FAR_ENOUGH_SIZE_FRACTION = 0.6f;
static final float MAX_SCROLL_SIZE_FRACTION = 0.3f;
+ protected final Handler mHandler;
+
private float mMinSwipeProgress = 0f;
private float mMaxSwipeProgress = 1f;
private final FlingAnimationUtils mFlingAnimationUtils;
private float mPagingTouchSlop;
private final Callback mCallback;
- private final Handler mHandler;
private final int mSwipeDirection;
private final VelocityTracker mVelocityTracker;
private final FalsingManager mFalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 72c2c0b..9978ec3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -87,7 +87,6 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
@@ -109,6 +108,7 @@
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationSnooze;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarStateController;
@@ -146,11 +146,9 @@
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
public class NotificationStackScrollLayout extends ViewGroup
- implements Callback, ExpandHelper.Callback, ScrollAdapter,
- OnHeightChangedListener, OnGroupChangeListener,
- OnMenuEventListener, VisibilityLocationProvider,
- NotificationListContainer, ConfigurationListener, DragDownCallback, AnimationStateHandler,
- Dumpable {
+ implements ExpandHelper.Callback, ScrollAdapter, OnHeightChangedListener,
+ OnGroupChangeListener, VisibilityLocationProvider, NotificationListContainer,
+ ConfigurationListener, DragDownCallback, AnimationStateHandler, Dumpable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -164,7 +162,7 @@
private static final int INVALID_POINTER = -1;
private ExpandHelper mExpandHelper;
- private NotificationSwipeHelper mSwipeHelper;
+ private final NotificationSwipeHelper mSwipeHelper;
private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
@@ -291,10 +289,6 @@
*/
private int mMaxScrollAfterExpand;
private ExpandableNotificationRow.LongPressListener mLongPressListener;
-
- private NotificationMenuRowPlugin mCurrMenuRow;
- private View mTranslatingParentView;
- private View mMenuExposedView;
boolean mCheckForLeavebehind;
/**
@@ -466,6 +460,9 @@
private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
private NotificationPanelView mNotificationPanel;
+ private final NotificationGutsManager
+ mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
+
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -495,7 +492,8 @@
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(this);
- mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, this, getContext());
+ mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, new SwipeHelperCallback(),
+ getContext(), new NotificationMenuListener());
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
initView(context);
mFalsingManager = FalsingManager.getInstance(context);
@@ -639,41 +637,6 @@
}
@Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onMenuClicked(View view, int x, int y, MenuItem item) {
- if (mLongPressListener == null) {
- return;
- }
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
- row.getStatusBarNotification().getPackageName());
- }
- mLongPressListener.onLongPress(view, x, y, item);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onMenuReset(View row) {
- if (mTranslatingParentView != null && row == mTranslatingParentView) {
- mMenuExposedView = null;
- mTranslatingParentView = null;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onMenuShown(View row) {
- mMenuExposedView = mTranslatingParentView;
- if (row instanceof ExpandableNotificationRow) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
- ((ExpandableNotificationRow) row).getStatusBarNotification()
- .getPackageName());
- }
- mSwipeHelper.onMenuShown(row);
- }
-
- @Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void onUiModeChanged() {
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
@@ -1295,111 +1258,6 @@
mQsContainer = qsContainer;
}
- /**
- * Handles cleanup after the given {@code view} has been fully swiped out (including
- * re-invoking dismiss logic in case the notification has not made its way out yet).
- */
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void onChildDismissed(View view) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (!row.isDismissed()) {
- handleChildViewDismissed(view);
- }
- ViewGroup transientContainer = row.getTransientContainer();
- if (transientContainer != null) {
- transientContainer.removeTransientView(view);
- }
- }
-
- /**
- * Starts up notification dismiss and tells the notification, if any, to remove itself from
- * layout.
- *
- * @param view view (e.g. notification) to dismiss from the layout
- */
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void handleChildViewDismissed(View view) {
- if (mDismissAllInProgress) {
- return;
- }
-
- boolean isBlockingHelperShown = false;
-
- setSwipingInProgress(false);
- if (mDragAnimPendingChildren.contains(view)) {
- // We start the swipe and finish it in the same frame; we don't want a drag animation.
- mDragAnimPendingChildren.remove(view);
- }
- mAmbientState.onDragFinished(view);
- updateContinuousShadowDrawing();
-
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (row.isHeadsUp()) {
- mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
- }
- isBlockingHelperShown =
- row.performDismissWithBlockingHelper(false /* fromAccessibility */);
- }
-
- if (!isBlockingHelperShown) {
- mSwipedOutViews.add(view);
- }
- mFalsingManager.onNotificationDismissed();
- if (mFalsingManager.shouldEnforceBouncer()) {
- mStatusBar.executeRunnableDismissingKeyguard(
- null,
- null /* cancelAction */,
- false /* dismissShade */,
- true /* afterKeyguardGone */,
- false /* deferred */);
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void onChildSnappedBack(View animView, float targetLeft) {
- mAmbientState.onDragFinished(animView);
- updateContinuousShadowDrawing();
- if (!mDragAnimPendingChildren.contains(animView)) {
- if (mAnimationsEnabled) {
- mSnappedBackChildren.add(animView);
- mNeedsAnimation = true;
- }
- requestChildrenUpdate();
- } else {
- // We start the swipe and snap back in the same frame, we don't want any animation
- mDragAnimPendingChildren.remove(animView);
- }
- if (mCurrMenuRow != null && targetLeft == 0) {
- mCurrMenuRow.resetMenu();
- mCurrMenuRow = null;
- }
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
- // Returning true prevents alpha fading.
- return !mFadeNotificationsOnDismiss;
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onBeginDrag(View v) {
- mFalsingManager.onNotificatonStartDismissing();
- setSwipingInProgress(true);
- mAmbientState.onBeginDrag(v);
- updateContinuousShadowDrawing();
- if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
- mDragAnimPendingChildren.add(v);
- mNeedsAnimation = true;
- }
- requestChildrenUpdate();
- }
-
@ShadeViewRefactor(RefactorComponent.ADAPTER)
public static boolean isPinnedHeadsUp(View v) {
if (v instanceof ExpandableNotificationRow) {
@@ -1418,41 +1276,6 @@
return false;
}
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void onDragCancelled(View v) {
- mFalsingManager.onNotificatonStopDismissing();
- setSwipingInProgress(false);
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public float getFalsingThresholdFactor() {
- return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public View getChildAtPosition(MotionEvent ev) {
- View child = getChildAtPosition(ev.getX(), ev.getY());
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- ExpandableNotificationRow parent = row.getNotificationParent();
- if (parent != null && parent.areChildrenExpanded()
- && (parent.areGutsExposed()
- || mMenuExposedView == parent
- || (parent.getNotificationChildren().size() == 1
- && parent.isClearable()))) {
- // In this case the group is expanded and showing the menu for the
- // group, further interaction should apply to the group, not any
- // child notifications so we use the parent of the child. We also do the same
- // if we only have a single child.
- child = parent;
- }
- }
- return child;
- }
-
@ShadeViewRefactor(RefactorComponent.INPUT)
public ExpandableView getClosestChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
@@ -1696,18 +1519,11 @@
return mScrollingEnabled;
}
- @Override
@ShadeViewRefactor(RefactorComponent.ADAPTER)
- public boolean canChildBeDismissed(View v) {
+ private boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
- @Override
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public boolean isAntiFalsingNeeded() {
- return onKeyguard();
- }
-
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private boolean onKeyguard() {
return mStatusBarState == StatusBarState.KEYGUARD;
@@ -1787,8 +1603,8 @@
}
// Check if we need to clear any snooze leavebehinds
- NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
- if (guts != null && !isTouchInView(ev, guts)
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ if (guts != null && !NotificationSwipeHelper.isTouchInView(ev, guts)
&& guts.getGutsContent() instanceof NotificationSnooze) {
NotificationSnooze ns = (NotificationSnooze) guts.getGutsContent();
if ((ns.isExpanded() && isCancelOrUp)
@@ -3013,11 +2829,11 @@
}
// Check if we need to clear any snooze leavebehinds
boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
- NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
- if (!isTouchInView(ev, guts) && isUp && !swipeWantsIt && !expandWantsIt
- && !scrollWantsIt) {
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+ !expandWantsIt && !scrollWantsIt) {
mCheckForLeavebehind = false;
- mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
}
@@ -3077,8 +2893,8 @@
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@Override
public void cleanUpViewState(View child) {
- if (child == mTranslatingParentView) {
- mTranslatingParentView = null;
+ if (child == mSwipeHelper.getTranslatingParentView()) {
+ mSwipeHelper.clearTranslatingParentView();
}
mCurrentStackScrollState.removeViewStateForView(child);
}
@@ -3986,7 +3802,7 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void checkSnoozeLeavebehind() {
if (mCheckForLeavebehind) {
- mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
mCheckForLeavebehind = false;
@@ -4068,7 +3884,7 @@
}
@ShadeViewRefactor(RefactorComponent.COORDINATOR)
- private void setIsExpanded(boolean isExpanded) {
+ public void setIsExpanded(boolean isExpanded) {
boolean changed = isExpanded != mIsExpanded;
mIsExpanded = isExpanded;
mStackScrollAlgorithm.setIsExpanded(isExpanded);
@@ -5242,8 +5058,8 @@
setFooterView(footerView);
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- private void inflateEmptyShadeView() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ private void inflateEmptyShadeView() {
EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_no_notifications, this, false);
view.setText(R.string.empty_shade_text);
@@ -5274,8 +5090,8 @@
mScrimController.setNotificationCount(getNotGoneChildCount());
}
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void setNotificationPanel(NotificationPanelView notificationPanelView) {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void setNotificationPanel(NotificationPanelView notificationPanelView) {
mNotificationPanel = notificationPanelView;
}
@@ -5293,306 +5109,29 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public interface OnOverscrollTopChangedListener {
- /**
- * Notifies a listener that the overscroll has changed.
- *
- * @param amount the amount of overscroll, in pixels
- * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
- * unrubberbanded motion to directly expand overscroll view (e.g
- * expand
- * QS)
- */
- void onOverscrollTopChanged(float amount, boolean isRubberbanded);
+ /**
+ * Notifies a listener that the overscroll has changed.
+ *
+ * @param amount the amount of overscroll, in pixels
+ * @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
+ * unrubberbanded motion to directly expand overscroll view (e.g
+ * expand
+ * QS)
+ */
+ void onOverscrollTopChanged(float amount, boolean isRubberbanded);
- /**
- * Notify a listener that the scroller wants to escape from the scrolling motion and
- * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
- *
- * @param velocity The velocity that the Scroller had when over flinging
- * @param open Should the fling open or close the overscroll view.
- */
- void flingTopOverscroll(float velocity, boolean open);
- }
+ /**
+ * Notify a listener that the scroller wants to escape from the scrolling motion and
+ * start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
+ *
+ * @param velocity The velocity that the Scroller had when over flinging
+ * @param open Should the fling open or close the overscroll view.
+ */
+ void flingTopOverscroll(float velocity, boolean open);
+ }
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private class NotificationSwipeHelper extends SwipeHelper
- implements NotificationSwipeActionHelper {
- private static final long COVER_MENU_DELAY = 4000;
- private Runnable mFalsingCheck;
- private Handler mHandler;
-
- private static final long SWIPE_MENU_TIMING = 200;
-
- public NotificationSwipeHelper(int swipeDirection, Callback callback, Context context) {
- super(swipeDirection, callback, context);
- mHandler = new Handler();
- mFalsingCheck = new Runnable() {
- @Override
- public void run() {
- resetExposedMenuView(true /* animate */, true /* force */);
- }
- };
- }
-
- @Override
- public void onDownUpdate(View currView, MotionEvent ev) {
- mTranslatingParentView = currView;
- if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchStart();
- }
- mCurrMenuRow = null;
- mHandler.removeCallbacks(mFalsingCheck);
-
- // Slide back any notifications that might be showing a menu
- resetExposedMenuView(true /* animate */, false /* force */);
-
- if (currView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) currView;
-
- if (row.getEntry().hasFinishedInitialization()) {
- mCurrMenuRow = row.createMenu();
- mCurrMenuRow.setMenuClickListener(NotificationStackScrollLayout.this);
- mCurrMenuRow.onTouchStart();
- }
- }
- }
-
- private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) {
- return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu();
- }
-
- @Override
- public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) {
- mHandler.removeCallbacks(mFalsingCheck);
- if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchMove(delta);
- }
- }
-
- @Override
- public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
- float translation) {
- if (mCurrMenuRow != null) {
- mCurrMenuRow.onTouchEnd();
- handleMenuRowSwipe(ev, animView, velocity, mCurrMenuRow);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean swipedFarEnough(float translation, float viewSize) {
- return swipedFarEnough();
- }
-
- private void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity,
- NotificationMenuRowPlugin menuRow) {
- if (!menuRow.shouldShowMenu()) {
- // If the menu should not be shown, then there is no need to check if the a swipe
- // should result in a snapping to the menu. As a result, just check if the swipe
- // was enough to dismiss the notification.
- if (isDismissGesture(ev)) {
- dismiss(animView, velocity);
- } else {
- snapBack(animView, velocity);
- menuRow.onSnapClosed();
- }
- return;
- }
-
- if (menuRow.isSnappedAndOnSameSide()) {
- // Menu was snapped to previously and we're on the same side
- handleSwipeFromSnap(ev, animView, velocity, menuRow);
- } else {
- // Menu has not been snapped, or was snapped previously but is now on
- // the opposite side.
- handleSwipeFromNonSnap(ev, animView, velocity, menuRow);
- }
- }
-
- private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity,
- NotificationMenuRowPlugin menuRow) {
- boolean isDismissGesture = isDismissGesture(ev);
- final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity);
- final boolean gestureFastEnough =
- mSwipeHelper.getMinDismissVelocity() <= Math.abs(velocity);
-
- final double timeForGesture = ev.getEventTime() - ev.getDownTime();
- final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed()
- && timeForGesture >= SWIPE_MENU_TIMING;
-
- if (!isFalseGesture(ev)
- && (swipedEnoughToShowMenu(menuRow)
- && (!gestureFastEnough || showMenuForSlowOnGoing))
- || (gestureTowardsMenu && !isDismissGesture)) {
- // Menu has not been snapped to previously and this is menu revealing gesture
- snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
- menuRow.onSnapOpen();
- } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
- dismiss(animView, velocity);
- menuRow.onDismiss();
- } else {
- snapBack(animView, velocity);
- menuRow.onSnapClosed();
- }
- }
-
- private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity,
- NotificationMenuRowPlugin menuRow) {
- boolean isDismissGesture = isDismissGesture(ev);
-
- final boolean withinSnapMenuThreshold =
- menuRow.isWithinSnapMenuThreshold();
-
- if (withinSnapMenuThreshold && !isDismissGesture) {
- // Haven't moved enough to unsnap from the menu
- menuRow.onSnapOpen();
- snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
- } else if (isDismissGesture && !menuRow.shouldSnapBack()) {
- // Only dismiss if we're not moving towards the menu
- dismiss(animView, velocity);
- menuRow.onDismiss();
- } else {
- snapBack(animView, velocity);
- menuRow.onSnapClosed();
- }
- }
-
- @Override
- public void dismissChild(final View view, float velocity,
- boolean useAccelerateInterpolator) {
- super.dismissChild(view, velocity, useAccelerateInterpolator);
- if (mIsExpanded) {
- // We don't want to quick-dismiss when it's a heads up as this might lead to closing
- // of the panel early.
- handleChildViewDismissed(view);
- }
- mStatusBar.getGutsManager().closeAndSaveGuts(true /* removeLeavebehind */,
- false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- handleMenuCoveredOrDismissed();
- }
-
- @Override
- public void snapChild(final View animView, final float targetLeft, float velocity) {
- super.snapChild(animView, targetLeft, velocity);
- onDragCancelled(animView);
- if (targetLeft == 0) {
- handleMenuCoveredOrDismissed();
- }
- }
-
- @Override
- public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) {
- mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
- }
-
- private void handleMenuCoveredOrDismissed() {
- if (mMenuExposedView != null && mMenuExposedView == mTranslatingParentView) {
- mMenuExposedView = null;
- }
- }
-
- @Override
- public Animator getViewTranslationAnimator(View v, float target,
- AnimatorUpdateListener listener) {
- if (v instanceof ExpandableNotificationRow) {
- return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
- } else {
- return super.getViewTranslationAnimator(v, target, listener);
- }
- }
-
- @Override
- public void setTranslation(View v, float translate) {
- ((ExpandableView) v).setTranslation(translate);
- }
-
- @Override
- public float getTranslation(View v) {
- return ((ExpandableView) v).getTranslation();
- }
-
- @Override
- public void dismiss(View animView, float velocity) {
- dismissChild(animView, velocity,
- !swipedFastEnough(0, 0) /* useAccelerateInterpolator */);
- }
-
- @Override
- public void snapOpen(View animView, int targetLeft, float velocity) {
- snapChild(animView, targetLeft, velocity);
- }
-
- private void snapBack(View animView, float velocity) {
- snapChild(animView, 0, velocity);
- }
-
- @Override
- public boolean swipedFastEnough(float translation, float velocity) {
- return swipedFastEnough();
- }
-
- @Override
- public float getMinDismissVelocity() {
- return getEscapeVelocity();
- }
-
- public void onMenuShown(View animView) {
- onDragCancelled(animView);
-
- // If we're on the lockscreen we want to false this.
- if (isAntiFalsingNeeded()) {
- mHandler.removeCallbacks(mFalsingCheck);
- mHandler.postDelayed(mFalsingCheck, COVER_MENU_DELAY);
- }
- }
-
- public void closeControlsIfOutsideTouch(MotionEvent ev) {
- NotificationGuts guts = mStatusBar.getGutsManager().getExposedGuts();
- View view = null;
- if (guts != null && !guts.getGutsContent().isLeavebehind()) {
- // Only close visible guts if they're not a leavebehind.
- view = guts;
- } else if (mCurrMenuRow != null && mCurrMenuRow.isMenuVisible()
- && mTranslatingParentView != null) {
- // Checking menu
- view = mTranslatingParentView;
- }
- if (view != null && !isTouchInView(ev, view)) {
- // Touch was outside visible guts / menu notification, close what's visible
- mStatusBar.getGutsManager().closeAndSaveGuts(false /* removeLeavebehind */,
- false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- resetExposedMenuView(true /* animate */, true /* force */);
- }
- }
-
- public void resetExposedMenuView(boolean animate, boolean force) {
- if (mMenuExposedView == null
- || (!force && mMenuExposedView == mTranslatingParentView)) {
- // If no menu is showing or it's showing for this view we do nothing.
- return;
- }
- final View prevMenuExposedView = mMenuExposedView;
- if (animate) {
- Animator anim = getViewTranslationAnimator(prevMenuExposedView,
- 0 /* leftTarget */, null /* updateListener */);
- if (anim != null) {
- anim.start();
- }
- } else if (mMenuExposedView instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) mMenuExposedView;
- if (!row.isRemoved()) {
- row.resetTranslation();
- }
- }
- mMenuExposedView = null;
- }
- }
-
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public boolean hasActiveNotifications() {
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public boolean hasActiveNotifications() {
return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
}
@@ -5656,8 +5195,8 @@
return mStatusBarState == StatusBarState.KEYGUARD;
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- public void updateSpeedBumpIndex() {
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
final int N = getChildCount();
@@ -5677,24 +5216,6 @@
updateSpeedBumpIndex(speedBumpIndex, noAmbient);
}
- @ShadeViewRefactor(RefactorComponent.INPUT)
- private boolean isTouchInView(MotionEvent ev, View view) {
- if (view == null) {
- return false;
- }
- final int height = (view instanceof ExpandableView)
- ? ((ExpandableView) view).getActualHeight()
- : view.getHeight();
- final int rx = (int) ev.getRawX();
- final int ry = (int) ev.getRawY();
- view.getLocationOnScreen(mTempInt2);
- final int x = mTempInt2[0];
- final int y = mTempInt2[1];
- Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
- boolean ret = rect.contains(rx, ry);
- return ret;
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContinuousShadowDrawing() {
boolean continuousShadowUpdate = mAnimationRunning
@@ -5718,11 +5239,29 @@
@ShadeViewRefactor(RefactorComponent.INPUT)
public void closeControlsIfOutsideTouch(MotionEvent ev) {
- mSwipeHelper.closeControlsIfOutsideTouch(ev);
+ NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ View view = null;
+ if (guts != null && !guts.getGutsContent().isLeavebehind()) {
+ // Only close visible guts if they're not a leavebehind.
+ view = guts;
+ } else if (menuRow != null && menuRow.isMenuVisible()
+ && translatingParentView != null) {
+ // Checking menu
+ view = translatingParentView;
+ }
+ if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
+ // Touch was outside visible guts / menu notification, close what's visible
+ mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
+ false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ resetExposedMenuView(true /* animate */, true /* force */);
+ }
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- static class AnimationEvent {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ static class AnimationEvent {
static AnimationFilter[] FILTERS = new AnimationFilter[]{
@@ -6022,8 +5561,8 @@
}
}
- @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
- private final StateListener mStateListener = new StateListener() {
+ @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
+ private final StateListener mStateListener = new StateListener() {
@Override
public void onStatePreChange(int oldState, int newState) {
if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
@@ -6036,9 +5575,222 @@
setStatusBarState(newState);
}
- @Override
- public void onStatePostChange() {
+ @Override
+ public void onStatePostChange() {
NotificationStackScrollLayout.this.onStatePostChange();
}
- };
+ };
+
+ class NotificationMenuListener implements NotificationMenuRowPlugin.OnMenuEventListener {
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onMenuClicked(View view, int x, int y, MenuItem item) {
+ if (mLongPressListener == null) {
+ return;
+ }
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
+ row.getStatusBarNotification().getPackageName());
+ }
+ mLongPressListener.onLongPress(view, x, y, item);
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onMenuReset(View row) {
+ View translatingParentView = mSwipeHelper.getTranslatingParentView();
+ if (translatingParentView != null && row == translatingParentView) {
+ mSwipeHelper.clearExposedMenuView();
+ mSwipeHelper.clearTranslatingParentView();
+ }
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onMenuShown(View row) {
+ if (row instanceof ExpandableNotificationRow) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
+ ((ExpandableNotificationRow) row).getStatusBarNotification()
+ .getPackageName());
+ }
+ mSwipeHelper.onMenuShown(row);
+ }
+ }
+
+ class SwipeHelperCallback implements NotificationSwipeHelper.NotificationCallback {
+ @Override
+ public void onDismiss() {
+ mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
+ false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ }
+
+ @Override
+ public void onSnooze(StatusBarNotification sbn,
+ NotificationSwipeActionHelper.SnoozeOption snoozeOption) {
+ mStatusBar.setNotificationSnoozed(sbn, snoozeOption);
+ }
+
+ @Override
+ public boolean isExpanded() {
+ return NotificationStackScrollLayout.this.isExpanded();
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onDragCancelled(View v) {
+ mFalsingManager.onNotificatonStopDismissing();
+ setSwipingInProgress(false);
+ }
+
+ /**
+ * Handles cleanup after the given {@code view} has been fully swiped out (including
+ * re-invoking dismiss logic in case the notification has not made its way out yet).
+ */
+ @Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void onChildDismissed(View view) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (!row.isDismissed()) {
+ handleChildViewDismissed(view);
+ }
+ ViewGroup transientContainer = row.getTransientContainer();
+ if (transientContainer != null) {
+ transientContainer.removeTransientView(view);
+ }
+ }
+
+ /**
+ * Starts up notification dismiss and tells the notification, if any, to remove itself from
+ * layout.
+ *
+ * @param view view (e.g. notification) to dismiss from the layout
+ */
+
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void handleChildViewDismissed(View view) {
+ if (mDismissAllInProgress) {
+ return;
+ }
+
+ boolean isBlockingHelperShown = false;
+
+ setSwipingInProgress(false);
+ if (mDragAnimPendingChildren.contains(view)) {
+ // We start the swipe and finish it in the same frame; we don't want a drag
+ // animation.
+ mDragAnimPendingChildren.remove(view);
+ }
+ mAmbientState.onDragFinished(view);
+ updateContinuousShadowDrawing();
+
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.isHeadsUp()) {
+ mHeadsUpManager.addSwipedOutNotification(
+ row.getStatusBarNotification().getKey());
+ }
+ isBlockingHelperShown =
+ row.performDismissWithBlockingHelper(false /* fromAccessibility */);
+ }
+
+ if (!isBlockingHelperShown) {
+ mSwipedOutViews.add(view);
+ }
+ mFalsingManager.onNotificationDismissed();
+ if (mFalsingManager.shouldEnforceBouncer()) {
+ mStatusBar.executeRunnableDismissingKeyguard(
+ null,
+ null /* cancelAction */,
+ false /* dismissShade */,
+ true /* afterKeyguardGone */,
+ false /* deferred */);
+ }
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean isAntiFalsingNeeded() {
+ return onKeyguard();
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public View getChildAtPosition(MotionEvent ev) {
+ View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(),
+ ev.getY());
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ ExpandableNotificationRow parent = row.getNotificationParent();
+ if (parent != null && parent.areChildrenExpanded()
+ && (parent.areGutsExposed()
+ || mSwipeHelper.getExposedMenuView() == parent
+ || (parent.getNotificationChildren().size() == 1
+ && parent.isClearable()))) {
+ // In this case the group is expanded and showing the menu for the
+ // group, further interaction should apply to the group, not any
+ // child notifications so we use the parent of the child. We also do the same
+ // if we only have a single child.
+ child = parent;
+ }
+ }
+ return child;
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public void onBeginDrag(View v) {
+ mFalsingManager.onNotificatonStartDismissing();
+ setSwipingInProgress(true);
+ mAmbientState.onBeginDrag(v);
+ updateContinuousShadowDrawing();
+ if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
+ mDragAnimPendingChildren.add(v);
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
+ public void onChildSnappedBack(View animView, float targetLeft) {
+ mAmbientState.onDragFinished(animView);
+ updateContinuousShadowDrawing();
+ if (!mDragAnimPendingChildren.contains(animView)) {
+ if (mAnimationsEnabled) {
+ mSnappedBackChildren.add(animView);
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ } else {
+ // We start the swipe and snap back in the same frame, we don't want any animation
+ mDragAnimPendingChildren.remove(animView);
+ }
+ NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
+ if (menuRow != null && targetLeft == 0) {
+ menuRow.resetMenu();
+ mSwipeHelper.clearCurrentMenuRow();
+ }
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public boolean updateSwipeProgress(View animView, boolean dismissable,
+ float swipeProgress) {
+ // Returning true prevents alpha fading.
+ return !mFadeNotificationsOnDismiss;
+ }
+
+ @Override
+ @ShadeViewRefactor(RefactorComponent.INPUT)
+ public float getFalsingThresholdFactor() {
+ return mStatusBar.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
+ }
+
+ @Override
+ public boolean canChildBeDismissed(View v) {
+ return NotificationStackScrollLayout.this.canChildBeDismissed(v);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
new file mode 100644
index 0000000..028957d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -0,0 +1,424 @@
+/*
+ * 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 Licen
+ */
+
+
+package com.android.systemui.statusbar.notification.stack;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.notification.ShadeViewRefactor;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.ExpandableView;
+
+@ShadeViewRefactor(ShadeViewRefactor.RefactorComponent.INPUT)
+class NotificationSwipeHelper extends SwipeHelper
+ implements NotificationSwipeActionHelper {
+ @VisibleForTesting
+ protected static final long COVER_MENU_DELAY = 4000;
+ private static final String TAG = "NotificationSwipeHelper";
+ private final Runnable mFalsingCheck;
+ private View mTranslatingParentView;
+ private View mMenuExposedView;
+ private final NotificationCallback mCallback;
+ private final NotificationMenuRowPlugin.OnMenuEventListener mMenuListener;
+
+ private static final long SWIPE_MENU_TIMING = 200;
+
+ private NotificationMenuRowPlugin mCurrMenuRow;
+
+ public NotificationSwipeHelper(int swipeDirection, NotificationCallback callback,
+ Context context, NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
+ super(swipeDirection, callback, context);
+ mMenuListener = menuListener;
+ mCallback = callback;
+ mFalsingCheck = new Runnable() {
+ @Override
+ public void run() {
+ resetExposedMenuView(true /* animate */, true /* force */);
+ }
+ };
+ }
+
+ public View getTranslatingParentView() {
+ return mTranslatingParentView;
+ }
+
+ public void clearTranslatingParentView() { setTranslatingParentView(null); }
+
+ @VisibleForTesting
+ protected void setTranslatingParentView(View view) { mTranslatingParentView = view; };
+
+ public void setExposedMenuView(View view) {
+ mMenuExposedView = view;
+ }
+
+ public void clearExposedMenuView() { setExposedMenuView(null); }
+
+ public void clearCurrentMenuRow() { setCurrentMenuRow(null); }
+
+ public View getExposedMenuView() {
+ return mMenuExposedView;
+ }
+
+ public void setCurrentMenuRow(NotificationMenuRowPlugin menuRow) {
+ mCurrMenuRow = menuRow;
+ }
+
+ public NotificationMenuRowPlugin getCurrentMenuRow() { return mCurrMenuRow; }
+
+ @VisibleForTesting
+ protected Handler getHandler() { return mHandler; }
+
+ @VisibleForTesting
+ protected Runnable getFalsingCheck() { return mFalsingCheck; };
+
+ @Override
+ public void onDownUpdate(View currView, MotionEvent ev) {
+ mTranslatingParentView = currView;
+ NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+ if (menuRow != null) {
+ menuRow.onTouchStart();
+ }
+ clearCurrentMenuRow();
+ getHandler().removeCallbacks(getFalsingCheck());
+
+ // Slide back any notifications that might be showing a menu
+ resetExposedMenuView(true /* animate */, false /* force */);
+
+ if (currView instanceof ExpandableNotificationRow) {
+ initializeRow((ExpandableNotificationRow) currView);
+ }
+ }
+
+ @VisibleForTesting
+ protected void initializeRow(ExpandableNotificationRow row) {
+ if (row.getEntry().hasFinishedInitialization()) {
+ mCurrMenuRow = row.createMenu();
+ mCurrMenuRow.setMenuClickListener(mMenuListener);
+ mCurrMenuRow.onTouchStart();
+ }
+ }
+
+ private boolean swipedEnoughToShowMenu(NotificationMenuRowPlugin menuRow) {
+ return !swipedFarEnough() && menuRow.isSwipedEnoughToShowMenu();
+ }
+
+ @Override
+ public void onMoveUpdate(View view, MotionEvent ev, float translation, float delta) {
+ getHandler().removeCallbacks(getFalsingCheck());
+ NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+ if (menuRow != null) {
+ menuRow.onTouchMove(delta);
+ }
+ }
+
+ @Override
+ public boolean handleUpEvent(MotionEvent ev, View animView, float velocity,
+ float translation) {
+ NotificationMenuRowPlugin menuRow = getCurrentMenuRow();
+ if (menuRow != null) {
+ menuRow.onTouchEnd();
+ handleMenuRowSwipe(ev, animView, velocity, menuRow);
+ return true;
+ }
+ return false;
+ }
+
+ @VisibleForTesting
+ protected void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ if (!menuRow.shouldShowMenu()) {
+ // If the menu should not be shown, then there is no need to check if the a swipe
+ // should result in a snapping to the menu. As a result, just check if the swipe
+ // was enough to dismiss the notification.
+ if (isDismissGesture(ev)) {
+ dismiss(animView, velocity);
+ } else {
+ snapClosed(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ return;
+ }
+
+ if (menuRow.isSnappedAndOnSameSide()) {
+ // Menu was snapped to previously and we're on the same side
+ handleSwipeFromSnap(ev, animView, velocity, menuRow);
+ } else {
+ // Menu has not been snapped, or was snapped previously but is now on
+ // the opposite side.
+ handleSwipeFromNonSnap(ev, animView, velocity, menuRow);
+ }
+ }
+
+ private void handleSwipeFromNonSnap(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ boolean isDismissGesture = isDismissGesture(ev);
+ final boolean gestureTowardsMenu = menuRow.isTowardsMenu(velocity);
+ final boolean gestureFastEnough = getEscapeVelocity() <= Math.abs(velocity);
+
+ final double timeForGesture = ev.getEventTime() - ev.getDownTime();
+ final boolean showMenuForSlowOnGoing = !menuRow.canBeDismissed()
+ && timeForGesture >= SWIPE_MENU_TIMING;
+
+ if (!isFalseGesture(ev)
+ && (swipedEnoughToShowMenu(menuRow)
+ && (!gestureFastEnough || showMenuForSlowOnGoing))
+ || (gestureTowardsMenu && !isDismissGesture)) {
+ // Menu has not been snapped to previously and this is menu revealing gesture
+ snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+ menuRow.onSnapOpen();
+ } else if (isDismissGesture(ev) && !gestureTowardsMenu) {
+ dismiss(animView, velocity);
+ menuRow.onDismiss();
+ } else {
+ snapClosed(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ }
+
+ private void handleSwipeFromSnap(MotionEvent ev, View animView, float velocity,
+ NotificationMenuRowPlugin menuRow) {
+ boolean isDismissGesture = isDismissGesture(ev);
+
+ final boolean withinSnapMenuThreshold =
+ menuRow.isWithinSnapMenuThreshold();
+
+ if (withinSnapMenuThreshold && !isDismissGesture) {
+ // Haven't moved enough to unsnap from the menu
+ menuRow.onSnapOpen();
+ snapOpen(animView, menuRow.getMenuSnapTarget(), velocity);
+ } else if (isDismissGesture && !menuRow.shouldSnapBack()) {
+ // Only dismiss if we're not moving towards the menu
+ dismiss(animView, velocity);
+ menuRow.onDismiss();
+ } else {
+ snapClosed(animView, velocity);
+ menuRow.onSnapClosed();
+ }
+ }
+
+ @Override
+ public void dismissChild(final View view, float velocity,
+ boolean useAccelerateInterpolator) {
+ superDismissChild(view, velocity, useAccelerateInterpolator);
+ if (mCallback.isExpanded()) {
+ // We don't want to quick-dismiss when it's a heads up as this might lead to closing
+ // of the panel early.
+ mCallback.handleChildViewDismissed(view);
+ }
+ mCallback.onDismiss();
+ handleMenuCoveredOrDismissed();
+ }
+
+ @VisibleForTesting
+ protected void superDismissChild(final View view, float velocity, boolean useAccelerateInterpolator) {
+ super.dismissChild(view, velocity, useAccelerateInterpolator);
+ }
+
+ @VisibleForTesting
+ protected void superSnapChild(final View animView, final float targetLeft, float velocity) {
+ super.snapChild(animView, targetLeft, velocity);
+ }
+
+ @Override
+ public void snapChild(final View animView, final float targetLeft, float velocity) {
+ superSnapChild(animView, targetLeft, velocity);
+ mCallback.onDragCancelled(animView);
+ if (targetLeft == 0) {
+ handleMenuCoveredOrDismissed();
+ }
+ }
+
+ @Override
+ public void snooze(StatusBarNotification sbn, SnoozeOption snoozeOption) {
+ mCallback.onSnooze(sbn, snoozeOption);
+ }
+
+ @VisibleForTesting
+ protected void handleMenuCoveredOrDismissed() {
+ View exposedMenuView = getExposedMenuView();
+ if (exposedMenuView != null && exposedMenuView == mTranslatingParentView) {
+ clearExposedMenuView();
+ }
+ }
+
+ @VisibleForTesting
+ protected Animator superGetViewTranslationAnimator(View v, float target,
+ ValueAnimator.AnimatorUpdateListener listener) {
+ return super.getViewTranslationAnimator(v, target, listener);
+ }
+
+ @Override
+ public Animator getViewTranslationAnimator(View v, float target,
+ ValueAnimator.AnimatorUpdateListener listener) {
+ if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
+ } else {
+ return superGetViewTranslationAnimator(v, target, listener);
+ }
+ }
+
+ @Override
+ public void setTranslation(View v, float translate) {
+ if (v instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) v).setTranslation(translate);
+ } else {
+ Log.wtf(TAG, "setTranslation should only be called on an ExpandableNotificationRow.");
+ }
+ }
+
+ @Override
+ public float getTranslation(View v) {
+ if (v instanceof ExpandableNotificationRow) {
+ return ((ExpandableNotificationRow) v).getTranslation();
+ }
+ else {
+ Log.wtf(TAG, "getTranslation should only be called on an ExpandableNotificationRow.");
+ return 0f;
+ }
+ }
+
+ @Override
+ public boolean swipedFastEnough(float translation, float viewSize) {
+ return swipedFastEnough();
+ }
+
+ @Override
+ @VisibleForTesting
+ protected boolean swipedFastEnough() {
+ return super.swipedFastEnough();
+ }
+
+ @Override
+ public boolean swipedFarEnough(float translation, float viewSize) {
+ return swipedFarEnough();
+ }
+
+ @Override
+ @VisibleForTesting
+ protected boolean swipedFarEnough() {
+ return super.swipedFarEnough();
+ }
+
+ @Override
+ public void dismiss(View animView, float velocity) {
+ dismissChild(animView, velocity,
+ !swipedFastEnough() /* useAccelerateInterpolator */);
+ }
+
+ @Override
+ public void snapOpen(View animView, int targetLeft, float velocity) {
+ snapChild(animView, targetLeft, velocity);
+ }
+
+ @VisibleForTesting
+ protected void snapClosed(View animView, float velocity) {
+ snapChild(animView, 0, velocity);
+ }
+
+ @Override
+ @VisibleForTesting
+ protected float getEscapeVelocity() {
+ return super.getEscapeVelocity();
+ }
+
+ @Override
+ public float getMinDismissVelocity() {
+ return getEscapeVelocity();
+ }
+
+ public void onMenuShown(View animView) {
+ setExposedMenuView(getTranslatingParentView());
+ mCallback.onDragCancelled(animView);
+ Handler handler = getHandler();
+
+ // If we're on the lockscreen we want to false this.
+ if (mCallback.isAntiFalsingNeeded()) {
+ handler.removeCallbacks(getFalsingCheck());
+ handler.postDelayed(getFalsingCheck(), COVER_MENU_DELAY);
+ }
+ }
+
+ @VisibleForTesting
+ protected boolean shouldResetMenu(boolean force) {
+ if (mMenuExposedView == null
+ || (!force && mMenuExposedView == mTranslatingParentView)) {
+ // If no menu is showing or it's showing for this view we do nothing.
+ return false;
+ }
+ return true;
+ }
+
+ public void resetExposedMenuView(boolean animate, boolean force) {
+ if (!shouldResetMenu(force)) {
+ return;
+ }
+ final View prevMenuExposedView = getExposedMenuView();
+ if (animate) {
+ Animator anim = getViewTranslationAnimator(prevMenuExposedView,
+ 0 /* leftTarget */, null /* updateListener */);
+ if (anim != null) {
+ anim.start();
+ }
+ } else if (prevMenuExposedView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) prevMenuExposedView;
+ if (!row.isRemoved()) {
+ row.resetTranslation();
+ }
+ }
+ clearExposedMenuView();
+ }
+
+ public static boolean isTouchInView(MotionEvent ev, View view) {
+ if (view == null) {
+ return false;
+ }
+ final int height = (view instanceof ExpandableView)
+ ? ((ExpandableView) view).getActualHeight()
+ : view.getHeight();
+ final int rx = (int) ev.getRawX();
+ final int ry = (int) ev.getRawY();
+ int[] temp = new int[2];
+ view.getLocationOnScreen(temp);
+ final int x = temp[0];
+ final int y = temp[1];
+ Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
+ boolean ret = rect.contains(rx, ry);
+ return ret;
+ }
+
+ public interface NotificationCallback extends SwipeHelper.Callback{
+ boolean isExpanded();
+
+ void handleChildViewDismissed(View view);
+
+ void onSnooze(StatusBarNotification sbn, SnoozeOption snoozeOption);
+
+ void onDismiss();
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 09c1931..da59450 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -79,13 +79,14 @@
Dependency.get(NotificationLockscreenUserManager.class);
NotificationViewHierarchyManager viewHierarchyManager =
Dependency.get(NotificationViewHierarchyManager.class);
+ NotificationGroupManager groupManager = Dependency.get(NotificationGroupManager.class);
when(mPresenter.getNotificationLockscreenUserManager()).thenReturn(lockscreenUserManager);
- when(mPresenter.getGroupManager()).thenReturn(
- Dependency.get(NotificationGroupManager.class));
+ when(mPresenter.getGroupManager()).thenReturn(groupManager);
entryManager.setUpWithPresenter(mPresenter, mListContainer, mEntryManagerCallback,
mHeadsUpManager);
+ groupManager.setHeadsUpManager(mHeadsUpManager);
gutsManager.setUpWithPresenter(mPresenter, mListContainer, mCheckSaveListener,
mOnClickListener);
notificationLogger.setUpWithEntryManager(entryManager, mListContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
new file mode 100644
index 0000000..b5f67c06
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -0,0 +1,511 @@
+/*
+ * 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.notification.stack;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockitoSession;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.service.notification.StatusBarNotification;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.MotionEvent;
+
+import com.android.systemui.SwipeHelper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationMenuRow;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for {@link NotificationSwipeHelper}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationSwipeHelperTest extends SysuiTestCase {
+
+ private NotificationSwipeHelper mSwipeHelper;
+ private NotificationSwipeHelper.NotificationCallback mCallback;
+ private NotificationMenuRowPlugin.OnMenuEventListener mListener;
+ private View mView;
+ private MotionEvent mEvent;
+ private NotificationMenuRowPlugin mMenuRow;
+ private Handler mHandler;
+ private ExpandableNotificationRow mNotificationRow;
+ private Runnable mFalsingCheck;
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule();
+
+ @Before
+ @UiThreadTest
+ public void setUp() throws Exception {
+ mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
+ mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
+ mSwipeHelper = spy(new NotificationSwipeHelper(SwipeHelper.X, mCallback, mContext, mListener));
+ mView = mock(View.class);
+ mEvent = mock(MotionEvent.class);
+ mMenuRow = mock(NotificationMenuRowPlugin.class);
+ mNotificationRow = mock(ExpandableNotificationRow.class);
+ mHandler = mock(Handler.class);
+ mFalsingCheck = mock(Runnable.class);
+ }
+
+ @Test
+ public void testSetExposedMenuView() {
+ assertEquals("intialized with null exposed menu view", null,
+ mSwipeHelper.getExposedMenuView());
+ mSwipeHelper.setExposedMenuView(mView);
+ assertEquals("swipe helper has correct exposedMenuView after setExposedMenuView to a view",
+ mView, mSwipeHelper.getExposedMenuView());
+ mSwipeHelper.setExposedMenuView(null);
+ assertEquals("swipe helper has null exposedMenuView after setExposedMenuView to null",
+ null, mSwipeHelper.getExposedMenuView());
+ }
+
+ @Test
+ public void testClearExposedMenuView() {
+ doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+ mSwipeHelper.clearExposedMenuView();
+ verify(mSwipeHelper, times(1)).setExposedMenuView(null);
+ }
+
+ @Test
+ public void testGetTranslatingParentView() {
+ assertEquals("intialized with null translating parent view", null,
+ mSwipeHelper.getTranslatingParentView());
+ mSwipeHelper.setTranslatingParentView(mView);
+ assertEquals("has translating parent view after setTranslatingParentView with a view",
+ mView, mSwipeHelper.getTranslatingParentView());
+ }
+
+ @Test
+ public void testClearTranslatingParentView() {
+ doNothing().when(mSwipeHelper).setTranslatingParentView(null);
+ mSwipeHelper.clearTranslatingParentView();
+ verify(mSwipeHelper, times(1)).setTranslatingParentView(null);
+ }
+
+ @Test
+ public void testSetCurrentMenuRow() {
+ assertEquals("currentMenuRow initializes to null", null,
+ mSwipeHelper.getCurrentMenuRow());
+ mSwipeHelper.setCurrentMenuRow(mMenuRow);
+ assertEquals("currentMenuRow set correctly after setCurrentMenuRow", mMenuRow,
+ mSwipeHelper.getCurrentMenuRow());
+ mSwipeHelper.setCurrentMenuRow(null);
+ assertEquals("currentMenuRow set to null after setCurrentMenuRow to null",
+ null, mSwipeHelper.getCurrentMenuRow());
+ }
+
+ @Test
+ public void testClearCurrentMenuRow() {
+ doNothing().when(mSwipeHelper).setCurrentMenuRow(null);
+ mSwipeHelper.clearCurrentMenuRow();
+ verify(mSwipeHelper, times(1)).setCurrentMenuRow(null);
+ }
+
+ @Test
+ public void testOnDownUpdate_ExpandableNotificationRow() {
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+ doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
+ doNothing().when(mSwipeHelper).clearCurrentMenuRow();
+ doNothing().when(mSwipeHelper).initializeRow(any());
+
+ mSwipeHelper.onDownUpdate(mNotificationRow, mEvent);
+
+ verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
+ verify(mSwipeHelper, times(1)).initializeRow(mNotificationRow);
+ }
+
+ @Test
+ public void testOnDownUpdate_notExpandableNotificationRow() {
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+ doNothing().when(mSwipeHelper).resetExposedMenuView(true, false);
+ doNothing().when(mSwipeHelper).clearCurrentMenuRow();
+ doNothing().when(mSwipeHelper).initializeRow(any());
+
+ mSwipeHelper.onDownUpdate(mView, mEvent);
+
+ verify(mSwipeHelper, times(1)).clearCurrentMenuRow();
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mSwipeHelper, times(1)).resetExposedMenuView(true, false);
+ verify(mSwipeHelper, times(0)).initializeRow(any());
+ }
+
+ @Test
+ public void testOnMoveUpdate_menuRow() {
+ when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+
+ mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
+
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mMenuRow, times(1)).onTouchMove(10);
+ }
+
+ @Test
+ public void testOnMoveUpdate_noMenuRow() {
+ when(mSwipeHelper.getHandler()).thenReturn(mHandler);
+ when(mSwipeHelper.getFalsingCheck()).thenReturn(mFalsingCheck);
+
+ mSwipeHelper.onMoveUpdate(mView, mEvent, 0, 10);
+
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ }
+
+ @Test
+ public void testHandleUpEvent_noMenuRow() {
+ assertFalse("Menu row does not exist",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ }
+
+ @Test
+ public void testHandleUpEvent_menuRow() {
+ when(mSwipeHelper.getCurrentMenuRow()).thenReturn(mMenuRow);
+ doNothing().when(mSwipeHelper).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+
+ assertTrue("Menu row exists",
+ mSwipeHelper.handleUpEvent(mEvent, mView, 0, 0));
+ verify(mMenuRow, times(1)).onTouchEnd();
+ verify(mSwipeHelper, times(1)).handleMenuRowSwipe(mEvent, mView, 0, mMenuRow);
+ }
+
+ @Test
+ public void testDismissChild_notExpanded() {
+ when(mCallback.isExpanded()).thenReturn(false);
+ doNothing().when(mSwipeHelper).superDismissChild(mView, 0, false);
+ doNothing().when(mSwipeHelper).handleMenuCoveredOrDismissed();
+
+ mSwipeHelper.dismissChild(mView, 0, false);
+
+ verify(mSwipeHelper, times(1)).superDismissChild(mView, 0, false);
+ verify(mCallback, times(0)).handleChildViewDismissed(mView);
+ verify(mCallback, times(1)).onDismiss();
+ verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
+ }
+
+ @Test
+ public void testSnapchild_targetIsZero() {
+ doNothing().when(mSwipeHelper).superSnapChild(mView, 0, 0);
+ mSwipeHelper.snapChild(mView, 0, 0);
+
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mSwipeHelper, times(1)).superSnapChild(mView, 0, 0);
+ verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
+ }
+
+
+ @Test
+ public void testSnapchild_targetNotZero() {
+ doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0);
+ mSwipeHelper.snapChild(mView, 10, 0);
+
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mSwipeHelper, times(1)).superSnapChild(mView, 10, 0);
+ verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
+ }
+
+ @Test
+ public void testSnooze() {
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ SnoozeOption snoozeOption = mock(SnoozeOption.class);
+ mSwipeHelper.snooze(sbn, snoozeOption);
+ verify(mCallback, times(1)).onSnooze(sbn, snoozeOption);
+ }
+
+ @Test
+ public void testGetViewTranslationAnimator_notExpandableNotificationRow() {
+ Animator animator = mock(Animator.class);
+ AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
+ doReturn(animator).when(mSwipeHelper).superGetViewTranslationAnimator(mView, 0, listener);
+
+ assertEquals("returns the correct animator from super", animator,
+ mSwipeHelper.getViewTranslationAnimator(mView, 0, listener));
+
+ verify(mSwipeHelper, times(1)).superGetViewTranslationAnimator(mView, 0, listener);
+ }
+
+ @Test
+ public void testGetViewTranslationAnimator_expandableNotificationRow() {
+ Animator animator = mock(Animator.class);
+ AnimatorUpdateListener listener = mock(AnimatorUpdateListener.class);
+ doReturn(animator).when(mNotificationRow).getTranslateViewAnimator(0, listener);
+
+ assertEquals("returns the correct animator from super when view is an ENR", animator,
+ mSwipeHelper.getViewTranslationAnimator(mNotificationRow, 0, listener));
+
+ verify(mNotificationRow, times(1)).getTranslateViewAnimator(0, listener);
+ }
+
+ @Test
+ public void testSetTranslation() {
+ mSwipeHelper.setTranslation(mNotificationRow, 0);
+ verify(mNotificationRow, times(1)).setTranslation(0);
+ }
+
+ @Test
+ public void testGetTranslation() {
+ doReturn(30f).when(mNotificationRow).getTranslation();
+
+ assertEquals("Returns getTranslation for the ENR",
+ mSwipeHelper.getTranslation(mNotificationRow), 30f);
+
+ verify(mNotificationRow, times(1)).getTranslation();
+ }
+
+ @Test
+ public void testDismiss() {
+ doNothing().when(mSwipeHelper).dismissChild(mView, 0, true);
+ doReturn(false).when(mSwipeHelper).swipedFastEnough();
+
+ mSwipeHelper.dismiss(mView, 0);
+
+ verify(mSwipeHelper, times(1)).swipedFastEnough();
+ verify(mSwipeHelper, times(1)).dismissChild(mView, 0, true);
+ }
+
+ @Test
+ public void testSnapOpen() {
+ doNothing().when(mSwipeHelper).snapChild(mView, 30, 0);
+
+ mSwipeHelper.snapOpen(mView, 30, 0);
+
+ verify(mSwipeHelper, times(1)).snapChild(mView, 30, 0);
+ }
+
+ @Test
+ public void testSnapClosed() {
+ doNothing().when(mSwipeHelper).snapChild(mView, 0, 0);
+
+ mSwipeHelper.snapClosed(mView, 0);
+
+ verify(mSwipeHelper, times(1)).snapChild(mView, 0, 0);
+ }
+
+ @Test
+ public void testGetMinDismissVelocity() {
+ doReturn(30f).when(mSwipeHelper).getEscapeVelocity();
+
+ assertEquals("Returns getEscapeVelocity", 30f, mSwipeHelper.getMinDismissVelocity());
+ }
+
+ @Test
+ public void onMenuShown_noAntiFalsing() {
+ doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+ doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
+ doReturn(mHandler).when(mSwipeHelper).getHandler();
+ doReturn(false).when(mCallback).isAntiFalsingNeeded();
+ doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
+
+ mSwipeHelper.onMenuShown(mView);
+
+ verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mCallback, times(1)).isAntiFalsingNeeded();
+
+ verify(mHandler, times(0)).removeCallbacks(mFalsingCheck);
+ verify(mHandler, times(0)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
+ }
+
+ @Test
+ public void onMenuShown_antiFalsing() {
+ doNothing().when(mSwipeHelper).setExposedMenuView(mView);
+ doReturn(mView).when(mSwipeHelper).getTranslatingParentView();
+ doReturn(mHandler).when(mSwipeHelper).getHandler();
+ doReturn(true).when(mCallback).isAntiFalsingNeeded();
+ doReturn(mFalsingCheck).when(mSwipeHelper).getFalsingCheck();
+
+ mSwipeHelper.onMenuShown(mView);
+
+ verify(mSwipeHelper, times(1)).setExposedMenuView(mView);
+ verify(mCallback, times(1)).onDragCancelled(mView);
+ verify(mCallback, times(1)).isAntiFalsingNeeded();
+
+ verify(mHandler, times(1)).removeCallbacks(mFalsingCheck);
+ verify(mHandler, times(1)).postDelayed(mFalsingCheck, mSwipeHelper.COVER_MENU_DELAY);
+ }
+
+ @Test
+ public void testResetExposedMenuView_noReset() {
+ doReturn(false).when(mSwipeHelper).shouldResetMenu(false);
+ doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+ mSwipeHelper.resetExposedMenuView(false, false);
+
+ verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+ // should not clear exposed menu row
+ verify(mSwipeHelper, times(0)).clearExposedMenuView();
+ }
+
+ @Test
+ public void testResetExposedMenuView_animate() {
+ Animator animator = mock(Animator.class);
+
+ doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
+ doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
+ doReturn(false).when(mNotificationRow).isRemoved();
+ doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
+ doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+ mSwipeHelper.resetExposedMenuView(true, false);
+
+ verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+ // should retrieve and start animator
+ verify(mSwipeHelper, times(1)).getViewTranslationAnimator(mNotificationRow, 0, null);
+ verify(animator, times(1)).start();
+
+ // should not reset translation on row directly
+ verify(mNotificationRow, times(0)).resetTranslation();
+
+ // should clear exposed menu row
+ verify(mSwipeHelper, times(1)).clearExposedMenuView();
+ }
+
+
+ @Test
+ public void testResetExposedMenuView_noAnimate() {
+ Animator animator = mock(Animator.class);
+
+ doReturn(true).when(mSwipeHelper).shouldResetMenu(false);
+ doReturn(mNotificationRow).when(mSwipeHelper).getExposedMenuView();
+ doReturn(false).when(mNotificationRow).isRemoved();
+ doReturn(animator).when(mSwipeHelper).getViewTranslationAnimator(mNotificationRow, 0, null);
+ doNothing().when(mSwipeHelper).clearExposedMenuView();
+
+ mSwipeHelper.resetExposedMenuView(false, false);
+
+ verify(mSwipeHelper, times(1)).shouldResetMenu(false);
+
+ // should not retrieve and start animator
+ verify(mSwipeHelper, times(0)).getViewTranslationAnimator(mNotificationRow, 0, null);
+ verify(animator, times(0)).start();
+
+ // should reset translation on row directly
+ verify(mNotificationRow, times(1)).resetTranslation();
+
+ // should clear exposed menu row
+ verify(mSwipeHelper, times(1)).clearExposedMenuView();
+ }
+
+ @Test
+ public void testIsTouchInView() {
+ assertEquals("returns false when view is null", false,
+ NotificationSwipeHelper.isTouchInView(mEvent, null));
+
+ doReturn(5f).when(mEvent).getRawX();
+ doReturn(10f).when(mEvent).getRawY();
+
+ doReturn(20).when(mView).getWidth();
+ doReturn(20).when(mView).getHeight();
+
+ Answer answer = (Answer) invocation -> {
+ int[] arr = invocation.getArgument(0);
+ arr[0] = 0;
+ arr[1] = 0;
+ return null;
+ };
+ doAnswer(answer).when(mView).getLocationOnScreen(any());
+
+ assertTrue("Touch is within the view",
+ mSwipeHelper.isTouchInView(mEvent, mView));
+
+ doReturn(50f).when(mEvent).getRawX();
+
+ assertFalse("Touch is not within the view",
+ mSwipeHelper.isTouchInView(mEvent, mView));
+ }
+
+ @Test
+ public void testIsTouchInView_expandable() {
+ assertEquals("returns false when view is null", false,
+ NotificationSwipeHelper.isTouchInView(mEvent, null));
+
+ doReturn(5f).when(mEvent).getRawX();
+ doReturn(10f).when(mEvent).getRawY();
+
+ doReturn(20).when(mNotificationRow).getWidth();
+ doReturn(20).when(mNotificationRow).getActualHeight();
+
+ Answer answer = (Answer) invocation -> {
+ int[] arr = invocation.getArgument(0);
+ arr[0] = 0;
+ arr[1] = 0;
+ return null;
+ };
+ doAnswer(answer).when(mNotificationRow).getLocationOnScreen(any());
+
+ assertTrue("Touch is within the view",
+ mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
+
+ doReturn(50f).when(mEvent).getRawX();
+
+ assertFalse("Touch is not within the view",
+ mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 692f9cf..2fd699e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9431,9 +9431,10 @@
mBatteryStatsService.noteWakupAlarm(sourcePkg, sourceUid, workSource, tag);
if (workSource != null) {
- StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag);
+ StatsLog.write(StatsLog.WAKEUP_ALARM_OCCURRED, workSource, tag, sourcePkg);
} else {
- StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag);
+ StatsLog.write_non_chained(StatsLog.WAKEUP_ALARM_OCCURRED, sourceUid, null, tag,
+ sourcePkg);
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 0f68c68..87cf9c4 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -39,6 +39,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
@@ -156,9 +157,18 @@
} else if (mCurrentModality == BIOMETRIC_IRIS) {
Slog.w(TAG, "Unsupported modality");
} else if (mCurrentModality == BIOMETRIC_FACE) {
- mFaceService.authenticateFromService(true /* requireConfirmation */, token,
- sessionId, userId, receiver, flags, opPackageName, bundle,
- dialogReceiver, callingUid, callingPid, callingUserId);
+ // If the user disabled face for apps, return ERROR_HW_UNAVAILABLE
+ if (isFaceEnabledForApps()) {
+ receiver.onError(0 /* deviceId */,
+ BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ FaceManager.getErrorString(getContext(),
+ BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
+ } else {
+ mFaceService.authenticateFromService(true /* requireConfirmation */,
+ token, sessionId, userId, receiver, flags, opPackageName,
+ bundle, dialogReceiver, callingUid, callingPid, callingUserId);
+ }
} else {
Slog.w(TAG, "Unsupported modality");
}
@@ -168,6 +178,15 @@
});
}
+ private boolean isFaceEnabledForApps() {
+ // TODO: maybe cache this and eliminate duplicated code with KeyguardUpdateMonitor
+ return Settings.Secure.getIntForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_APP_ENABLED,
+ 1 /* default */,
+ UserHandle.USER_CURRENT) == 0;
+ }
+
@Override // Binder call
public void cancelAuthentication(IBinder token, String opPackageName)
throws RemoteException {
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 98c38dd..f6af52a 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -28,10 +28,11 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.IBiometricPromptReceiver;
-import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
+import android.hardware.biometrics.face.V1_0.Status;
import android.hardware.face.Face;
import android.hardware.face.FaceManager;
import android.hardware.face.IFaceService;
@@ -121,15 +122,15 @@
* The following methods contain common code which is shared in biometrics/common.
*/
@Override // Binder call
- public long preEnroll(IBinder token) {
+ public long generateChallenge(IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
- return startPreEnroll(token);
+ return startGenerateChallenge(token);
}
@Override // Binder call
- public int postEnroll(IBinder token) {
+ public int revokeChallenge(IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
- return startPostEnroll(token);
+ return startRevokeChallenge(token);
}
@Override // Binder call
@@ -346,6 +347,45 @@
// TODO: confirm security token when we move timeout management into the HAL layer.
mHandler.post(mResetFailedAttemptsForCurrentUserRunnable);
}
+
+ @Override
+ public int setRequireAttention(boolean requireAttention, final byte[] token) {
+ checkPermission(MANAGE_BIOMETRIC);
+
+ final ArrayList<Byte> byteToken = new ArrayList<>();
+ for (int i = 0; i < token.length; i++) {
+ byteToken.add(token[i]);
+ }
+
+ int result;
+ try {
+ result = mDaemon != null ? mDaemon.setRequireAttention(requireAttention, byteToken)
+ : Status.INTERNAL_ERROR;
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to setRequireAttention to " + requireAttention);
+ result = Status.INTERNAL_ERROR;
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean getRequireAttention(final byte[] token) {
+ checkPermission(MANAGE_BIOMETRIC);
+
+ final ArrayList<Byte> byteToken = new ArrayList<>();
+ for (int i = 0; i < token.length; i++) {
+ byteToken.add(token[i]);
+ }
+
+ boolean result = true;
+ try {
+ result = mDaemon != null ? mDaemon.getRequireAttention(byteToken).value : true;
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to getRequireAttention");
+ }
+ return result;
+ }
}
/**
@@ -779,30 +819,30 @@
return mDaemon;
}
- private long startPreEnroll(IBinder token) {
+ private long startGenerateChallenge(IBinder token) {
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
- Slog.w(TAG, "startPreEnroll: no face HAL!");
+ Slog.w(TAG, "startGenerateChallenge: no face HAL!");
return 0;
}
try {
return daemon.generateChallenge(CHALLENGE_TIMEOUT_SEC).value;
} catch (RemoteException e) {
- Slog.e(TAG, "startPreEnroll failed", e);
+ Slog.e(TAG, "startGenerateChallenge failed", e);
}
return 0;
}
- private int startPostEnroll(IBinder token) {
+ private int startRevokeChallenge(IBinder token) {
IBiometricsFace daemon = getFaceDaemon();
if (daemon == null) {
- Slog.w(TAG, "startPostEnroll: no face HAL!");
+ Slog.w(TAG, "startRevokeChallenge: no face HAL!");
return 0;
}
try {
return daemon.revokeChallenge();
} catch (RemoteException e) {
- Slog.e(TAG, "startPostEnroll failed", e);
+ Slog.e(TAG, "startRevokeChallenge failed", e);
}
return 0;
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index d8d650b..5698fdf 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1226,7 +1226,7 @@
if (userId == UserHandle.USER_ALL) {
mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri);
} else if (userId < 0) {
throw new IllegalArgumentException("Invalid user: " + userId);
} else if (userId != UserHandle.getCallingUserId()) {
@@ -1247,7 +1247,7 @@
? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
Manifest.permission.INTERACT_ACROSS_USERS)
: Manifest.permission.INTERACT_ACROSS_USERS_FULL;
- throw new SecurityException(TAG + "Neither user " + uid
+ throw new SecurityException("No access to " + uri + ": neither user " + uid
+ " nor current process has " + permissions);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e10827b..10980b7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16004,7 +16004,8 @@
}
if (apkPath != null) {
final VerityUtils.SetupResult result =
- VerityUtils.generateApkVeritySetupData(apkPath);
+ VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */,
+ true /* skipSigningBlock */);
if (result.isOk()) {
if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
FileDescriptor fd = result.getUnownedFileDescriptor();
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 9f69702..3796610 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -26,42 +26,76 @@
import android.util.Pair;
import android.util.Slog;
import android.util.apk.ApkSignatureVerifier;
+import android.util.apk.ApkVerityBuilder;
import android.util.apk.ByteBufferFactory;
import android.util.apk.SignatureNotFoundException;
+import libcore.util.HexEncoding;
+
import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.DigestException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
+import sun.security.pkcs.PKCS7;
+
/** Provides fsverity related operations. */
abstract public class VerityUtils {
private static final String TAG = "VerityUtils";
+ /** The maximum size of signature file. This is just to avoid potential abuse. */
+ private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192;
+
private static final boolean DEBUG = false;
/**
- * Generates Merkle tree and fsverity metadata.
+ * Generates Merkle tree and fs-verity metadata.
*
- * @return {@code SetupResult} that contains the {@code EsetupResultCode}, and when success, the
+ * @return {@code SetupResult} that contains the result code, and when success, the
* {@code FileDescriptor} to read all the data from.
*/
- public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) {
- if (DEBUG) Slog.d(TAG, "Trying to install apk verity to " + apkPath);
+ public static SetupResult generateApkVeritySetupData(@NonNull String apkPath,
+ String signaturePath, boolean skipSigningBlock) {
+ if (DEBUG) {
+ Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file "
+ + signaturePath);
+ }
SharedMemory shm = null;
try {
- byte[] signedRootHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
- if (signedRootHash == null) {
+ byte[] signedVerityHash;
+ if (skipSigningBlock) {
+ signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
+ } else {
+ Path path = Paths.get(signaturePath);
+ if (Files.exists(path)) {
+ // TODO(112037636): fail early if the signing key is not in .fs-verity keyring.
+ PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path));
+ signedVerityHash = pkcs7.getContentInfo().getContentBytes();
+ if (DEBUG) {
+ Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash));
+ }
+ } else {
+ signedVerityHash = null;
+ }
+ }
+
+ if (signedVerityHash == null) {
if (DEBUG) {
- Slog.d(TAG, "Skip verity tree generation since there is no root hash");
+ Slog.d(TAG, "Skip verity tree generation since there is no signed root hash");
}
return SetupResult.skipped();
}
- Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath,
- signedRootHash);
+ Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath,
+ signaturePath, signedVerityHash, skipSigningBlock);
shm = result.first;
int contentSize = result.second;
FileDescriptor rfd = shm.getFileDescriptor();
@@ -97,22 +131,114 @@
}
/**
+ * Generates fs-verity metadata for {@code filePath} in the buffer created by {@code
+ * trackedBufferFactory}. The metadata contains the Merkle tree, fs-verity descriptor and
+ * extensions, including a PKCS#7 signature provided in {@code signaturePath}.
+ *
+ * <p>It is worthy to note that {@code trackedBufferFactory} generates a "tracked" {@code
+ * ByteBuffer}. The data will be used outside this method via the factory itself.
+ *
+ * @return fs-verity measurement of {@code filePath}, which is a SHA-256 of fs-verity descriptor
+ * and authenticated extensions.
+ */
+ private static byte[] generateFsverityMetadata(String filePath, String signaturePath,
+ @NonNull TrackedShmBufferFactory trackedBufferFactory)
+ throws IOException, SignatureNotFoundException, SecurityException, DigestException,
+ NoSuchAlgorithmException {
+ try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) {
+ ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateFsVerityTree(
+ file, trackedBufferFactory);
+
+ ByteBuffer buffer = result.verityData;
+ buffer.position(result.merkleTreeSize);
+ return generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath,
+ buffer);
+ }
+ }
+
+ /**
+ * Generates fs-verity descriptor including the extensions to the {@code output} and returns the
+ * fs-verity measurement.
+ *
+ * @return fs-verity measurement, which is a SHA-256 of fs-verity descriptor and authenticated
+ * extensions.
+ */
+ private static byte[] generateFsverityDescriptorAndMeasurement(
+ @NonNull RandomAccessFile file, @NonNull byte[] rootHash,
+ @NonNull String pkcs7SignaturePath, @NonNull ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ final short kRootHashExtensionId = 1;
+ final short kPkcs7SignatureExtensionId = 3;
+ final int origPosition = output.position();
+
+ // For generating fs-verity file measurement, which consists of the descriptor and
+ // authenticated extensions (but not unauthenticated extensions and the footer).
+ MessageDigest md = MessageDigest.getInstance("SHA-256");
+
+ // 1. Generate fs-verity descriptor.
+ final byte[] desc = constructFsverityDescriptorNative(file.length());
+ output.put(desc);
+ md.update(desc);
+
+ // 2. Generate authenticated extensions.
+ final byte[] authExt =
+ constructFsverityExtensionNative(kRootHashExtensionId, rootHash.length);
+ output.put(authExt);
+ output.put(rootHash);
+ md.update(authExt);
+ md.update(rootHash);
+
+ // 3. Generate unauthenticated extensions.
+ ByteBuffer header = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
+ output.putShort((short) 1); // number of unauthenticated extensions below
+ output.position(output.position() + 6);
+
+ // Generate PKCS#7 extension. NB: We do not verify agaist trusted certificate (should be
+ // done by the caller if needed).
+ Path path = Paths.get(pkcs7SignaturePath);
+ if (Files.size(path) > MAX_SIGNATURE_FILE_SIZE_BYTES) {
+ throw new IllegalArgumentException("Signature size is unexpectedly large: "
+ + pkcs7SignaturePath);
+ }
+ final byte[] pkcs7Signature = Files.readAllBytes(path);
+ output.put(constructFsverityExtensionNative(kPkcs7SignatureExtensionId,
+ pkcs7Signature.length));
+ output.put(pkcs7Signature);
+
+ // 4. Generate the footer.
+ output.put(constructFsverityFooterNative(output.position() - origPosition));
+
+ return md.digest();
+ }
+
+ private static native byte[] constructFsverityDescriptorNative(long fileSize);
+ private static native byte[] constructFsverityExtensionNative(short extensionId,
+ int extensionDataSize);
+ private static native byte[] constructFsverityFooterNative(int offsetToDescriptorHead);
+
+ /**
* Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains
* Merkle tree and fsverity headers for the given apk, in the form that can immediately be used
* for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has
* length equals to the returned {@code Integer}.
*/
- private static Pair<SharedMemory, Integer> generateApkVerityIntoSharedMemory(
- String apkPath, byte[] expectedRootHash)
+ private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(
+ String apkPath, String signaturePath, @NonNull byte[] expectedRootHash,
+ boolean skipSigningBlock)
throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,
SignatureNotFoundException {
TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory();
- byte[] generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath,
- shmBufferFactory);
+ byte[] generatedRootHash;
+ if (skipSigningBlock) {
+ generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
+ } else {
+ generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory);
+ }
// We only generate Merkle tree once here, so it's important to make sure the root hash
// matches the signed one in the apk.
if (!Arrays.equals(expectedRootHash, generatedRootHash)) {
- throw new SecurityException("Locally generated verity root hash does not match");
+ throw new SecurityException("verity hash mismatch: "
+ + bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash));
}
int contentSize = shmBufferFactory.getBufferLimit();
@@ -126,11 +252,15 @@
return Pair.create(shm, contentSize);
}
+ private static String bytesToString(byte[] bytes) {
+ return HexEncoding.encodeToString(bytes);
+ }
+
public static class SetupResult {
/** Result code if verity is set up correctly. */
private static final int RESULT_OK = 1;
- /** Result code if the apk does not contain a verity root hash. */
+ /** Result code if signature is not provided. */
private static final int RESULT_SKIPPED = 2;
/** Result code if the setup failed. */
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 1eae567..e718c7b 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -20,8 +20,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
-
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
@@ -48,16 +48,13 @@
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.input.InputWindowHandle;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.InsetUtils;
-
import com.google.android.collect.Sets;
-
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -93,6 +90,7 @@
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mTargetAppToken;
+ private int mTargetActivityType;
private Rect mMinimizedHomeBounds = new Rect();
// We start the RecentsAnimationController in a pending-start state since we need to wait for
@@ -259,23 +257,37 @@
mDisplayId = displayId;
}
+ public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
+ initialize(mService.mRoot.getDisplayContent(mDisplayId), targetActivityType, recentTaskIds);
+ }
+
/**
* Initializes the recents animation controller. This is a separate call from the constructor
* because it may call cancelAnimation() which needs to properly clean up the controller
* in the window manager.
*/
- public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
- // Make leashes for each of the visible tasks and add it to the recents animation to be
- // started
- final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+ @VisibleForTesting
+ void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
+ mTargetActivityType = targetActivityType;
+
+ // Make leashes for each of the visible/target tasks and add it to the recents animation to
+ // be started
final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
+ final TaskStack targetStack = dc.getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
+ if (targetStack != null) {
+ for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
+ final Task t = targetStack.getChildAt(i);
+ if (!visibleTasks.contains(t)) {
+ visibleTasks.add(t);
+ }
+ }
+ }
final int taskCount = visibleTasks.size();
for (int i = 0; i < taskCount; i++) {
final Task task = visibleTasks.get(i);
final WindowConfiguration config = task.getWindowConfiguration();
if (config.tasksAreFloating()
- || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || config.getActivityType() == targetActivityType) {
+ || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
continue;
}
addAnimation(task, !recentTaskIds.get(task.mTaskId));
@@ -586,7 +598,10 @@
final Rect insets = new Rect();
mainWindow.getContentInsets(insets);
InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
- mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
+ final int mode = topApp.getActivityType() == mTargetActivityType
+ ? MODE_OPENING
+ : MODE_CLOSING;
+ mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
!topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cc23ab6..6aa0e01 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -561,9 +561,10 @@
@Override
public SurfaceControl getAnimationLeashParent() {
- // Reparent to the animation layer so that we aren't clipped by the non-minimized
- // stack bounds, currently we only animate the task for the recents animation
- return getAppAnimationLayer(ANIMATION_LAYER_STANDARD);
+ // Currently, only the recents animation will create animation leashes for tasks. In this
+ // case, reparent the task to the home animation layer while it is being animated to allow
+ // the home activity to reorder the app windows relative to its own.
+ return getAppAnimationLayer(ANIMATION_LAYER_HOME);
}
boolean isTaskAnimating() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e860939..4883f97 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -42,10 +42,8 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
-
import com.android.internal.util.ToBooleanFunction;
import com.android.server.wm.SurfaceAnimator.Animatable;
-
import java.io.PrintWriter;
import java.util.Comparator;
import java.util.LinkedList;
@@ -71,7 +69,8 @@
/**
* Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
- * activities that happens below all {@link TaskStack}s.
+ * activities and all activities that are being controlled by the recents animation. This
+ * layer is generally below all {@link TaskStack}s.
*/
static final int ANIMATION_LAYER_HOME = 2;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7caa7ae..b627df4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -227,6 +227,7 @@
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -2714,6 +2715,11 @@
}
}
+ @VisibleForTesting
+ void setRecentsAnimationController(RecentsAnimationController controller) {
+ mRecentsAnimationController = controller;
+ }
+
public RecentsAnimationController getRecentsAnimationController() {
return mRecentsAnimationController;
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index becde73..061f8e2 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -37,6 +37,7 @@
"com_android_server_locksettings_SyntheticPasswordManager.cpp",
"com_android_server_net_NetworkStatsService.cpp",
"com_android_server_power_PowerManagerService.cpp",
+ "com_android_server_security_VerityUtils.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
"com_android_server_SystemServer.cpp",
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
new file mode 100644
index 0000000..d0f173b
--- /dev/null
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VerityUtils"
+
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+#include <utils/Log.h>
+
+#include <string.h>
+
+// TODO(112037636): Always include once fsverity.h is upstreamed and backported.
+#define HAS_FSVERITY 0
+
+#if HAS_FSVERITY
+#include <linux/fsverity.h>
+#endif
+
+namespace android {
+
+namespace {
+
+class JavaByteArrayHolder {
+ public:
+ static JavaByteArrayHolder* newArray(JNIEnv* env, jsize size) {
+ return new JavaByteArrayHolder(env, size);
+ }
+
+ jbyte* getRaw() {
+ return mElements;
+ }
+
+ jbyteArray release() {
+ mEnv->ReleaseByteArrayElements(mBytes, mElements, 0);
+ mElements = nullptr;
+ return mBytes;
+ }
+
+ private:
+ JavaByteArrayHolder(JNIEnv* env, jsize size) {
+ mEnv = env;
+ mBytes = mEnv->NewByteArray(size);
+ mElements = mEnv->GetByteArrayElements(mBytes, nullptr);
+ memset(mElements, 0, size);
+ }
+
+ virtual ~JavaByteArrayHolder() {
+ LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released");
+ }
+
+ JNIEnv* mEnv;
+ jbyteArray mBytes;
+ jbyte* mElements;
+};
+
+jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) {
+#if HAS_FSVERITY
+ auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor));
+ fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw());
+
+ memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic));
+ desc->major_version = 1;
+ desc->minor_version = 0;
+ desc->log_data_blocksize = 12;
+ desc->log_tree_blocksize = 12;
+ desc->data_algorithm = FS_VERITY_ALG_SHA256;
+ desc->tree_algorithm = FS_VERITY_ALG_SHA256;
+ desc->flags = 0;
+ desc->orig_file_size = fileSize;
+ desc->auth_ext_count = 1;
+
+ return raii->release();
+#else
+ LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+ return 0;
+#endif // HAS_FSVERITY
+}
+
+jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId,
+ jint extensionDataSize) {
+#if HAS_FSVERITY
+ auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension));
+ fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw());
+
+ ext->length = sizeof(fsverity_extension) + extensionDataSize;
+ ext->type = extensionId;
+
+ return raii->release();
+#else
+ LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+ return 0;
+#endif // HAS_FSVERITY
+}
+
+jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */,
+ jint offsetToDescriptorHead) {
+#if HAS_FSVERITY
+ auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer));
+ fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw());
+
+ footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer);
+ memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic));
+
+ return raii->release();
+#else
+ LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
+ return 0;
+#endif // HAS_FSVERITY
+}
+
+const JNINativeMethod sMethods[] = {
+ { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
+ { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension },
+ { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter },
+};
+
+} // namespace
+
+int register_android_server_security_VerityUtils(JNIEnv* env) {
+ return jniRegisterNativeMethods(env,
+ "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index bb6e684..918f57e 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -54,6 +54,7 @@
int register_android_server_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
+int register_android_server_security_VerityUtils(JNIEnv* env);
};
using namespace android;
@@ -101,5 +102,6 @@
register_android_server_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_android_server_net_NetworkStatsService(env);
+ register_android_server_security_VerityUtils(env);
return JNI_VERSION_1_4;
}
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
index f7bf393..5a73a4e 100644
--- a/services/net/java/android/net/util/SharedLog.java
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -17,6 +17,7 @@
package android.net.util;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
@@ -92,10 +93,17 @@
}
/**
- * Log an error due to an exception, with the exception stacktrace.
+ * Log an error due to an exception, with the exception stacktrace if provided.
+ *
+ * <p>The error and exception message appear in the shared log, but the stacktrace is only
+ * logged in general log output (logcat).
*/
- public void e(@NonNull String msg, @NonNull Throwable e) {
- Log.e(mTag, record(Category.ERROR, msg + ": " + e.getMessage()), e);
+ public void e(@NonNull String msg, @Nullable Throwable exception) {
+ if (exception == null) {
+ e(msg);
+ return;
+ }
+ Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception);
}
public void i(String msg) {
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportData.java b/services/robotests/src/com/android/server/backup/testing/TransportData.java
index 4c67180..77f5d9a4 100644
--- a/services/robotests/src/com/android/server/backup/testing/TransportData.java
+++ b/services/robotests/src/com/android/server/backup/testing/TransportData.java
@@ -48,9 +48,9 @@
public static TransportData localTransport() {
return new TransportData(
- "android/com.android.internal.backup.LocalTransport",
- "android/com.android.internal.backup.LocalTransportService",
- "com.android.internal.backup.LocalTransport",
+ "com.android.localtransport/.LocalTransport",
+ "com.android.localtransport/.LocalTransportService",
+ "com.android.localtransport.LocalTransport",
null,
"Backing up to debug-only private cache",
null,
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index e7c45d5..aaa00452 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -24,6 +25,8 @@
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static org.junit.Assert.fail;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
@@ -33,6 +36,7 @@
import android.os.Binder;
import android.os.IInterface;
import android.platform.test.annotations.Presubmit;
+import android.util.SparseBooleanArray;
import android.view.IRecentsAnimationRunner;
import android.view.SurfaceControl;
@@ -109,6 +113,24 @@
}
}
+ @Test
+ public void testIncludedApps_expectTargetAndVisible() throws Exception {
+ sWm.setRecentsAnimationController(mController);
+ final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ hiddenAppWindow.setHidden(true);
+ mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+
+ // Ensure that we are animating the target activity as well
+ assertTrue(mController.isAnimatingTask(homeAppWindow.getTask()));
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+ assertFalse(mController.isAnimatingTask(hiddenAppWindow.getTask()));
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);
diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java
index 7c7d7a0..202da68 100644
--- a/telephony/java/android/telephony/NetworkScan.java
+++ b/telephony/java/android/telephony/NetworkScan.java
@@ -16,11 +16,10 @@
package android.telephony;
+import android.annotation.IntDef;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.annotation.IntDef;
-import android.util.Log;
import com.android.internal.telephony.ITelephony;
@@ -113,6 +112,8 @@
}
try {
telephony.stopNetworkScan(mSubId, mScanId);
+ } catch (IllegalArgumentException ex) {
+ Rlog.d(TAG, "stopNetworkScan - no active scan for ScanID=" + mScanId);
} catch (RemoteException ex) {
Rlog.e(TAG, "stopNetworkScan RemoteException", ex);
} catch (RuntimeException ex) {
diff --git a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
index ae011a0..c86f06e 100644
--- a/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
+++ b/tests/NativeProcessesMemoryTest/src/com/android/tests/nativeprocesses/NativeProcessesMemoryTest.java
@@ -21,6 +21,7 @@
import com.android.tradefed.result.ByteArrayInputStreamSource;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestDescription;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
@@ -84,7 +85,10 @@
// showmap requires root, we enable it here for the rest of the test
mTestDevice.enableAdbRoot();
- listener.testRunStarted(RUN_NAME, 0 /* testCount */);
+ listener.testRunStarted(RUN_NAME, 1 /* testCount */);
+
+ TestDescription testDescription = new TestDescription(getClass().getName(), "run");
+ listener.testStarted(testDescription);
// process name -> list of pids with that name
Map<String, List<String>> nativeProcesses = collectNativeProcesses();
@@ -94,7 +98,8 @@
mNativeProcessToMemory.put(
NUM_NATIVE_PROCESSES_KEY, Integer.toString(nativeProcesses.size()));
- listener.testRunEnded(0, mNativeProcessToMemory);
+ listener.testEnded(testDescription, mNativeProcessToMemory);
+ listener.testRunEnded(0, new HashMap<String, String>());
}
/** Samples memory of all processes and logs the memory use. */
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
index d46facf..8604860 100644
--- a/tests/net/java/android/net/util/SharedLogTest.java
+++ b/tests/net/java/android/net/util/SharedLogTest.java
@@ -44,6 +44,8 @@
final SharedLog logLevel2a = logTop.forSubComponent("twoA");
final SharedLog logLevel2b = logTop.forSubComponent("twoB");
logLevel2b.e("2b or not 2b");
+ logLevel2b.e("No exception", null);
+ logLevel2b.e("Wait, here's one", new Exception("Test"));
logLevel2a.w("second post?");
final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
@@ -54,6 +56,9 @@
final String[] expected = {
" - MARK first post!",
" - [twoB] ERROR 2b or not 2b",
+ " - [twoB] ERROR No exception",
+ // No stacktrace in shared log, only in logcat
+ " - [twoB] ERROR Wait, here's one: Test",
" - [twoA] WARN second post?",
" - still logging",
" - [twoA.three] 3 >> 2",
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e3db7e8..fceaabd 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -79,6 +79,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -248,7 +249,7 @@
@Spy private Resources mResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
- MockContext(Context base) {
+ MockContext(Context base, ContentProvider settingsProvider) {
super(base);
mResources = spy(base.getResources());
@@ -260,7 +261,7 @@
});
mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
}
@Override
@@ -1048,7 +1049,9 @@
Looper.prepare();
}
- mServiceContext = new MockContext(InstrumentationRegistry.getContext());
+ FakeSettingsProvider.clearSettingsProvider();
+ mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
+ new FakeSettingsProvider());
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
@@ -1086,6 +1089,7 @@
mEthernetNetworkAgent.disconnect();
mEthernetNetworkAgent = null;
}
+ FakeSettingsProvider.clearSettingsProvider();
}
private static int transportToLegacyType(int transport) {
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 9915479..56c8428 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -234,9 +234,11 @@
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
- "const std::map<int, char const*>& arg%d_2, "
- "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -302,6 +304,13 @@
fprintf(out, " event.end();\n");
fprintf(out, " }\n");
+ fprintf(out, " for (const auto& it : arg%d_4) {\n", argIndex);
+ fprintf(out, " event.begin();\n");
+ fprintf(out, " event << it.first;\n");
+ fprintf(out, " event << it.second;\n");
+ fprintf(out, " event.end();\n");
+ fprintf(out, " }\n");
+
fprintf(out, " event.end();\n\n");
} else {
if (*arg == JAVA_TYPE_STRING) {
@@ -344,9 +353,11 @@
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
- "const std::map<int, char const*>& arg%d_2, "
- "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -374,7 +385,8 @@
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", arg%d_1, arg%d_2, arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", arg%d", argIndex);
}
@@ -529,10 +541,14 @@
}
}
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& %s_int"
+ fprintf(out, ", const std::map<int, int32_t>& %s_int"
+ ", const std::map<int, int64_t>& %s_long"
", const std::map<int, char const*>& %s_str"
", const std::map<int, float>& %s_float",
- field->name.c_str(), field->name.c_str(), field->name.c_str());
+ field->name.c_str(),
+ field->name.c_str(),
+ field->name.c_str(),
+ field->name.c_str());
} else {
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
}
@@ -561,9 +577,11 @@
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
- "const std::map<int, char const*>& arg%d_2, "
- "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
+ fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -976,6 +994,7 @@
}
static void write_key_value_map_jni(FILE* out) {
+ fprintf(out, " std::map<int, int32_t> int32_t_map;\n");
fprintf(out, " std::map<int, int64_t> int64_t_map;\n");
fprintf(out, " std::map<int, float> float_map;\n");
fprintf(out, " std::map<int, char const*> string_map;\n\n");
@@ -989,9 +1008,11 @@
fprintf(out, " std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");
+ fprintf(out, " jclass jint_class = env->FindClass(\"java/lang/Integer\");\n");
fprintf(out, " jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
fprintf(out, " jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
fprintf(out, " jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
+ fprintf(out, " jmethodID jget_int_method = env->GetMethodID(jint_class, \"intValue\", \"()I\");\n");
fprintf(out, " jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
fprintf(out, " jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");
@@ -1000,7 +1021,9 @@
fprintf(out, " jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
fprintf(out, " jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
fprintf(out, " if (jvalue_obj == NULL) { continue; }\n");
- fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
+ fprintf(out, " if (env->IsInstanceOf(jvalue_obj, jint_class)) {\n");
+ fprintf(out, " int32_t_map[key] = env->CallIntMethod(jvalue_obj, jget_int_method);\n");
+ fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
fprintf(out, " int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
fprintf(out, " } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
fprintf(out, " float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
@@ -1129,7 +1152,7 @@
}
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", int64_t_map, string_map, float_map");
+ fprintf(out, ", int32_t_map, int64_t_map, string_map, float_map");
} else {
const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ce8d71d..58c1300 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -332,9 +332,10 @@
public String preSharedKey;
/**
- * Up to four WEP keys. Either an ASCII string enclosed in double
- * quotation marks (e.g., {@code "abcdef"}) or a string
- * of hex digits (e.g., {@code 0102030405}).
+ * Four WEP keys. For each of the four values, provide either an ASCII
+ * string enclosed in double quotation marks (e.g., {@code "abcdef"}),
+ * a string of hex digits (e.g., {@code 0102030405}), or an empty string
+ * (e.g., {@code ""}).
* <p/>
* When the value of one of these keys is read, the actual key is
* not returned, just a "*" if the key has a value, or the null