Merge "[Settings] Code refactor for async Lifecycle listening" into tm-dev
diff --git a/res/layout/accessibility_text_reading_reset_button.xml b/res/layout/accessibility_text_reading_reset_button.xml
index f3691e1..a0bdcba 100644
--- a/res/layout/accessibility_text_reading_reset_button.xml
+++ b/res/layout/accessibility_text_reading_reset_button.xml
@@ -27,14 +27,11 @@
android:id="@+id/reset_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center|end"
+ android:layout_gravity="center_vertical|start"
android:paddingVertical="14dp"
- android:background="@null"
android:drawableStart="@drawable/ic_history"
android:drawablePadding="9dp"
- android:drawableTint="?android:attr/colorAccent"
- android:textColor="?android:attr/colorAccent"
- android:textSize="16sp"
- android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
- android:text="@string/accessibility_text_reading_reset_button_title"/>
+ android:drawableTint="@color/settingslib_btn_colored_text_material"
+ android:text="@string/accessibility_text_reading_reset_button_title"
+ style="@style/ActionPrimaryButton"/>
</FrameLayout>
diff --git a/res/layout/icon_discrete_slider.xml b/res/layout/icon_discrete_slider.xml
index b1d960f..47be5ef 100644
--- a/res/layout/icon_discrete_slider.xml
+++ b/res/layout/icon_discrete_slider.xml
@@ -19,6 +19,7 @@
android:id="@+id/seekbar_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clipChildren="false"
android:background="?android:colorBackground"
android:gravity="center_vertical">
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 37e71e2..5248da6 100755
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -18,8 +18,6 @@
<dimen name="appwidget_width">421dip</dimen>
<dimen name="appwidget_height">68dip</dimen>
- <dimen name="captioning_preview_height">100dp</dimen>
-
<!-- ActionBar height -->
<dimen name="actionbar_size">46dip</dimen>
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
index 4e4a1d3..015a6af 100755
--- a/res/values-sw600dp-land/dimens.xml
+++ b/res/values-sw600dp-land/dimens.xml
@@ -19,8 +19,6 @@
<dimen name="screen_margin_top">72dip</dimen>
<dimen name="screen_margin_bottom">48dip</dimen>
- <dimen name="captioning_preview_height">150dp</dimen>
-
<dimen name="confirm_credentials_top_padding">20dp</dimen>
<dimen name="confirm_credentials_top_margin">24dp</dimen>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index b67bb22..c80e42c 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -49,7 +49,7 @@
<dimen name="pager_tabs_title_padding">16dp</dimen>
<dimen name="pager_tabs_selected_indicator_height">3dp</dimen>
- <dimen name="captioning_preview_height">200dp</dimen>
+ <dimen name="captioning_preview_height">300dp</dimen>
<dimen name="autoclick_preview_height">200dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a398c38..f87b489 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2931,6 +2931,8 @@
<string name="auto_rotate_screen_summary">Automatically adjust the screen orientation when you move your phone between portrait and landscape</string>
<!-- Accessibility description for auto rotate learn more link [CHAR LIMIT=NONE] -->
<string name="auto_rotate_link_a11y">Learn more about auto-rotate</string>
+ <!-- Accessibility summary text for auto rotate [CHAR LIMIT=60] -->
+ <string name="auto_rotate_summary_a11y">When you move your phone between portrait and landscape</string>
<!-- Display settings screen, screen resolution settings title [CHAR LIMIT=30] -->
<string name="screen_resolution_title">Screen resolution</string>
diff --git a/res/xml/accessibility_text_reading_options.xml b/res/xml/accessibility_text_reading_options.xml
index ad742c9..7fd5ff9 100644
--- a/res/xml/accessibility_text_reading_options.xml
+++ b/res/xml/accessibility_text_reading_options.xml
@@ -27,7 +27,7 @@
<com.android.settings.widget.LabeledSeekBarPreference
android:key="font_size"
- android:selectable="false"
+ android:selectable="true"
android:summary="@string/short_summary_font_size"
android:title="@string/title_font_size"
settings:iconEnd="@drawable/ic_add_24dp"
@@ -38,7 +38,7 @@
<com.android.settings.widget.LabeledSeekBarPreference
android:key="display_size"
- android:selectable="false"
+ android:selectable="true"
android:summary="@string/screen_zoom_short_summary"
android:title="@string/screen_zoom_title"
settings:iconEnd="@drawable/ic_add_24dp"
diff --git a/src/com/android/settings/accessibility/CaptionAppearanceFragment.java b/src/com/android/settings/accessibility/CaptionAppearanceFragment.java
index 13055be..53c1dd0 100644
--- a/src/com/android/settings/accessibility/CaptionAppearanceFragment.java
+++ b/src/com/android/settings/accessibility/CaptionAppearanceFragment.java
@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
import android.app.settings.SettingsEnums;
import android.content.ContentResolver;
import android.content.Context;
@@ -400,6 +402,7 @@
}
refreshPreviewText();
+ enableCaptioningManager();
}
@Override
@@ -409,16 +412,26 @@
Settings.Secure.putString(
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE, (String) value);
refreshPreviewText();
+ enableCaptioningManager();
} else if (mFontSize == preference) {
Settings.Secure.putFloat(
cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
Float.parseFloat((String) value));
refreshPreviewText();
+ enableCaptioningManager();
}
return true;
}
+ private void enableCaptioningManager() {
+ if (mCaptioningManager.isEnabled()) {
+ return;
+ }
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, ON);
+ }
+
@Override
public int getHelpResource() {
return R.string.help_url_caption;
diff --git a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java
index 71f47cc..06f8276 100644
--- a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java
@@ -51,6 +51,11 @@
@Override
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ final boolean isEnabled = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
+ if (enabled == isEnabled) {
+ return;
+ }
+
if (enabled) {
showQuickSettingsTooltipIfNeeded(QuickSettingsTooltipType.GUIDE_TO_DIRECT_USE);
}
diff --git a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java
index ac4408f..208d5c1 100644
--- a/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleDaltonizerPreferenceFragment.java
@@ -166,6 +166,11 @@
@Override
protected void onPreferenceToggled(String preferenceKey, boolean enabled) {
+ final boolean isEnabled = Settings.Secure.getInt(getContentResolver(), ENABLED, OFF) == ON;
+ if (enabled == isEnabled) {
+ return;
+ }
+
if (enabled) {
showQuickSettingsTooltipIfNeeded(QuickSettingsTooltipType.GUIDE_TO_DIRECT_USE);
}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
index 8eb71df..96acd43 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java
@@ -22,6 +22,7 @@
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.WindowManager;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
@@ -75,7 +76,12 @@
mRootView = LayoutInflater.from(builder.getContext())
.inflate(R.layout.dialog_sim_status, null /* parent */);
mController.initialize();
- return builder.setView(mRootView).create();
+
+ Dialog dlg = builder.setView(mRootView).create();
+ dlg.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
+ WindowManager.LayoutParams.FLAG_SECURE);
+
+ return dlg;
}
@Override
@@ -94,7 +100,7 @@
/**
* View ID(s) which is digit format (instead of decimal number) text.
**/
- private static final int [] sViewIdsInDigitFormat = IntStream
+ private static final int[] sViewIdsInDigitFormat = IntStream
.of(SimStatusDialogController.ICCID_INFO_VALUE_ID,
SimStatusDialogController.PHONE_NUMBER_VALUE_ID,
SimStatusDialogController.EID_INFO_VALUE_ID)
@@ -107,8 +113,7 @@
}
if (TextUtils.isEmpty(text)) {
text = getResources().getString(R.string.device_info_default);
- }
- else if (Arrays.binarySearch(sViewIdsInDigitFormat, viewId) >= 0) {
+ } else if (Arrays.binarySearch(sViewIdsInDigitFormat, viewId) >= 0) {
text = PhoneNumberUtil.expandByTts(text);
}
textView.setText(text);
diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java
index d29a64e..093c845 100644
--- a/src/com/android/settings/display/SmartAutoRotateController.java
+++ b/src/com/android/settings/display/SmartAutoRotateController.java
@@ -35,7 +35,6 @@
import android.service.rotationresolver.RotationResolverService;
import android.text.TextUtils;
-import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
@@ -82,10 +81,6 @@
context);
}
- public void init(Lifecycle lifecycle) {
- lifecycle.addObserver(this);
- }
-
@Override
public int getAvailabilityStatus() {
if (!isRotationResolverServiceAvailable(mContext)) {
diff --git a/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java b/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java
index 1b4e998..36d3006 100644
--- a/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java
+++ b/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java
@@ -64,7 +64,6 @@
@Override
public void onAttach(Context context) {
super.onAttach(context);
- use(SmartAutoRotateController.class).init(getLifecycle());
DeviceStateAutoRotationHelper.initControllers(
getLifecycle(),
useAll(DeviceStateAutoRotateSettingController.class)
diff --git a/src/com/android/settings/network/helper/LifecycleCallbackAdapter.java b/src/com/android/settings/network/helper/LifecycleCallbackAdapter.java
new file mode 100644
index 0000000..548eae5
--- /dev/null
+++ b/src/com/android/settings/network/helper/LifecycleCallbackAdapter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.helper;
+
+import androidx.annotation.MainThread;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A {@link androidx.lifecycle.LifecycleObserver} implementation of adapter over callback.
+ *
+ * Which including:
+ * 1. Request to active callback when Lifecycle.State.STARTED
+ * 2. Request to inactive callback when Lifecycle.State.STOPPED
+ * 3. Close (no further resume) when Lifecycle.State.DESTROYED
+ */
+@VisibleForTesting
+abstract class LifecycleCallbackAdapter implements LifecycleEventObserver, AutoCloseable {
+ private static final String TAG = "LifecycleCallbackAdapter";
+ private AtomicReference<Lifecycle> mLifecycle = new AtomicReference<Lifecycle>();
+
+ /**
+ * Constructor
+ * @param lifecycle {@link Lifecycle} to monitor
+ */
+ @VisibleForTesting
+ protected LifecycleCallbackAdapter(@NonNull Lifecycle lifecycle) {
+ mLifecycle.set(lifecycle);
+ lifecycle.addObserver(this);
+ }
+
+ /**
+ * Get {@link Lifecycle} under monitor.
+ * @return {@link Lifecycle}. Return {@code null} when closed.
+ */
+ @VisibleForTesting
+ public Lifecycle getLifecycle() {
+ return mLifecycle.get();
+ }
+
+ /**
+ * Check current callback status.
+ * @return true when callback is active.
+ */
+ public abstract boolean isCallbackActive();
+
+ /**
+ * Change callback status.
+ * @param isActive true to active callback, otherwise inactive.
+ */
+ public abstract void setCallbackActive(boolean isActive);
+
+ /**
+ * Implementation of LifecycleEventObserver.
+ */
+ public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
+ if (mLifecycle.get() == null) {
+ return;
+ }
+
+ Lifecycle.State state = event.getTargetState();
+ boolean expectCallbackActive = state.isAtLeast(Lifecycle.State.STARTED);
+ if (expectCallbackActive != isCallbackActive()) {
+ setCallbackActive(expectCallbackActive);
+ }
+ if (state == Lifecycle.State.DESTROYED) {
+ close();
+ }
+ }
+
+ /**
+ * Implementation of AutoCloseable.
+ */
+ @MainThread
+ public void close() {
+ Lifecycle lifecycle = mLifecycle.getAndSet(null);
+ if (lifecycle != null) {
+ lifecycle.removeObserver(this);
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/settings/network/helper/LifecycleCallbackAdapterTest.java b/tests/unit/src/com/android/settings/network/helper/LifecycleCallbackAdapterTest.java
new file mode 100644
index 0000000..ddeb3f8
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/helper/LifecycleCallbackAdapterTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.network.helper;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class LifecycleCallbackAdapterTest implements LifecycleOwner {
+
+ private final LifecycleRegistry mRegistry = LifecycleRegistry.createUnsafe(this);
+
+ private TestObj mTarget;
+
+ @Before
+ public void setUp() {
+ mTarget = new TestObj(getLifecycle());
+ }
+
+ public Lifecycle getLifecycle() {
+ return mRegistry;
+ }
+
+ @Test
+ public void lifecycle_get_lifecycleToMonitor() {
+ assertThat(mTarget.getLifecycle()).isEqualTo(mRegistry);
+ }
+
+ @Test
+ public void lifecycle_stateChangeToStart_callbackActive() {
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
+
+ assertThat(mTarget.getCallbackCount()).isEqualTo(0);
+ assertThat(mTarget.isCallbackActive()).isEqualTo(Boolean.FALSE);
+
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
+
+ assertThat(mTarget.getCallbackCount()).isEqualTo(1);
+ assertThat(mTarget.isCallbackActive()).isEqualTo(Boolean.TRUE);
+ }
+
+ @Test
+ public void lifecycle_stateChangeToStop_callbackInActive() {
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
+
+ assertThat(mTarget.getCallbackCount()).isEqualTo(2);
+ assertThat(mTarget.isCallbackActive()).isEqualTo(Boolean.FALSE);
+ }
+
+ @Test
+ public void lifecycle_stateChangeToDestroy_noFurtherActive() {
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
+
+ assertThat(mTarget.getCallbackCount()).isEqualTo(2);
+ assertThat(mTarget.isCallbackActive()).isEqualTo(Boolean.FALSE);
+
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
+
+ assertThat(mTarget.getCallbackCount()).isEqualTo(2);
+ assertThat(mTarget.isCallbackActive()).isEqualTo(Boolean.FALSE);
+ }
+
+ public static class TestObj extends LifecycleCallbackAdapter {
+ boolean mIsActive;
+ int mNumberOfCallback;
+
+ public TestObj(Lifecycle lifecycle) {
+ super(lifecycle);
+ }
+
+ public boolean isCallbackActive() {
+ return mIsActive;
+ }
+
+ public void setCallbackActive(boolean isActive) {
+ mIsActive = isActive;
+ mNumberOfCallback ++;
+ }
+
+ protected int getCallbackCount() {
+ return mNumberOfCallback;
+ }
+ }
+}