Merge changes Ia5accb74,Ic4d7def4,I30bd56fc into sc-v2-dev
* changes:
Change DialogLaunchAnimator X-axis interpolator
Extract interpolators and durations out of LaunchAnimator
Synchronize dialog launch animation using BLAST
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index fca4c69..3712caed 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1488,18 +1488,27 @@
mContext.getUserId());
if (fd != null) {
FileOutputStream fos = null;
- boolean ok = false;
+ final Bitmap tmp = BitmapFactory.decodeStream(resources.openRawResource(resid));
try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
- // The 'close()' is the trigger for any server-side image manipulation,
- // so we must do that before waiting for completion.
- fos.close();
- completion.waitForCompletion();
+ // If the stream can't be decoded, treat it as an invalid input.
+ if (tmp != null) {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ tmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ // The 'close()' is the trigger for any server-side image manipulation,
+ // so we must do that before waiting for completion.
+ fos.close();
+ completion.waitForCompletion();
+ } else {
+ throw new IllegalArgumentException(
+ "Resource 0x" + Integer.toHexString(resid) + " is invalid");
+ }
} finally {
// Might be redundant but completion shouldn't wait unless the write
// succeeded; this is a fallback if it threw past the close+wait.
IoUtils.closeQuietly(fos);
+ if (tmp != null) {
+ tmp.recycle();
+ }
}
}
} catch (RemoteException e) {
@@ -1741,13 +1750,22 @@
result, which, completion, mContext.getUserId());
if (fd != null) {
FileOutputStream fos = null;
+ final Bitmap tmp = BitmapFactory.decodeStream(bitmapData);
try {
- fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- copyStreamToWallpaperFile(bitmapData, fos);
- fos.close();
- completion.waitForCompletion();
+ // If the stream can't be decoded, treat it as an invalid input.
+ if (tmp != null) {
+ fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
+ tmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ fos.close();
+ completion.waitForCompletion();
+ } else {
+ throw new IllegalArgumentException("InputStream is invalid");
+ }
} finally {
IoUtils.closeQuietly(fos);
+ if (tmp != null) {
+ tmp.recycle();
+ }
}
}
} catch (RemoteException e) {
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 046232a..2dac81c 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -129,7 +129,11 @@
* The index of the element in the tree in prefix order. This should be used for z-layering
* to preserve original z-layer order in the hierarchy tree assuming no "boosting" needs to
* happen.
+ * @deprecated WindowManager may set a z-order different from the prefix order, and has set the
+ * correct layer for the animation leash already, so this should not be used for
+ * layer any more.
*/
+ @Deprecated
@UnsupportedAppUsage
public final int prefixOrderIndex;
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 424632fe..6541b14 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -270,8 +270,6 @@
private Drawable mCaptionBackgroundDrawable;
private Drawable mUserCaptionBackgroundDrawable;
- private float mAvailableWidth;
-
String mLogTag = TAG;
private final Rect mFloatingInsets = new Rect();
private boolean mApplyFloatingVerticalInsets = false;
@@ -315,8 +313,6 @@
mSemiTransparentBarColor = context.getResources().getColor(
R.color.system_bar_background_semi_transparent, null /* theme */);
- updateAvailableWidth();
-
setWindow(window);
updateLogTag(params);
@@ -697,7 +693,8 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+ final Resources res = getContext().getResources();
+ final DisplayMetrics metrics = res.getDisplayMetrics();
final boolean isPortrait =
getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
@@ -767,17 +764,19 @@
if (!fixedWidth && widthMode == AT_MOST) {
final TypedValue tv = isPortrait ? mWindow.mMinWidthMinor : mWindow.mMinWidthMajor;
+ final float availableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ res.getConfiguration().screenWidthDp, metrics);
if (tv.type != TypedValue.TYPE_NULL) {
final int min;
if (tv.type == TypedValue.TYPE_DIMENSION) {
- min = (int)tv.getDimension(metrics);
+ min = (int) tv.getDimension(metrics);
} else if (tv.type == TypedValue.TYPE_FRACTION) {
- min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth);
+ min = (int) tv.getFraction(availableWidth, availableWidth);
} else {
min = 0;
}
if (DEBUG_MEASURE) Log.d(mLogTag, "Adjust for min width: " + min + ", value::"
- + tv.coerceToString() + ", mAvailableWidth=" + mAvailableWidth);
+ + tv.coerceToString() + ", mAvailableWidth=" + availableWidth);
if (width < min) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
@@ -2144,7 +2143,6 @@
updateDecorCaptionStatus(newConfig);
- updateAvailableWidth();
initializeElevation();
}
@@ -2616,12 +2614,6 @@
mLogTag = TAG + "[" + getTitleSuffix(params) + "]";
}
- private void updateAvailableWidth() {
- Resources res = getResources();
- mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
- }
-
/**
* @hide
*/
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index d17c328..446e580 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -384,7 +384,16 @@
return base::unexpected(IOError::PAGES_MISSING);
}
- auto offset = dtohl(entry_offset_ptr.value());
+ uint32_t offset;
+ uint16_t res_idx;
+ if (type->flags & ResTable_type::FLAG_SPARSE) {
+ auto sparse_entry = entry_offset_ptr.convert<ResTable_sparseTypeEntry>();
+ offset = dtohs(sparse_entry->offset) * 4u;
+ res_idx = dtohs(sparse_entry->idx);
+ } else {
+ offset = dtohl(entry_offset_ptr.value());
+ res_idx = entry_idx;
+ }
if (offset != ResTable_type::NO_ENTRY) {
auto entry = type.offset(dtohl(type->entriesStart) + offset).convert<ResTable_entry>();
if (!entry) {
@@ -394,7 +403,7 @@
if (dtohl(entry->key.index) == static_cast<uint32_t>(*key_idx)) {
// The package ID will be overridden by the caller (due to runtime assignment of package
// IDs for shared libraries).
- return make_resid(0x00, *type_idx + type_id_offset_ + 1, entry_idx);
+ return make_resid(0x00, *type_idx + type_id_offset_ + 1, res_idx);
}
}
}
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index f356c8130..d214e2d 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -95,6 +95,38 @@
ASSERT_TRUE(LoadedPackage::GetEntry(type.type, entry_index).has_value());
}
+TEST(LoadedArscTest, FindSparseEntryApp) {
+ std::string contents;
+ ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
+ &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
+ ASSERT_THAT(loaded_arsc, NotNull());
+
+ const LoadedPackage* package =
+ loaded_arsc->GetPackageById(get_package_id(sparse::R::string::only_v26));
+ ASSERT_THAT(package, NotNull());
+
+ const uint8_t type_index = get_type_id(sparse::R::string::only_v26) - 1;
+ const uint16_t entry_index = get_entry_id(sparse::R::string::only_v26);
+
+ const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
+ ASSERT_THAT(type_spec, NotNull());
+ ASSERT_THAT(type_spec->type_entries.size(), Ge(1u));
+
+ // Ensure that AAPT2 sparsely encoded the v26 config as expected.
+ auto type_entry = std::find_if(
+ type_spec->type_entries.begin(), type_spec->type_entries.end(),
+ [](const TypeSpec::TypeEntry& x) { return x.config.sdkVersion == 26; });
+ ASSERT_NE(type_entry, type_spec->type_entries.end());
+ ASSERT_NE(type_entry->type->flags & ResTable_type::FLAG_SPARSE, 0);
+
+ // Test fetching a resource with only sparsely encoded configs by name.
+ auto id = package->FindEntryByName(u"string", u"only_v26");
+ ASSERT_EQ(id.value(), fix_package_id(sparse::R::string::only_v26, 0));
+}
+
TEST(LoadedArscTest, LoadSharedLibrary) {
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
diff --git a/libs/androidfw/tests/data/sparse/R.h b/libs/androidfw/tests/data/sparse/R.h
index 243e74f..2492dbf 100644
--- a/libs/androidfw/tests/data/sparse/R.h
+++ b/libs/androidfw/tests/data/sparse/R.h
@@ -27,21 +27,22 @@
struct integer {
enum : uint32_t {
foo_0 = 0x7f010000,
- foo_1 = 0x7f010000,
- foo_2 = 0x7f010000,
- foo_3 = 0x7f010000,
- foo_4 = 0x7f010000,
- foo_5 = 0x7f010000,
- foo_6 = 0x7f010000,
- foo_7 = 0x7f010000,
- foo_8 = 0x7f010000,
- foo_9 = 0x7f010000,
+ foo_1 = 0x7f010001,
+ foo_2 = 0x7f010002,
+ foo_3 = 0x7f010003,
+ foo_4 = 0x7f010004,
+ foo_5 = 0x7f010005,
+ foo_6 = 0x7f010006,
+ foo_7 = 0x7f010007,
+ foo_8 = 0x7f010008,
+ foo_9 = 0x7f010009,
};
};
struct string {
enum : uint32_t {
foo_999 = 0x7f0203e7,
+ only_v26 = 0x7f0203e8
};
};
};
diff --git a/libs/androidfw/tests/data/sparse/gen_strings.sh b/libs/androidfw/tests/data/sparse/gen_strings.sh
index e7e1d60..4ea5468 100755
--- a/libs/androidfw/tests/data/sparse/gen_strings.sh
+++ b/libs/androidfw/tests/data/sparse/gen_strings.sh
@@ -14,5 +14,7 @@
fi
done
echo "</resources>" >> $OUTPUT_default
+
+echo " <string name=\"only_v26\">only v26</string>" >> $OUTPUT_v26
echo "</resources>" >> $OUTPUT_v26
diff --git a/libs/androidfw/tests/data/sparse/not_sparse.apk b/libs/androidfw/tests/data/sparse/not_sparse.apk
index 599a370..b08a621 100644
--- a/libs/androidfw/tests/data/sparse/not_sparse.apk
+++ b/libs/androidfw/tests/data/sparse/not_sparse.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/sparse/res/values-v26/strings.xml b/libs/androidfw/tests/data/sparse/res/values-v26/strings.xml
index b6f8299..d116087e 100644
--- a/libs/androidfw/tests/data/sparse/res/values-v26/strings.xml
+++ b/libs/androidfw/tests/data/sparse/res/values-v26/strings.xml
@@ -333,4 +333,5 @@
<string name="foo_993">9930</string>
<string name="foo_996">9960</string>
<string name="foo_999">9990</string>
+ <string name="only_v26">only v26</string>
</resources>
diff --git a/libs/androidfw/tests/data/sparse/sparse.apk b/libs/androidfw/tests/data/sparse/sparse.apk
index 1f9bba3..9fd01fb 100644
--- a/libs/androidfw/tests/data/sparse/sparse.apk
+++ b/libs/androidfw/tests/data/sparse/sparse.apk
Binary files differ
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
index 2272a37..2624a41 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
@@ -21,10 +21,10 @@
<dimen name="settingslib_switchbar_margin">16dp</dimen>
<!-- Size of layout margin left -->
- <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
+ <dimen name="settingslib_switchbar_padding_left">20dp</dimen>
<!-- Size of layout margin right -->
- <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
+ <dimen name="settingslib_switchbar_padding_right">20dp</dimen>
<!-- Minimum width of switch -->
<dimen name="settingslib_min_switch_width">52dp</dimen>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index 6362882..157a54e 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -24,7 +24,7 @@
<dimen name="settingslib_restricted_icon_margin_end">16dp</dimen>
<!-- Size of title margin -->
- <dimen name="settingslib_switch_title_margin">16dp</dimen>
+ <dimen name="settingslib_switch_title_margin">24dp</dimen>
<!-- SwitchBar sub settings margin start / end -->
<dimen name="settingslib_switchbar_subsettings_margin_start">72dp</dimen>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index bf0dc7b..1343895 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -261,8 +261,6 @@
private void updateWifiState() {
state = mWifiManager.getWifiState();
enabled = state == WifiManager.WIFI_STATE_ENABLED;
- isCarrierMerged = false;
- subId = 0;
}
private void updateRssi(int newRssi) {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index a61b18c..a0d335d 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -468,7 +468,6 @@
.withAlpha(1f)
.withMatrix(matrix)
.withWindowCrop(windowCrop)
- .withLayer(window.prefixOrderIndex)
.withCornerRadius(cornerRadius)
.withVisibility(true)
.build()
diff --git a/packages/SystemUI/res/drawable/ic_qs_drag_handle.xml b/packages/SystemUI/res/drawable/ic_qs_drag_handle.xml
deleted file mode 100644
index 9a69b33..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_drag_handle.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ~ Copyright (C) 2021 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
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="36dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="?android:attr/textColorPrimary"
- android:pathData="M5.41,7.59L4,9l8,8 8,-8 -1.41,-1.41L12,14.17" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
index 363a022..eb08434 100644
--- a/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
+++ b/packages/SystemUI/res/drawable/media_output_dialog_button_background.xml
@@ -13,17 +13,20 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- android:shape="rectangle">
- <stroke
- android:color="?androidprv:attr/colorAccentPrimaryVariant"
- android:width="1dp"/>
- <corners android:radius="20dp"/>
- <padding
- android:left="16dp"
- android:right="16dp"
- android:top="8dp"
- android:bottom="8dp" />
- <solid android:color="@android:color/transparent" />
-</shape>
+ android:insetBottom="6dp"
+ android:insetTop="6dp">
+ <shape android:shape="rectangle">
+ <stroke
+ android:color="?androidprv:attr/colorAccentPrimaryVariant"
+ android:width="1dp"/>
+ <corners android:radius="20dp"/>
+ <padding
+ android:left="16dp"
+ android:right="16dp"
+ android:top="8dp"
+ android:bottom="8dp"/>
+ <solid android:color="@android:color/transparent"/>
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index a64ef3e..07fd1b0 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -24,9 +24,9 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="96dp"
+ android:layout_height="wrap_content"
android:gravity="start|center_vertical"
- android:paddingStart="16dp"
+ android:paddingStart="24dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/header_icon"
@@ -36,7 +36,7 @@
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="20dp"
android:paddingBottom="24dp"
@@ -59,7 +59,7 @@
android:gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="?android:attr/textColorTertiary"
+ android:textColor="?android:attr/textColorSecondary"
android:fontFamily="roboto-regular"
android:textSize="16sp"/>
</LinearLayout>
@@ -90,7 +90,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="24dp"
- android:layout_marginBottom="18dp"
+ android:layout_marginBottom="24dp"
android:layout_marginEnd="24dp"
android:orientation="horizontal">
@@ -98,7 +98,7 @@
android:id="@+id/stop"
style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:minWidth="0dp"
android:text="@string/keyboard_key_media_stop"
android:visibility="gone"/>
@@ -112,7 +112,7 @@
android:id="@+id/done"
style="@style/MediaOutputRoundedOutlinedButton"
android:layout_width="wrap_content"
- android:layout_height="36dp"
+ android:layout_height="wrap_content"
android:minWidth="0dp"
android:text="@string/inline_done_button"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 2ac03c2..f5c6036 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -56,17 +56,4 @@
layout="@layout/qs_customize_panel"
android:visibility="gone" />
- <ImageView
- android:id="@+id/qs_drag_handle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="24dp"
- android:elevation="4dp"
- android:importantForAccessibility="no"
- android:scaleType="center"
- android:src="@drawable/ic_qs_drag_handle"
- android:tint="@color/qs_detail_button_white"
- tools:ignore="UseAppTint" />
-
</com.android.systemui.qs.QSContainerImpl>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 362e18d..dabc310 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -18,11 +18,14 @@
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
+ <!-- The maximum number of rows in the QSPanel -->
+ <integer name="quick_settings_max_rows">3</integer>
+
<!-- The maximum number of rows in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_rows">4</integer>
+ <integer name="quick_qs_panel_max_rows">3</integer>
<!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_tiles">8</integer>
+ <integer name="quick_qs_panel_max_tiles">6</integer>
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">true</bool>
diff --git a/packages/SystemUI/res/values-sw720dp-land/config.xml b/packages/SystemUI/res/values-sw720dp-land/config.xml
index e4573c6..e0b1614 100644
--- a/packages/SystemUI/res/values-sw720dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/config.xml
@@ -18,11 +18,14 @@
<!-- Max number of columns for quick controls area -->
<integer name="controls_max_columns">2</integer>
+ <!-- The maximum number of rows in the QSPanel -->
+ <integer name="quick_settings_max_rows">3</integer>
+
<!-- The maximum number of rows in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_rows">4</integer>
+ <integer name="quick_qs_panel_max_rows">3</integer>
<!-- The maximum number of tiles in the QuickQSPanel -->
- <integer name="quick_qs_panel_max_tiles">8</integer>
+ <integer name="quick_qs_panel_max_tiles">6</integer>
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">true</bool>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index b6be6ed..e46b6f1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -26,6 +26,7 @@
import com.android.systemui.unfold.config.UnfoldTransitionConfig
import com.android.systemui.unfold.progress.FixedTimingTransitionProgressProvider
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
+import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider
import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider
@@ -62,7 +63,7 @@
mainExecutor
)
- return if (config.isHingeAngleEnabled) {
+ val unfoldTransitionProgressProvider = if (config.isHingeAngleEnabled) {
PhysicsBasedUnfoldTransitionProgressProvider(
mainHandler,
foldStateProvider
@@ -70,6 +71,10 @@
} else {
FixedTimingTransitionProgressProvider(foldStateProvider)
}
+ return ScaleAwareTransitionProgressProvider(
+ unfoldTransitionProgressProvider,
+ context.contentResolver
+ )
}
fun createConfig(context: Context): UnfoldTransitionConfig =
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
index e072d41..58d7dfb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProvider.kt
@@ -2,7 +2,6 @@
import android.content.Context
import android.os.RemoteException
-import android.util.Log
import android.view.IRotationWatcher
import android.view.IWindowManager
import android.view.Surface
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
new file mode 100644
index 0000000..df9078a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
@@ -0,0 +1,50 @@
+package com.android.systemui.unfold.util
+
+import android.animation.ValueAnimator
+import android.content.ContentResolver
+import android.database.ContentObserver
+import android.provider.Settings
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+
+/** Wraps [UnfoldTransitionProgressProvider] to disable transitions when animations are disabled. */
+class ScaleAwareTransitionProgressProvider(
+ unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
+ private val contentResolver: ContentResolver
+) : UnfoldTransitionProgressProvider {
+
+ private val scopedUnfoldTransitionProgressProvider =
+ ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider)
+
+ private val animatorDurationScaleObserver = object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ onAnimatorScaleChanged()
+ }
+ }
+
+ init {
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
+ /* notifyForDescendants= */ false,
+ animatorDurationScaleObserver)
+ onAnimatorScaleChanged()
+ }
+
+ private fun onAnimatorScaleChanged() {
+ val animationsEnabled = ValueAnimator.areAnimatorsEnabled()
+ scopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(animationsEnabled)
+ }
+
+ override fun addCallback(listener: TransitionProgressListener) {
+ scopedUnfoldTransitionProgressProvider.addCallback(listener)
+ }
+
+ override fun removeCallback(listener: TransitionProgressListener) {
+ scopedUnfoldTransitionProgressProvider.removeCallback(listener)
+ }
+
+ override fun destroy() {
+ contentResolver.unregisterContentObserver(animatorDurationScaleObserver)
+ scopedUnfoldTransitionProgressProvider.destroy()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index b2ecc614..0c1934c 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -218,11 +218,14 @@
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
- pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
- pw.println("Radius in pixels: " + mRadius);
- pw.println("topLeft= (" + getX() + ", " + getY() + ")");
- pw.println("topLeft= (" + getX() + ", " + getY() + ")");
- pw.println("mIconType=" + typeToString(mIconType));
- pw.println("mAod=" + mAod);
+ pw.println("Lock Icon View Parameters:");
+ pw.println(" Center in px (x, y)= ("
+ + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
+ pw.println(" Radius in pixels: " + mRadius);
+ pw.println(" mIconType=" + typeToString(mIconType));
+ pw.println(" mAod=" + mAod);
+ pw.println("Lock Icon View actual measurements:");
+ pw.println(" topLeft= (" + getX() + ", " + getY() + ")");
+ pw.println(" width=" + getWidth() + " height=" + getHeight());
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 1633923..e267c5c 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -35,13 +35,14 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.media.AudioAttributes;
import android.os.Process;
+import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.MathUtils;
-import android.view.GestureDetector;
-import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -83,6 +84,7 @@
*/
@StatusBarComponent.StatusBarScope
public class LockIconViewController extends ViewController<LockIconView> implements Dumpable {
+ private static final String TAG = "LockIconViewController";
private static final float sDefaultDensity =
(float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
private static final int sLockIconRadiusPx = (int) (sDefaultDensity * 36);
@@ -91,6 +93,7 @@
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ private static final long LONG_PRESS_TIMEOUT = 200L; // milliseconds
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final KeyguardViewController mKeyguardViewController;
@@ -112,6 +115,12 @@
@Nullable private final Vibrator mVibrator;
@Nullable private final AuthRippleController mAuthRippleController;
+ // Tracks the velocity of a touch to help filter out the touches that move too fast.
+ private VelocityTracker mVelocityTracker;
+ // The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
+ private int mActivePointerId = -1;
+ private VibrationEffect mTick;
+
private boolean mIsDozing;
private boolean mIsBouncerShowing;
private boolean mRunningFPS;
@@ -122,6 +131,7 @@
private boolean mUserUnlockedWithBiometric;
private Runnable mCancelDelayedUpdateVisibilityRunnable;
private Runnable mOnGestureDetectedRunnable;
+ private Runnable mLongPressCancelRunnable;
private boolean mUdfpsSupported;
private float mHeightPixels;
@@ -181,7 +191,7 @@
mView.setImageDrawable(mIcon);
mUnlockedLabel = resources.getString(R.string.accessibility_unlock_button);
mLockedLabel = resources.getString(R.string.accessibility_lock_icon);
- dumpManager.registerDumpable("LockIconViewController", this);
+ dumpManager.registerDumpable(TAG, this);
}
@Override
@@ -320,7 +330,7 @@
getResources().getString(R.string.accessibility_enter_hint));
public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(v, info);
- if (isClickable()) {
+ if (isActionable()) {
if (mShowLockIcon) {
info.addAction(mAccessibilityAuthenticateHint);
} else if (mShowUnlockIcon) {
@@ -425,10 +435,8 @@
mAodFp.setAlpha(255 * mInterpolatedDarkAmount);
}
- if (mShowAodLockIcon) {
- mView.setTranslationX(offsetX);
- mView.setTranslationY(offsetY);
- }
+ mView.setTranslationX(offsetX);
+ mView.setTranslationY(offsetY);
}
private void updateIsUdfpsEnrolled() {
@@ -477,7 +485,7 @@
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
// reset mIsBouncerShowing state in case it was preemptively set
- // onAffordanceClick
+ // onLongPress
mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
updateVisibility();
}
@@ -571,104 +579,79 @@
}
};
- private final GestureDetector mGestureDetector =
- new GestureDetector(new SimpleOnGestureListener() {
- public boolean onDown(MotionEvent e) {
- if (!isClickable()) {
- mDownDetected = false;
- return false;
- }
-
- // intercept all following touches until we see MotionEvent.ACTION_CANCEL UP or
- // MotionEvent.ACTION_UP (see #onTouchEvent)
- if (mVibrator != null && !mDownDetected) {
- mVibrator.vibrate(
- Process.myUid(),
- getContext().getOpPackageName(),
- UdfpsController.EFFECT_CLICK,
- "lockIcon-onDown",
- VIBRATION_SONIFICATION_ATTRIBUTES);
- }
-
- mDownDetected = true;
- return true;
- }
-
- public void onLongPress(MotionEvent e) {
- if (!wasClickableOnDownEvent()) {
- return;
- }
-
- if (onAffordanceClick() && mVibrator != null) {
- // only vibrate if the click went through and wasn't intercepted by falsing
- mVibrator.vibrate(
- Process.myUid(),
- getContext().getOpPackageName(),
- UdfpsController.EFFECT_CLICK,
- "lockIcon-onLongPress",
- VIBRATION_SONIFICATION_ATTRIBUTES);
- }
- }
-
- public boolean onSingleTapUp(MotionEvent e) {
- if (!wasClickableOnDownEvent()) {
- return false;
- }
- onAffordanceClick();
- return true;
- }
-
- public boolean onFling(MotionEvent e1, MotionEvent e2,
- float velocityX, float velocityY) {
- if (!wasClickableOnDownEvent()) {
- return false;
- }
- onAffordanceClick();
- return true;
- }
-
- private boolean wasClickableOnDownEvent() {
- return mDownDetected;
- }
-
- /**
- * Whether we tried to launch the affordance.
- *
- * If falsing intercepts the click, returns false.
- */
- private boolean onAffordanceClick() {
- if (mFalsingManager.isFalseTouch(LOCK_ICON)) {
- return false;
- }
-
- // pre-emptively set to true to hide view
- mIsBouncerShowing = true;
- if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
- mAuthRippleController.showRipple(FINGERPRINT);
- }
- updateVisibility();
- if (mOnGestureDetectedRunnable != null) {
- mOnGestureDetectedRunnable.run();
- }
- mKeyguardViewController.showBouncer(/* scrim */ true);
- return true;
- }
- });
-
/**
- * Send touch events to this view and handles it if the touch is within this view and we are
- * in a 'clickable' state
- * @return whether to intercept the touch event
+ * Handles the touch if it is within the lock icon view and {@link #isActionable()} is true.
+ * Subsequently, will trigger {@link #onLongPress()} if a touch is continuously in the lock icon
+ * area for {@link #LONG_PRESS_TIMEOUT} ms.
+ *
+ * Touch speed debouncing mimics logic from the velocity tracker in {@link UdfpsController}.
*/
public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) {
- if (onInterceptTouchEvent(event)) {
- mOnGestureDetectedRunnable = onGestureDetectedRunnable;
- mGestureDetector.onTouchEvent(event);
- return true;
+ if (!onInterceptTouchEvent(event)) {
+ cancelTouches();
+ return false;
}
- mDownDetected = false;
- return false;
+ mOnGestureDetectedRunnable = onGestureDetectedRunnable;
+ switch(event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_HOVER_ENTER:
+ if (mVibrator != null && !mDownDetected) {
+ if (mTick == null) {
+ mTick = UdfpsController.lowTick(getContext(), true,
+ LONG_PRESS_TIMEOUT);
+ }
+ mVibrator.vibrate(
+ Process.myUid(),
+ getContext().getOpPackageName(),
+ mTick,
+ "lock-icon-tick",
+ VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+
+ // The pointer that causes ACTION_DOWN is always at index 0.
+ // We need to persist its ID to track it during ACTION_MOVE that could include
+ // data for many other pointers because of multi-touch support.
+ mActivePointerId = event.getPointerId(0);
+ if (mVelocityTracker == null) {
+ // To simplify the lifecycle of the velocity tracker, make sure it's never null
+ // after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
+ mVelocityTracker = VelocityTracker.obtain();
+ } else {
+ // ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
+ // ACTION_DOWN, in that case we should just reuse the old instance.
+ mVelocityTracker.clear();
+ }
+ mVelocityTracker.addMovement(event);
+
+ mDownDetected = true;
+ mLongPressCancelRunnable = mExecutor.executeDelayed(
+ this::onLongPress, LONG_PRESS_TIMEOUT);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_HOVER_MOVE:
+ mVelocityTracker.addMovement(event);
+ // Compute pointer velocity in pixels per second.
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float velocity = UdfpsController.computePointerSpeed(mVelocityTracker,
+ mActivePointerId);
+ if (event.getClassification() != MotionEvent.CLASSIFICATION_DEEP_PRESS
+ && UdfpsController.exceedsVelocityThreshold(velocity)) {
+ Log.v(TAG, "lock icon long-press rescheduled due to "
+ + "high pointer velocity=" + velocity);
+ mLongPressCancelRunnable.run();
+ mLongPressCancelRunnable = mExecutor.executeDelayed(
+ this::onLongPress, LONG_PRESS_TIMEOUT);
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_HOVER_EXIT:
+ cancelTouches();
+ break;
+ }
+
+ return true;
}
/**
@@ -676,7 +659,7 @@
* bounds.
*/
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (!inLockIconArea(event) || !isClickable()) {
+ if (!inLockIconArea(event) || !isActionable()) {
return false;
}
@@ -687,13 +670,59 @@
return mDownDetected;
}
+ private void onLongPress() {
+ cancelTouches();
+ if (mFalsingManager.isFalseTouch(LOCK_ICON)) {
+ Log.v(TAG, "lock icon long-press rejected by the falsing manager.");
+ return;
+ }
+
+ // pre-emptively set to true to hide view
+ mIsBouncerShowing = true;
+ if (mUdfpsSupported && mShowUnlockIcon && mAuthRippleController != null) {
+ mAuthRippleController.showRipple(FINGERPRINT);
+ }
+ updateVisibility();
+ if (mOnGestureDetectedRunnable != null) {
+ mOnGestureDetectedRunnable.run();
+ }
+
+ if (mVibrator != null) {
+ // play device entry haptic (same as biometric success haptic)
+ mVibrator.vibrate(
+ Process.myUid(),
+ getContext().getOpPackageName(),
+ UdfpsController.EFFECT_CLICK,
+ "lock-icon-device-entry",
+ VIBRATION_SONIFICATION_ATTRIBUTES);
+ }
+
+ mKeyguardViewController.showBouncer(/* scrim */ true);
+ }
+
+
+ private void cancelTouches() {
+ mDownDetected = false;
+ if (mLongPressCancelRunnable != null) {
+ mLongPressCancelRunnable.run();
+ }
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ if (mVibrator != null) {
+ mVibrator.cancel();
+ }
+ }
+
+
private boolean inLockIconArea(MotionEvent event) {
return mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
&& (mView.getVisibility() == View.VISIBLE
|| (mAodFp != null && mAodFp.getVisibility() == View.VISIBLE));
}
- private boolean isClickable() {
+ private boolean isActionable() {
return mUdfpsSupported || mShowUnlockIcon;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 09f2af4..9808045 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -103,6 +103,7 @@
public class UdfpsController implements DozeReceiver {
private static final String TAG = "UdfpsController";
private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
+ private static final long DEFAULT_VIBRATION_DURATION = 1000; // milliseconds
// Minimum required delay between consecutive touch logs in milliseconds.
private static final long MIN_TOUCH_LOG_INTERVAL = 50;
@@ -164,8 +165,7 @@
private boolean mAttemptedToDismissKeyguard;
private Set<Callback> mCallbacks = new HashSet<>();
- // by default, use low tick
- private int mPrimitiveTick = VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
+ private static final int DEFAULT_TICK = VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
private final VibrationEffect mTick;
@VisibleForTesting
@@ -327,12 +327,23 @@
}
}
- private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
+ /**
+ * Calculate the pointer speed given a velocity tracker and the pointer id.
+ * This assumes that the velocity tracker has already been passed all relevant motion events.
+ */
+ public static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
final float vx = tracker.getXVelocity(pointerId);
final float vy = tracker.getYVelocity(pointerId);
return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
}
+ /**
+ * Whether the velocity exceeds the acceptable UDFPS debouncing threshold.
+ */
+ public static boolean exceedsVelocityThreshold(float velocity) {
+ return velocity > 750f;
+ }
+
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -467,7 +478,7 @@
final float v = computePointerSpeed(mVelocityTracker, mActivePointerId);
final float minor = event.getTouchMinor(idx);
final float major = event.getTouchMajor(idx);
- final boolean exceedsVelocityThreshold = v > 750f;
+ final boolean exceedsVelocityThreshold = exceedsVelocityThreshold(v);
final String touchInfo = String.format(
"minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
minor, major, v, exceedsVelocityThreshold);
@@ -575,7 +586,7 @@
mConfigurationController = configurationController;
mSystemClock = systemClock;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
- mTick = lowTick();
+ mTick = lowTick(context, false /* useShortRampup */, DEFAULT_VIBRATION_DURATION);
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -610,32 +621,43 @@
udfpsHapticsSimulator.setUdfpsController(this);
}
- private VibrationEffect lowTick() {
- boolean useLowTickDefault = mContext.getResources()
+ /**
+ * Returns the continuous low tick effect that starts playing on the udfps finger-down event.
+ */
+ public static VibrationEffect lowTick(
+ Context context,
+ boolean useShortRampUp,
+ long duration
+ ) {
+ boolean useLowTickDefault = context.getResources()
.getBoolean(R.bool.config_udfpsUseLowTick);
+ int primitiveTick = DEFAULT_TICK;
if (Settings.Global.getFloat(
- mContext.getContentResolver(),
+ context.getContentResolver(),
"tick-low", useLowTickDefault ? 1 : 0) == 0) {
- mPrimitiveTick = VibrationEffect.Composition.PRIMITIVE_TICK;
+ primitiveTick = VibrationEffect.Composition.PRIMITIVE_TICK;
}
float tickIntensity = Settings.Global.getFloat(
- mContext.getContentResolver(),
+ context.getContentResolver(),
"tick-intensity",
- mContext.getResources().getFloat(R.dimen.config_udfpsTickIntensity));
+ context.getResources().getFloat(R.dimen.config_udfpsTickIntensity));
int tickDelay = Settings.Global.getInt(
- mContext.getContentResolver(),
+ context.getContentResolver(),
"tick-delay",
- mContext.getResources().getInteger(R.integer.config_udfpsTickDelay));
+ context.getResources().getInteger(R.integer.config_udfpsTickDelay));
VibrationEffect.Composition composition = VibrationEffect.startComposition();
- composition.addPrimitive(mPrimitiveTick, tickIntensity, 0);
- int primitives = 1000 / tickDelay;
+ composition.addPrimitive(primitiveTick, tickIntensity, 0);
+ int primitives = (int) (duration / tickDelay);
float[] rampUp = new float[]{.48f, .58f, .69f, .83f};
+ if (useShortRampUp) {
+ rampUp = new float[]{.5f, .7f};
+ }
for (int i = 0; i < rampUp.length; i++) {
- composition.addPrimitive(mPrimitiveTick, tickIntensity * rampUp[i], tickDelay);
+ composition.addPrimitive(primitiveTick, tickIntensity * rampUp[i], tickDelay);
}
for (int i = rampUp.length; i < primitives; i++) {
- composition.addPrimitive(mPrimitiveTick, tickIntensity, tickDelay);
+ composition.addPrimitive(primitiveTick, tickIntensity, tickDelay);
}
return composition.compose();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
index 71edbc0..d17eadd 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DiagonalClassifier.java
@@ -19,6 +19,7 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_HORIZONTAL_ANGLE_RANGE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DIAGONAL_VERTICAL_ANGLE_RANGE;
import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
+import static com.android.systemui.classifier.Classifier.LOCK_ICON;
import static com.android.systemui.classifier.Classifier.RIGHT_AFFORDANCE;
import android.provider.DeviceConfig;
@@ -71,7 +72,9 @@
return Result.passed(0);
}
- if (interactionType == LEFT_AFFORDANCE || interactionType == RIGHT_AFFORDANCE) {
+ if (interactionType == LEFT_AFFORDANCE
+ || interactionType == RIGHT_AFFORDANCE
+ || interactionType == LOCK_ICON) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 03a0977..c12d48d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -63,13 +63,14 @@
View mDialogView;
private TextView mHeaderTitle;
private TextView mHeaderSubtitle;
- private ImageView mHeaderIcon;
private RecyclerView mDevicesRecyclerView;
private LinearLayout mDeviceListLayout;
private Button mDoneButton;
private Button mStopButton;
private int mListMaxHeight;
+ protected ImageView mHeaderIcon;
+
MediaOutputBaseAdapter mAdapter;
private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> {
@@ -140,7 +141,6 @@
mMediaOutputController.stop();
}
- @VisibleForTesting
void refresh() {
// Update header icon
final int iconRes = getHeaderIconRes();
@@ -154,12 +154,6 @@
} else {
mHeaderIcon.setVisibility(View.GONE);
}
- if (mHeaderIcon.getVisibility() == View.VISIBLE) {
- final int size = getHeaderIconSize();
- final int padding = mContext.getResources().getDimensionPixelSize(
- R.dimen.media_output_dialog_header_icon_padding);
- mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
- }
// Update title and subtitle
mHeaderTitle.setText(getHeaderText());
final CharSequence subTitle = getHeaderSubtitle();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index 1300400..b41e813 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -20,6 +20,7 @@
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
+import android.widget.LinearLayout;
import androidx.core.graphics.drawable.IconCompat;
@@ -76,6 +77,15 @@
}
@Override
+ void refresh() {
+ super.refresh();
+ final int size = getHeaderIconSize();
+ final int padding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.media_output_dialog_header_icon_padding);
+ mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
+ }
+
+ @Override
int getStopButtonVisibility() {
return View.VISIBLE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index cdf770f..c3de3c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -110,6 +110,16 @@
}
@Override
+ public int getTilesHeight() {
+ // Use the first page as that is the maximum height we need to show.
+ TileLayout tileLayout = mPages.get(0);
+ if (tileLayout == null) {
+ return 0;
+ }
+ return tileLayout.getTilesHeight();
+ }
+
+ @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass configuration change to non-attached pages as well. Some config changes will cause
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 8588ddf..e230e1b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -27,7 +27,6 @@
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
@@ -53,7 +52,6 @@
private float mQsExpansion;
private QSCustomizer mQSCustomizer;
private NonInterceptingScrollView mQSPanelContainer;
- private ImageView mDragHandle;
private int mSideMargins;
private boolean mQsDisabled;
@@ -71,7 +69,6 @@
mQSDetail = findViewById(R.id.qs_detail);
mHeader = findViewById(R.id.header);
mQSCustomizer = findViewById(R.id.qs_customize);
- mDragHandle = findViewById(R.id.qs_drag_handle);
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
@@ -190,23 +187,14 @@
mQSDetail.setBottom(getTop() + scrollBottom);
int qsDetailBottomMargin = ((MarginLayoutParams) mQSDetail.getLayoutParams()).bottomMargin;
mQSDetail.setBottom(getTop() + scrollBottom - qsDetailBottomMargin);
- // Pin the drag handle to the bottom of the panel.
- mDragHandle.setTranslationY(scrollBottom - mDragHandle.getHeight());
}
protected int calculateContainerHeight() {
int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
// Need to add the dragHandle height so touches will be intercepted by it.
- int dragHandleHeight;
- if (mDragHandle.getVisibility() == VISIBLE) {
- dragHandleHeight = Math.round((1 - mQsExpansion) * mDragHandle.getHeight());
- } else {
- dragHandleHeight = 0;
- }
return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
: Math.round(mQsExpansion * (heightOverride - mHeader.getHeight()))
- + mHeader.getHeight()
- + dragHandleHeight;
+ + mHeader.getHeight();
}
int calculateContainerBottom() {
@@ -221,8 +209,6 @@
public void setExpansion(float expansion) {
mQsExpansion = expansion;
mQSPanelContainer.setScrollingEnabled(expansion > 0f);
- mDragHandle.setAlpha(1.0f - expansion);
- mDragHandle.setClickable(expansion == 0f); // Only clickable when fully collapsed
updateExpansion();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index ee59ae6..e82e9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -33,7 +33,6 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout.LayoutParams;
-import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -94,7 +93,6 @@
private float mLastPanelFraction;
private float mSquishinessFraction = 1;
private boolean mQsDisabled;
- private ImageView mQsDragHandler;
private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
private final CommandQueue mCommandQueue;
@@ -205,7 +203,6 @@
mHeader = view.findViewById(R.id.header);
mQSPanelController.setHeaderContainer(view.findViewById(R.id.header_text_container));
mFooter = qsFragmentComponent.getQSFooter();
- mQsDragHandler = view.findViewById(R.id.qs_drag_handle);
mQsDetailDisplayer.setQsPanelController(mQSPanelController);
@@ -249,11 +246,6 @@
mQSPanelController.getMediaHost().getHostView().setAlpha(1.0f);
mQSAnimator.requestAnimatorUpdate();
});
-
- mQsDragHandler.setOnClickListener(v -> {
- Log.d(TAG, "drag handler clicked");
- mCommandQueue.animateExpandSettingsPanel(null);
- });
}
@Override
@@ -385,30 +377,26 @@
}
private void updateQsState() {
- final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling
+ final boolean expanded = mQsExpanded || mInSplitShade;
+ final boolean expandVisually = expanded || mStackScrollerOverscrolling
|| mHeaderAnimating;
- mQSPanelController.setExpanded(mQsExpanded);
- mQSDetail.setExpanded(mQsExpanded);
+ mQSPanelController.setExpanded(expanded);
+ mQSDetail.setExpanded(expanded);
boolean keyguardShowing = isKeyguardState();
- mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
+ mHeader.setVisibility((expanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
? View.VISIBLE
: View.INVISIBLE);
mHeader.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
- || (mQsExpanded && !mStackScrollerOverscrolling), mQuickQSPanelController);
- mFooter.setVisibility(!mQsDisabled && (mQsExpanded || !keyguardShowing || mHeaderAnimating
+ || (expanded && !mStackScrollerOverscrolling), mQuickQSPanelController);
+ mFooter.setVisibility(!mQsDisabled && (expanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
? View.VISIBLE
: View.INVISIBLE);
mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
- || (mQsExpanded && !mStackScrollerOverscrolling));
+ || (expanded && !mStackScrollerOverscrolling));
mQSPanelController.setVisibility(
!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
- mQsDragHandler.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
- || mShowCollapsedOnKeyguard)
- && Utils.shouldUseSplitNotificationShade(getResources())
- ? View.VISIBLE
- : View.GONE);
}
private boolean isKeyguardState() {
@@ -418,7 +406,8 @@
}
private void updateShowCollapsedOnKeyguard() {
- boolean showCollapsed = mBypassController.getBypassEnabled() || mTransitioningToFullShade;
+ boolean showCollapsed = mBypassController.getBypassEnabled()
+ || (mTransitioningToFullShade && !mInSplitShade);
if (showCollapsed != mShowCollapsedOnKeyguard) {
mShowCollapsedOnKeyguard = showCollapsed;
updateQsState();
@@ -498,6 +487,8 @@
public void setInSplitShade(boolean inSplitShade) {
mInSplitShade = inSplitShade;
mQSAnimator.setTranslateWhileExpanding(inSplitShade);
+ updateShowCollapsedOnKeyguard();
+ updateQsState();
}
@Override
@@ -516,7 +507,8 @@
public void setQsExpansion(float expansion, float panelExpansionFraction,
float proposedTranslation, float squishinessFraction) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
- float progress = mTransitioningToFullShade ? mFullShadeProgress : panelExpansionFraction;
+ float progress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
+ ? mFullShadeProgress : panelExpansionFraction;
setAlphaAnimationProgress(mInSplitShade ? progress : 1);
mContainer.setExpansion(expansion);
final float translationScaleY = (mInSplitShade
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index d69deef..20c0fdd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -258,13 +258,8 @@
}
private void updateViewPositions() {
- if (!(mTileLayout instanceof TileLayout)) {
- return;
- }
- TileLayout layout = (TileLayout) mTileLayout;
-
// Adjust view positions based on tile squishing
- int tileHeightOffset = layout.getTilesHeight() - layout.getHeight();
+ int tileHeightOffset = mTileLayout.getTilesHeight() - mTileLayout.getHeight();
boolean move = false;
for (int i = 0; i < getChildCount(); i++) {
@@ -787,6 +782,12 @@
/** */
void setListening(boolean listening, UiEventLogger uiEventLogger);
+ /** */
+ int getHeight();
+
+ /** */
+ int getTilesHeight();
+
/**
* Sets a size modifier for the tile. Where 0 means collapsed, and 1 expanded.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 6794d5b..001c740e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -45,6 +45,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.util.Utils;
import javax.inject.Inject;
import javax.inject.Named;
@@ -72,6 +73,7 @@
new QSPanel.OnConfigurationChangedListener() {
@Override
public void onConfigurationChange(Configuration newConfig) {
+ updateMediaExpansion();
mView.updateResources();
mQsSecurityFooter.onConfigurationChanged();
if (mView.isListening()) {
@@ -121,13 +123,17 @@
@Override
public void onInit() {
super.onInit();
- mMediaHost.setExpansion(1);
+ updateMediaExpansion();
mMediaHost.setShowsOnlyActiveMedia(false);
mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
mQsCustomizerController.init();
mBrightnessSliderController.init();
}
+ private void updateMediaExpansion() {
+ mMediaHost.setExpansion(Utils.shouldUseSplitNotificationShade(getResources()) ? 0 : 1);
+ }
+
@Override
protected void onViewAttached() {
super.onViewAttached();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 7f08e5b..bff318a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -275,6 +275,7 @@
return Math.max(mColumns * mRows, 1);
}
+ @Override
public int getTilesHeight() {
return mLastTileBottom + getPaddingBottom();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 706f423..6f63a08 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -86,6 +86,7 @@
import com.android.wifitrackerlib.MergedCarrierEntry;
import com.android.wifitrackerlib.WifiEntry;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -98,8 +99,10 @@
import javax.inject.Inject;
-public class InternetDialogController implements WifiEntry.DisconnectCallback,
- AccessPointController.AccessPointCallback {
+/**
+ * Controller for Internet Dialog.
+ */
+public class InternetDialogController implements AccessPointController.AccessPointCallback {
private static final String TAG = "InternetDialogController";
private static final String ACTION_NETWORK_PROVIDER_SETTINGS =
@@ -881,20 +884,6 @@
return;
}
- boolean hasConnectedWifi = false;
- final int accessPointSize = accessPoints.size();
- for (int i = 0; i < accessPointSize; i++) {
- WifiEntry wifiEntry = accessPoints.get(i);
- if (wifiEntry.isDefaultNetwork() && wifiEntry.hasInternetAccess()) {
- mConnectedEntry = wifiEntry;
- hasConnectedWifi = true;
- break;
- }
- }
- if (!hasConnectedWifi) {
- mConnectedEntry = null;
- }
-
int count = MAX_WIFI_ENTRY_COUNT;
if (mHasEthernet) {
count -= 1;
@@ -902,15 +891,22 @@
if (hasActiveSubId()) {
count -= 1;
}
- if (hasConnectedWifi) {
- count -= 1;
+ if (count > accessPoints.size()) {
+ count = accessPoints.size();
}
- final List<WifiEntry> wifiEntries = accessPoints.stream()
- .filter(wifiEntry -> (!wifiEntry.isDefaultNetwork()
- || !wifiEntry.hasInternetAccess()))
- .limit(count)
- .collect(Collectors.toList());
- mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
+
+ WifiEntry connectedEntry = null;
+ final List<WifiEntry> wifiEntries = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ WifiEntry entry = accessPoints.get(i);
+ if (connectedEntry == null && entry.isDefaultNetwork() && entry.hasInternetAccess()) {
+ connectedEntry = entry;
+ } else {
+ wifiEntries.add(entry);
+ }
+ }
+ mConnectedEntry = connectedEntry;
+ mWifiEntriesCount = wifiEntries.size();
if (mCallback != null) {
mCallback.onAccessPointsChanged(wifiEntries, mConnectedEntry);
@@ -921,10 +917,6 @@
public void onSettingsActivityTriggered(Intent settingsIntent) {
}
- @Override
- public void onDisconnectResult(int status) {
- }
-
private class InternetTelephonyCallback extends TelephonyCallback implements
TelephonyCallback.DataConnectionStateListener,
TelephonyCallback.DisplayInfoListener,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index dca7f70..0fb08e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -174,7 +174,7 @@
internal fun canDragDown(): Boolean {
return (statusBarStateController.state == StatusBarState.KEYGUARD ||
nsslController.isInLockedDownShade()) &&
- qS.isFullyCollapsed
+ (qS.isFullyCollapsed || useSplitShade)
}
/**
@@ -285,7 +285,7 @@
internal val isDragDownAnywhereEnabled: Boolean
get() = (statusBarStateController.getState() == StatusBarState.KEYGUARD &&
!keyguardBypassController.bypassEnabled &&
- qS.isFullyCollapsed)
+ (qS.isFullyCollapsed || useSplitShade))
/**
* The amount in pixels that the user has dragged down.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
index 103ca0e..ff9d919 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiSignalController.java
@@ -83,7 +83,7 @@
@Override
public void notifyListeners(SignalCallback callback) {
if (mCurrentState.isCarrierMerged) {
- if (mCurrentState.isDefault) {
+ if (mCurrentState.isDefault || !mNetworkController.isRadioOn()) {
notifyListenersForCarrierWifi(callback);
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 4441270..fa9217d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -20,6 +20,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
@@ -158,6 +159,9 @@
mExpansionStateLogger.onVisibilityChanged(
mTmpCurrentlyVisibleNotifications, mTmpCurrentlyVisibleNotifications);
+ Trace.traceCounter(Trace.TRACE_TAG_APP, "Notifications [Active]", N);
+ Trace.traceCounter(Trace.TRACE_TAG_APP, "Notifications [Visible]",
+ mCurrentlyVisibleNotifications.size());
recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
mTmpCurrentlyVisibleNotifications.clear();
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 ab08865..5477c19 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
@@ -119,6 +119,7 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -726,38 +727,59 @@
}
if (DEBUG) {
- int y = mTopPadding;
- mDebugPaint.setColor(Color.RED);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = getLayoutHeight();
- mDebugPaint.setColor(Color.YELLOW);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = (int) mMaxLayoutHeight;
- mDebugPaint.setColor(Color.MAGENTA);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- if (mKeyguardBottomPadding >= 0) {
- y = getHeight() - (int) mKeyguardBottomPadding;
- mDebugPaint.setColor(Color.GRAY);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
- }
-
- y = getHeight() - getEmptyBottomMargin();
- mDebugPaint.setColor(Color.GREEN);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = (int) (mAmbientState.getStackY());
- mDebugPaint.setColor(Color.CYAN);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-
- y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
- mDebugPaint.setColor(Color.BLUE);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+ onDrawDebug(canvas);
}
}
+ /** Used to track the Y positions that were already used to draw debug text labels. */
+ private static final Set<Integer> DEBUG_TEXT_USED_Y_POSITIONS =
+ DEBUG ? new HashSet<>() : Collections.emptySet();
+
+ private void onDrawDebug(Canvas canvas) {
+ DEBUG_TEXT_USED_Y_POSITIONS.clear();
+
+ int y = mTopPadding;
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding");
+
+ y = getLayoutHeight();
+ drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight()");
+
+ y = (int) mMaxLayoutHeight;
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight");
+
+ if (mKeyguardBottomPadding >= 0) {
+ y = getHeight() - (int) mKeyguardBottomPadding;
+ drawDebugInfo(canvas, y, Color.GRAY,
+ /* label= */ "getHeight() - mKeyguardBottomPadding");
+ }
+
+ y = getHeight() - getEmptyBottomMargin();
+ drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeight() - getEmptyBottomMargin()");
+
+ y = (int) (mAmbientState.getStackY());
+ drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY()");
+
+ y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
+ drawDebugInfo(canvas, y, Color.BLUE,
+ /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight()");
+ }
+
+ private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
+ mDebugPaint.setColor(color);
+ canvas.drawLine(/* startX= */ 0, /* startY= */ y, /* stopX= */ getWidth(), /* stopY= */ y,
+ mDebugPaint);
+ canvas.drawText(label, /* x= */ 0, /* y= */ computeDebugYTextPosition(y), mDebugPaint);
+ }
+
+ private int computeDebugYTextPosition(int lineY) {
+ int textY = lineY;
+ while (DEBUG_TEXT_USED_Y_POSITIONS.contains(textY)) {
+ textY = (int) (textY + mDebugPaint.getTextSize());
+ }
+ DEBUG_TEXT_USED_Y_POSITIONS.add(textY);
+ return textY;
+ }
+
@ShadeViewRefactor(RefactorComponent.DECORATOR)
private void drawBackground(Canvas canvas) {
int lockScreenLeft = mSidePaddings;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index c8bca7c..261b5db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -2248,11 +2248,14 @@
private void updateQsExpansion() {
if (mQs == null) return;
- float qsExpansionFraction = computeQsExpansionFraction();
- float squishiness = mNotificationStackScrollLayoutController
- .getNotificationSquishinessFraction();
- mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
- mQsExpandImmediate || mQsExpanded ? 1f : squishiness);
+ final float squishiness =
+ mQsExpandImmediate || mQsExpanded ? 1f : mNotificationStackScrollLayoutController
+ .getNotificationSquishinessFraction();
+ final float qsExpansionFraction = computeQsExpansionFraction();
+ final float adjustedExpansionFraction = mShouldUseSplitNotificationShade
+ ? 1f : computeQsExpansionFraction();
+ mQs.setQsExpansion(adjustedExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
+ squishiness);
mSplitShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 51de1321..e6fc49f 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.unfold
+import android.animation.ValueAnimator
import android.content.Context
import android.graphics.PixelFormat
import android.hardware.devicestate.DeviceStateManager
@@ -111,7 +112,7 @@
Trace.beginSection("UnfoldLightRevealOverlayAnimation#onScreenTurningOn")
try {
// Add the view only if we are unfolding and this is the first screen on
- if (!isFolded && !isUnfoldHandled) {
+ if (!isFolded && !isUnfoldHandled && ValueAnimator.areAnimatorsEnabled()) {
addView(onOverlayReady)
isUnfoldHandled = true
} else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index e01583e..81bcbfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -16,12 +16,14 @@
package com.android.systemui.keyguard;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.keyguard.LockIconView.ICON_LOCK;
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
@@ -57,6 +59,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.doze.util.BurnInHelperKt;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -68,6 +71,7 @@
import com.airbnb.lottie.LottieAnimationView;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -76,6 +80,8 @@
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.List;
@@ -86,6 +92,8 @@
public class LockIconViewControllerTest extends SysuiTestCase {
private static final String UNLOCKED_LABEL = "unlocked";
+ private MockitoSession mStaticMockSession;
+
private @Mock LockIconView mLockIconView;
private @Mock AnimatedStateListDrawable mIconDrawable;
private @Mock Context mContext;
@@ -133,6 +141,10 @@
@Before
public void setUp() throws Exception {
+ mStaticMockSession = mockitoSession()
+ .mockStatic(BurnInHelperKt.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
MockitoAnnotations.initMocks(this);
when(mLockIconView.getResources()).thenReturn(mResources);
@@ -169,6 +181,11 @@
);
}
+ @After
+ public void tearDown() {
+ mStaticMockSession.finishMocking();
+ }
+
@Test
public void testIgnoreUdfpsWhenNotSupported() {
// GIVEN Udpfs sensor is NOT available
@@ -369,6 +386,42 @@
verify(mLockIconView).updateIcon(ICON_LOCK, true);
}
+ @Test
+ public void testBurnInOffsetsUpdated_onDozeAmountChanged() {
+ // GIVEN udfps enrolled
+ setupUdfps();
+ when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(true);
+
+ // GIVEN burn-in offset = 5
+ int burnInOffset = 5;
+ when(BurnInHelperKt.getBurnInOffset(anyInt(), anyBoolean())).thenReturn(burnInOffset);
+
+ // GIVEN starting state for the lock icon (keyguard)
+ setupShowLockIcon();
+ mLockIconViewController.init();
+ captureAttachListener();
+ mAttachListener.onViewAttachedToWindow(mLockIconView);
+ captureStatusBarStateListener();
+ reset(mLockIconView);
+
+ // WHEN dozing updates
+ mStatusBarStateListener.onDozingChanged(true /* isDozing */);
+ mStatusBarStateListener.onDozeAmountChanged(1f, 1f);
+
+ // THEN the view's translation is updated to use the AoD burn-in offsets
+ verify(mLockIconView).setTranslationY(burnInOffset);
+ verify(mLockIconView).setTranslationX(burnInOffset);
+ reset(mLockIconView);
+
+ // WHEN the device is no longer dozing
+ mStatusBarStateListener.onDozingChanged(false /* isDozing */);
+ mStatusBarStateListener.onDozeAmountChanged(0f, 0f);
+
+ // THEN the view is updated to NO translation (no burn-in offsets anymore)
+ verify(mLockIconView).setTranslationY(0);
+ verify(mLockIconView).setTranslationX(0);
+
+ }
private Pair<Integer, PointF> setupUdfps() {
when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
final PointF udfpsLocation = new PointF(50, 75);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index ca8903b..95e7a98c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -1,5 +1,7 @@
package com.android.systemui.qs.tiles.dialog;
+import static android.provider.Settings.Global.AIRPLANE_MODE_ON;
+
import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_VERTICAL_WEIGHT;
@@ -19,7 +21,6 @@
import static org.mockito.Mockito.when;
import android.animation.Animator;
-import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
@@ -37,7 +38,6 @@
import android.view.View;
import android.view.WindowManager;
-import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
@@ -47,7 +47,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.connectivity.AccessPointController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -70,7 +69,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Executor;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -78,8 +76,6 @@
public class InternetDialogControllerTest extends SysuiTestCase {
private static final int SUB_ID = 1;
- private static final String CONNECTED_TITLE = "Connected Wi-Fi Title";
- private static final String CONNECTED_SUMMARY = "Connected Wi-Fi Summary";
//SystemUIToast
private static final int GRAVITY_FLAGS = Gravity.FILL_HORIZONTAL | Gravity.FILL_VERTICAL;
@@ -142,7 +138,7 @@
private DialogLaunchAnimator mDialogLaunchAnimator;
private TestableResources mTestableResources;
- private MockInternetDialogController mInternetDialogController;
+ private InternetDialogController mInternetDialogController;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
private List<WifiEntry> mAccessPoints = new ArrayList<>();
private List<WifiEntry> mWifiEntries = new ArrayList<>();
@@ -170,7 +166,7 @@
when(mSystemUIToast.getGravity()).thenReturn(GRAVITY_FLAGS);
when(mSystemUIToast.getInAnimation()).thenReturn(mAnimator);
- mInternetDialogController = new MockInternetDialogController(mContext,
+ mInternetDialogController = new InternetDialogController(mContext,
mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
mSubscriptionManager, mTelephonyManager, mWifiManager,
mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher,
@@ -225,7 +221,7 @@
@Test
public void getDialogTitleText_withAirplaneModeOn_returnAirplaneMode() {
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(),
getResourcesString("airplane_mode")));
@@ -233,7 +229,7 @@
@Test
public void getDialogTitleText_withAirplaneModeOff_returnInternet() {
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(),
getResourcesString("quick_settings_internet_label")));
@@ -241,14 +237,14 @@
@Test
public void getSubtitleText_withAirplaneModeOn_returnNull() {
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
assertThat(mInternetDialogController.getSubtitleText(false)).isNull();
}
@Test
public void getSubtitleText_withWifiOff_returnWifiIsOff() {
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(false);
assertThat(mInternetDialogController.getSubtitleText(false))
@@ -263,7 +259,7 @@
@Test
public void getSubtitleText_withNoWifiEntry_returnSearchWifi() {
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
@@ -280,7 +276,7 @@
@Test
public void getSubtitleText_withWifiEntry_returnTapToConnect() {
// The preconditions WiFi Entries is already in setUp()
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
assertThat(mInternetDialogController.getSubtitleText(false))
@@ -295,7 +291,7 @@
@Test
public void getSubtitleText_deviceLockedWithWifiOn_returnUnlockToViewNetworks() {
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
@@ -305,7 +301,7 @@
@Test
public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
@@ -319,7 +315,7 @@
@Test
public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() {
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
@@ -420,7 +416,7 @@
@Test
public void onAccessPointsChanged_oneConnectedEntry_callbackConnectedEntryOnly() {
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
mAccessPoints.clear();
mAccessPoints.add(mConnectedEntry);
@@ -433,7 +429,7 @@
@Test
public void onAccessPointsChanged_noConnectedEntryAndOneOther_callbackWifiEntriesOnly() {
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
mAccessPoints.clear();
mAccessPoints.add(mWifiEntry1);
@@ -448,7 +444,7 @@
@Test
public void onAccessPointsChanged_oneConnectedEntryAndOneOther_callbackCorrectly() {
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
mAccessPoints.clear();
mAccessPoints.add(mConnectedEntry);
mAccessPoints.add(mWifiEntry1);
@@ -463,7 +459,7 @@
@Test
public void onAccessPointsChanged_oneConnectedEntryAndTwoOthers_callbackCorrectly() {
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
mAccessPoints.clear();
mAccessPoints.add(mConnectedEntry);
mAccessPoints.add(mWifiEntry1);
@@ -480,7 +476,7 @@
@Test
public void onAccessPointsChanged_oneConnectedEntryAndThreeOthers_callbackCutMore() {
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
mAccessPoints.clear();
mAccessPoints.add(mConnectedEntry);
mAccessPoints.add(mWifiEntry1);
@@ -497,7 +493,7 @@
// Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
mInternetDialogController.onAccessPointsChanged(mAccessPoints);
@@ -508,7 +504,7 @@
@Test
public void onAccessPointsChanged_oneConnectedEntryAndFourOthers_callbackCutMore() {
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
mAccessPoints.clear();
mAccessPoints.add(mConnectedEntry);
mAccessPoints.add(mWifiEntry1);
@@ -526,7 +522,7 @@
// Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
mInternetDialogController.onAccessPointsChanged(mAccessPoints);
@@ -537,7 +533,7 @@
@Test
public void onAccessPointsChanged_fourWifiEntries_callbackCutMore() {
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(true);
+ fakeAirplaneModeEnabled(true);
mAccessPoints.clear();
mAccessPoints.add(mWifiEntry1);
mAccessPoints.add(mWifiEntry2);
@@ -566,7 +562,7 @@
// Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
reset(mInternetDialogCallback);
- mInternetDialogController.setAirplaneModeEnabled(false);
+ fakeAirplaneModeEnabled(false);
mInternetDialogController.onAccessPointsChanged(mAccessPoints);
@@ -576,6 +572,23 @@
}
@Test
+ public void onAccessPointsChanged_wifiIsDefaultButNoInternetAccess_putIntoWifiEntries() {
+ reset(mInternetDialogCallback);
+ mAccessPoints.clear();
+ when(mWifiEntry1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
+ when(mWifiEntry1.isDefaultNetwork()).thenReturn(true);
+ when(mWifiEntry1.hasInternetAccess()).thenReturn(false);
+ mAccessPoints.add(mWifiEntry1);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.clear();
+ mWifiEntries.add(mWifiEntry1);
+ verify(mInternetDialogCallback)
+ .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */);
+ }
+
+ @Test
public void setMergedCarrierWifiEnabledIfNeed_carrierProvisionsEnabled_doNothing() {
when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
.thenReturn(true);
@@ -641,38 +654,7 @@
mContext.getPackageName());
}
- private class MockInternetDialogController extends InternetDialogController {
-
- private GlobalSettings mGlobalSettings;
- private boolean mIsAirplaneModeOn;
-
- MockInternetDialogController(Context context, UiEventLogger uiEventLogger,
- ActivityStarter starter, AccessPointController accessPointController,
- SubscriptionManager subscriptionManager, TelephonyManager telephonyManager,
- @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
- @Main Handler handler, @Main Executor mainExecutor,
- BroadcastDispatcher broadcastDispatcher,
- KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings,
- KeyguardStateController keyguardStateController, WindowManager windowManager,
- ToastFactory toastFactory, Handler workerHandler,
- CarrierConfigTracker carrierConfigTracker,
- LocationController locationController,
- DialogLaunchAnimator dialogLaunchAnimator) {
- super(context, uiEventLogger, starter, accessPointController, subscriptionManager,
- telephonyManager, wifiManager, connectivityManager, handler, mainExecutor,
- broadcastDispatcher, keyguardUpdateMonitor, globalSettings,
- keyguardStateController, windowManager, toastFactory, workerHandler,
- carrierConfigTracker, locationController, dialogLaunchAnimator);
- mGlobalSettings = globalSettings;
- }
-
- @Override
- boolean isAirplaneModeEnabled() {
- return mIsAirplaneModeOn;
- }
-
- public void setAirplaneModeEnabled(boolean enabled) {
- mIsAirplaneModeOn = enabled;
- }
+ private void fakeAirplaneModeEnabled(boolean enabled) {
+ when(mGlobalSettings.getInt(eq(AIRPLANE_MODE_ON), anyInt())).thenReturn(enabled ? 1 : 0);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
index a39971d..9f152e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
@@ -269,6 +269,21 @@
}
@Test
+ public void testDisableWiFiWithVcnWithUnderlyingWifi() {
+ String testSsid = "Test VCN SSID";
+ setWifiEnabled(true);
+ verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
+
+ mNetworkController.setNoNetworksAvailable(false);
+ setWifiStateForVcn(true, testSsid);
+ setWifiLevelForVcn(1);
+ verifyLastMobileDataIndicatorsForVcn(true, 1, TelephonyIcons.ICON_CWF, false);
+
+ setWifiEnabled(false);
+ verifyLastMobileDataIndicatorsForVcn(false, 1, 0, false);
+ }
+
+ @Test
public void testCallStrengh() {
if (true) return;
String testSsid = "Test SSID";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
new file mode 100644
index 0000000..db7a8516
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2021 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.unfold.util
+
+import android.animation.ValueAnimator
+import android.content.ContentResolver
+import android.database.ContentObserver
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.util.mockito.any
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ScaleAwareUnfoldProgressProviderTest : SysuiTestCase() {
+
+ @Mock
+ lateinit var contentResolver: ContentResolver
+
+ @Mock
+ lateinit var sourceProvider: UnfoldTransitionProgressProvider
+
+ @Mock
+ lateinit var sinkProvider: TransitionProgressListener
+
+ lateinit var progressProvider: ScaleAwareTransitionProgressProvider
+
+ private val sourceProviderListenerCaptor =
+ ArgumentCaptor.forClass(TransitionProgressListener::class.java)
+
+ private val animatorDurationScaleListenerCaptor =
+ ArgumentCaptor.forClass(ContentObserver::class.java)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ progressProvider = ScaleAwareTransitionProgressProvider(
+ sourceProvider,
+ contentResolver
+ )
+
+ verify(sourceProvider).addCallback(sourceProviderListenerCaptor.capture())
+ verify(contentResolver).registerContentObserver(any(), any(),
+ animatorDurationScaleListenerCaptor.capture())
+
+ progressProvider.addCallback(sinkProvider)
+ }
+
+ @Test
+ fun onTransitionStarted_animationsEnabled_eventReceived() {
+ setAnimationsEnabled(true)
+
+ source.onTransitionStarted()
+
+ verify(sinkProvider).onTransitionStarted()
+ }
+
+ @Test
+ fun onTransitionStarted_animationsNotEnabled_eventNotReceived() {
+ setAnimationsEnabled(false)
+
+ source.onTransitionStarted()
+
+ verifyNoMoreInteractions(sinkProvider)
+ }
+
+ @Test
+ fun onTransitionEnd_animationsEnabled_eventReceived() {
+ setAnimationsEnabled(true)
+
+ source.onTransitionFinished()
+
+ verify(sinkProvider).onTransitionFinished()
+ }
+
+ @Test
+ fun onTransitionEnd_animationsNotEnabled_eventNotReceived() {
+ setAnimationsEnabled(false)
+
+ source.onTransitionFinished()
+
+ verifyNoMoreInteractions(sinkProvider)
+ }
+
+ @Test
+ fun onTransitionProgress_animationsEnabled_eventReceived() {
+ setAnimationsEnabled(true)
+
+ source.onTransitionProgress(42f)
+
+ verify(sinkProvider).onTransitionProgress(42f)
+ }
+
+ @Test
+ fun onTransitionProgress_animationsNotEnabled_eventNotReceived() {
+ setAnimationsEnabled(false)
+
+ source.onTransitionProgress(42f)
+
+ verifyNoMoreInteractions(sinkProvider)
+ }
+
+ private fun setAnimationsEnabled(enabled: Boolean) {
+ val durationScale = if (enabled) {
+ 1f
+ } else {
+ 0f
+ }
+ ValueAnimator.setDurationScale(durationScale)
+ animatorDurationScaleListenerCaptor.value.dispatchChange(/* selfChange= */false)
+ }
+
+ private val source: TransitionProgressListener
+ get() = sourceProviderListenerCaptor.value
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ba11e9c..7a70bfe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24299,24 +24299,24 @@
}
enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
true /* checkShell */, "stop package");
- boolean shouldUnhibernate = false;
// writer
synchronized (mLock) {
final PackageSetting ps = mSettings.getPackageLPr(packageName);
- if (ps != null && ps.getStopped(userId) && !stopped) {
- shouldUnhibernate = true;
- }
if (!shouldFilterApplicationLocked(ps, callingUid, userId)
&& mSettings.setPackageStoppedStateLPw(this, packageName, stopped, userId)) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
- if (shouldUnhibernate) {
+ // If this would cause the app to leave force-stop, then also make sure to unhibernate the
+ // app if needed.
+ if (!stopped) {
mHandler.post(() -> {
AppHibernationManagerInternal ah =
mInjector.getLocalService(AppHibernationManagerInternal.class);
- ah.setHibernatingForUser(packageName, userId, false);
- ah.setHibernatingGlobally(packageName, false);
+ if (ah != null && ah.isHibernatingForUser(packageName, userId)) {
+ ah.setHibernatingForUser(packageName, userId, false);
+ ah.setHibernatingGlobally(packageName, false);
+ }
});
}
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 2be29d4..dfff76d 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -50,6 +50,10 @@
import static android.util.MathUtils.constrain;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
+import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC;
import static com.android.internal.util.FrameworkStatsLog.TIME_ZONE_DETECTOR_STATE__DETECTION_MODE__GEO;
@@ -4387,8 +4391,9 @@
final int userId = userInfo.getUserHandle().getIdentifier();
if (isAccessibilityShortcutUser(mContext, userId)) {
- final int software_shortcut_type = Settings.Secure.getIntForUser(resolver,
- Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId);
+ final int software_shortcut_type = convertToAccessibilityShortcutType(
+ Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE, 0, userId));
final String software_shortcut_list = Settings.Secure.getStringForUser(resolver,
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId);
final int software_shortcut_service_num = countAccessibilityServices(
@@ -4509,6 +4514,19 @@
&& !TextUtils.isEmpty(software_string);
}
+ private int convertToAccessibilityShortcutType(int shortcutType) {
+ switch (shortcutType) {
+ case Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
+ case Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
+ case Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
+ default:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
+ }
+ }
+
// Thermal event received from vendor thermal management subsystem
private static final class ThermalEventListener extends IThermalEventListener.Stub {
@Override
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7dec4e7..51c3b33 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -77,6 +77,7 @@
import android.os.PowerManager.WakeLock;
import android.os.Process;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.Slog;
@@ -782,8 +783,19 @@
// TODO(b/179091925): Move the delayed-message handling to BaseState
// If underlying is null, all underlying networks have been lost. Disconnect VCN after a
- // timeout.
+ // timeout (or immediately if in airplane mode, since the device user has indicated that
+ // the radios should all be turned off).
if (underlying == null) {
+ if (mDeps.isAirplaneModeOn(mVcnContext)) {
+ sendMessageAndAcquireWakeLock(
+ EVENT_UNDERLYING_NETWORK_CHANGED,
+ TOKEN_ALL,
+ new EventUnderlyingNetworkChangedInfo(null));
+ sendDisconnectRequestedAndAcquireWakelock(
+ DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */);
+ return;
+ }
+
setDisconnectRequestAlarm();
} else {
// Received a new Network so any previous alarm is irrelevant - cancel + clear it,
@@ -2414,6 +2426,12 @@
validationStatusCallback);
}
+ /** Checks if airplane mode is enabled. */
+ public boolean isAirplaneModeOn(@NonNull VcnContext vcnContext) {
+ return Settings.Global.getInt(vcnContext.getContext().getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+
/** Gets the elapsed real time since boot, in millis. */
public long getElapsedRealTime() {
return SystemClock.elapsedRealtime();
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index fd97557..e053dc3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -29,6 +29,7 @@
import com.android.server.apphibernation.AppHibernationService
import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.testutils.whenever
+import org.junit.Assert
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -100,8 +101,11 @@
rule.system().dataAppDirectory)
val pm = createPackageManagerService()
rule.system().validateFinalState()
- val ps = pm.getPackageSetting(TEST_PACKAGE_NAME)
- ps!!.setStopped(true, TEST_USER_ID)
+
+ TestableLooper.get(this).processAllMessages()
+
+ whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(true)
pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
@@ -112,6 +116,31 @@
}
@Test
+ fun testExitForceStop_nonExistingAppHibernationManager_doesNotThrowException() {
+ whenever(rule.mocks().injector.getLocalService(AppHibernationManagerInternal::class.java))
+ .thenReturn(null)
+
+ rule.system().stageScanExistingPackage(
+ TEST_PACKAGE_NAME,
+ 1L,
+ rule.system().dataAppDirectory)
+ val pm = createPackageManagerService()
+ rule.system().validateFinalState()
+
+ TestableLooper.get(this).processAllMessages()
+
+ whenever(appHibernationManager.isHibernatingForUser(TEST_PACKAGE_NAME, TEST_USER_ID))
+ .thenReturn(true)
+
+ try {
+ pm.setPackageStoppedState(TEST_PACKAGE_NAME, false, TEST_USER_ID)
+ TestableLooper.get(this).processAllMessages()
+ } catch (e: Exception) {
+ Assert.fail("Method throws exception when AppHibernationManager is not ready.\n$e")
+ }
+ }
+
+ @Test
fun testGetOptimizablePackages_ExcludesGloballyHibernatingPackages() {
rule.system().stageScanExistingPackage(
TEST_PACKAGE_NAME,
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index c9a8947a..7b5f0b1 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -118,6 +118,8 @@
@Test
public void testNullNetworkDoesNotTriggerDisconnect() throws Exception {
+ doReturn(false).when(mDeps).isAirplaneModeOn(any());
+
mGatewayConnection
.getUnderlyingNetworkTrackerCallback()
.onSelectedUnderlyingNetworkChanged(null);
@@ -129,6 +131,19 @@
}
@Test
+ public void testNullNetworkAirplaneModeDisconnects() throws Exception {
+ doReturn(true).when(mDeps).isAirplaneModeOn(any());
+
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState());
+ verify(mIkeSession).kill();
+ }
+
+ @Test
public void testNewNetworkTriggersMigration() throws Exception {
mGatewayConnection
.getUnderlyingNetworkTrackerCallback()