diff --git a/src/com/android/settings/display/AlwaysOnDisplaySlice.java b/src/com/android/settings/display/AlwaysOnDisplaySlice.java new file mode 100644 index 00000000000..27374ef26e8 --- /dev/null +++ b/src/com/android/settings/display/AlwaysOnDisplaySlice.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.display; + +import static android.provider.Settings.Secure.DOZE_ALWAYS_ON; +import static android.provider.Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE; + +import android.annotation.ColorInt; +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.hardware.display.AmbientDisplayConfiguration; +import android.net.Uri; +import android.os.UserHandle; +import android.provider.Settings; + +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.SliceAction; + +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.aware.AwareFeatureProvider; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.slices.CustomSliceRegistry; +import com.android.settings.slices.CustomSliceable; + +/** + * Custom {@link Slice} for Always on Display. + *

+ * We make a custom slice instead of using {@link AmbientDisplayAlwaysOnPreferenceController} + * because the controller will be unavailable if devices support aware sensor, and thus + * can not convert to slice. + *

+ * + */ +public class AlwaysOnDisplaySlice implements CustomSliceable { + private static final int MY_USER = UserHandle.myUserId(); + + private final Context mContext; + private final AmbientDisplayConfiguration mConfig; + private final AwareFeatureProvider mFeatureProvider; + + public AlwaysOnDisplaySlice(Context context) { + mContext = context; + mConfig = new AmbientDisplayConfiguration(mContext); + mFeatureProvider = FeatureFactory.getFactory(context).getAwareFeatureProvider(); + } + + @Override + public Slice getSlice() { + if (!mConfig.alwaysOnAvailableForUser(MY_USER)) { + return null; + } + + final PendingIntent toggleAction = getBroadcastIntent(mContext); + @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext); + final boolean isChecked = mConfig.alwaysOnEnabled(MY_USER); + + return new ListBuilder(mContext, CustomSliceRegistry.ALWAYS_ON_SLICE_URI, + ListBuilder.INFINITY) + .setAccentColor(color) + .addRow(new ListBuilder.RowBuilder() + .setTitle(mContext.getText(R.string.doze_always_on_title)) + .setSubtitle(mContext.getText(R.string.doze_always_on_summary)) + .setPrimaryAction( + SliceAction.createToggle(toggleAction, null /* actionTitle */, + isChecked))) + .build(); + } + + @Override + public Uri getUri() { + return CustomSliceRegistry.ALWAYS_ON_SLICE_URI; + } + + @Override + public void onNotifyChange(Intent intent) { + final boolean isChecked = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, + false); + final ContentResolver resolver = mContext.getContentResolver(); + final boolean isAwareSupported = mFeatureProvider.isSupported(mContext); + final boolean isAwareEnabled = mFeatureProvider.isEnabled(mContext); + + Settings.Secure.putInt(resolver, DOZE_ALWAYS_ON, isChecked ? 1 : 0); + Settings.Secure.putInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, + (isAwareEnabled && isAwareSupported && isChecked) ? 1 : 0); + } + + @Override + public Intent getIntent() { + return null; + } +} diff --git a/src/com/android/settings/network/TetherProvisioningActivity.java b/src/com/android/settings/network/TetherProvisioningActivity.java index bb61546594d..047c90d5443 100644 --- a/src/com/android/settings/network/TetherProvisioningActivity.java +++ b/src/com/android/settings/network/TetherProvisioningActivity.java @@ -18,7 +18,6 @@ package com.android.settings.network; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; -import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; import static android.net.TetheringManager.TETHERING_INVALID; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; @@ -28,7 +27,6 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.os.Bundle; import android.os.ResultReceiver; import android.os.UserHandle; @@ -37,8 +35,6 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; -import com.android.settings.Utils; - /** * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission * restrictions. Specifically, the provisioning apps require @@ -53,7 +49,10 @@ public class TetherProvisioningActivity extends Activity { @VisibleForTesting static final int PROVISION_REQUEST = 0; @VisibleForTesting - static final String EXTRA_SUBID = "subId"; + static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID"; + @VisibleForTesting + public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME = + "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME"; @Override public void onCreate(Bundle savedInstanceState) { @@ -62,7 +61,8 @@ public class TetherProvisioningActivity extends Activity { final int tetherType = getIntent().getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); - final int tetherSubId = getIntent().getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); + final int tetherSubId = getIntent().getIntExtra( + EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = SubscriptionManager.getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); @@ -70,11 +70,11 @@ public class TetherProvisioningActivity extends Activity { finish(); return; } - String[] provisionApp = getIntent().getStringArrayExtra(EXTRA_RUN_PROVISION); - if (provisionApp == null || provisionApp.length < 2) { - final Resources res = Utils.getResourcesForSubId(this, subId); - provisionApp = res.getStringArray( - com.android.internal.R.array.config_mobile_hotspot_provision_app); + String[] provisionApp = getIntent().getStringArrayExtra( + EXTRA_TETHER_UI_PROVISIONING_APP_NAME); + if (provisionApp == null || provisionApp.length != 2) { + Log.e(TAG, "Unexpected provision app configuration"); + return; } final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(provisionApp[0], provisionApp[1]); diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index 12397e4c8b3..a5768d3f9e6 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -27,6 +27,7 @@ import android.util.ArrayMap; import androidx.annotation.VisibleForTesting; import com.android.settings.display.AdaptiveSleepPreferenceController; +import com.android.settings.display.AlwaysOnDisplaySlice; import com.android.settings.flashlight.FlashlightSlice; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice; @@ -303,6 +304,16 @@ public class CustomSliceRegistry { .appendPath(MediaOutputSliceConstants.KEY_REMOTE_MEDIA) .build(); + /** + * Backing Uri for the Always On Slice. + */ + public static final Uri ALWAYS_ON_SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("always_on_display") + .build(); + @VisibleForTesting static final Map> sUriToSlice; @@ -325,6 +336,7 @@ public class CustomSliceRegistry { sUriToSlice.put(DARK_THEME_SLICE_URI, DarkThemeSlice.class); sUriToSlice.put(REMOTE_MEDIA_SLICE_URI, RemoteMediaSlice.class); sUriToSlice.put(MEDIA_OUTPUT_GROUP_SLICE_URI, MediaOutputGroupSlice.class); + sUriToSlice.put(ALWAYS_ON_SLICE_URI, AlwaysOnDisplaySlice.class); } public static Class getSliceClassByUri(Uri uri) { diff --git a/src/com/android/settings/wifi/tether/TetherService.java b/src/com/android/settings/wifi/tether/TetherService.java index 72ea1a9c591..59027193ed5 100644 --- a/src/com/android/settings/wifi/tether/TetherService.java +++ b/src/com/android/settings/wifi/tether/TetherService.java @@ -41,7 +41,6 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.net.TetheringManager; import android.os.IBinder; import android.os.ResultReceiver; @@ -52,10 +51,9 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; -import com.android.settings.Utils; - import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class TetherService extends Service { private static final String TAG = "TetherService"; @@ -64,7 +62,13 @@ public class TetherService extends Service { @VisibleForTesting public static final String EXTRA_RESULT = "EntitlementResult"; @VisibleForTesting - public static final String EXTRA_SUBID = "subId"; + public static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID"; + @VisibleForTesting + public static final String EXTRA_TETHER_PROVISIONING_RESPONSE = + "android.net.extra.TETHER_PROVISIONING_RESPONSE"; + @VisibleForTesting + public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION = + "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION"; // Activity results to match the activity provision protocol. // Default to something not ok. @@ -79,6 +83,11 @@ public class TetherService extends Service { private int mCurrentTypeIndex; private boolean mInProvisionCheck; + /** Intent action received from the provisioning app when entitlement check completes. */ + private String mExpectedProvisionResponseAction = null; + /** Intent action sent to the provisioning app to request an entitlement check. */ + private String mProvisionAction; + private int mSubId = INVALID_SUBSCRIPTION_ID; private TetherServiceWrapper mWrapper; private ArrayList mCurrentTethers; private ArrayMap> mPendingCallbacks; @@ -92,10 +101,6 @@ public class TetherService extends Service { public void onCreate() { super.onCreate(); if (DEBUG) Log.d(TAG, "Creating TetherService"); - String provisionResponse = getResourceForActiveDataSubId().getString( - com.android.internal.R.string.config_mobile_hotspot_provision_response); - registerReceiver(mReceiver, new IntentFilter(provisionResponse), - android.Manifest.permission.TETHER_PRIVILEGED, null); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); mCurrentTethers = stringToTethers(prefs.getString(KEY_TETHERS, "")); mCurrentTypeIndex = 0; @@ -106,10 +111,28 @@ public class TetherService extends Service { mPendingCallbacks.put(TETHERING_ETHERNET, new ArrayList()); } + // Registers the broadcast receiver for the specified response action, first unregistering + // the receiver if it was registered for a different response action. + private void maybeRegisterReceiver(final String responseAction) { + if (Objects.equals(responseAction, mExpectedProvisionResponseAction)) return; + + if (mExpectedProvisionResponseAction != null) unregisterReceiver(mReceiver); + + registerReceiver(mReceiver, new IntentFilter(responseAction), + android.Manifest.permission.TETHER_PRIVILEGED, null /* handler */); + mExpectedProvisionResponseAction = responseAction; + if (DEBUG) Log.d(TAG, "registerReceiver " + responseAction); + } + + private int stopSelfAndStartNotSticky() { + stopSelf(); + return START_NOT_STICKY; + } + @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (intent.hasExtra(EXTRA_SUBID)) { - final int tetherSubId = intent.getIntExtra(EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); + if (intent.hasExtra(EXTRA_TETHER_SUBID)) { + final int tetherSubId = intent.getIntExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); @@ -118,7 +141,9 @@ public class TetherService extends Service { } return START_NOT_STICKY; } + mSubId = subId; } + if (intent.hasExtra(EXTRA_ADD_TETHER_TYPE)) { int type = intent.getIntExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_INVALID); ResultReceiver callback = intent.getParcelableExtra(EXTRA_PROVISION_CALLBACK); @@ -128,9 +153,9 @@ public class TetherService extends Service { callbacksForType.add(callback); } else { // Invalid tether type. Just ignore this request and report failure. + Log.e(TAG, "Invalid tethering type " + type + ", stopping"); callback.send(TETHER_ERROR_UNKNOWN_IFACE, null); - stopSelf(); - return START_NOT_STICKY; + return stopSelfAndStartNotSticky(); } } @@ -140,6 +165,19 @@ public class TetherService extends Service { } } + mProvisionAction = intent.getStringExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION); + if (mProvisionAction == null) { + Log.e(TAG, "null provisioning action, stop "); + return stopSelfAndStartNotSticky(); + } + + final String response = intent.getStringExtra(EXTRA_TETHER_PROVISIONING_RESPONSE); + if (response == null) { + Log.e(TAG, "null provisioning response, stop "); + return stopSelfAndStartNotSticky(); + } + maybeRegisterReceiver(response); + if (intent.hasExtra(EXTRA_REM_TETHER_TYPE)) { if (!mInProvisionCheck) { int type = intent.getIntExtra(EXTRA_REM_TETHER_TYPE, TETHERING_INVALID); @@ -158,8 +196,7 @@ public class TetherService extends Service { } else if (!mInProvisionCheck) { // If we aren't running any provisioning, no reason to stay alive. if (DEBUG) Log.d(TAG, "Stopping self. startid: " + startId); - stopSelf(); - return START_NOT_STICKY; + return stopSelfAndStartNotSticky(); } // We want to be started if we are killed accidently, so that we can be sure we finish // the check. @@ -175,7 +212,10 @@ public class TetherService extends Service { SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); prefs.edit().putString(KEY_TETHERS, tethersToString(mCurrentTethers)).commit(); - unregisterReceiver(mReceiver); + if (mExpectedProvisionResponseAction != null) { + unregisterReceiver(mReceiver); + mExpectedProvisionResponseAction = null; + } if (DEBUG) Log.d(TAG, "Destroying TetherService"); super.onDestroy(); } @@ -220,26 +260,26 @@ public class TetherService extends Service { } private void startProvisioning(int index) { - if (index < mCurrentTethers.size()) { - Intent intent = getProvisionBroadcastIntent(index); - setEntitlementAppActive(index); + if (index >= mCurrentTethers.size()) return; - if (DEBUG) Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction() + Intent intent = getProvisionBroadcastIntent(index); + setEntitlementAppActive(index); + + if (DEBUG) { + Log.d(TAG, "Sending provisioning broadcast: " + intent.getAction() + " type: " + mCurrentTethers.get(index)); - - sendBroadcast(intent); - mInProvisionCheck = true; } + + sendBroadcast(intent); + mInProvisionCheck = true; } private Intent getProvisionBroadcastIntent(int index) { - String provisionAction = getResourceForActiveDataSubId().getString( - com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); - final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); - Intent intent = new Intent(provisionAction); + if (mProvisionAction == null) Log.wtf(TAG, "null provisioning action"); + Intent intent = new Intent(mProvisionAction); int type = mCurrentTethers.get(index); intent.putExtra(TETHER_CHOICE, type); - intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId); + intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, mSubId); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); @@ -282,27 +322,30 @@ public class TetherService extends Service { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Got provision result " + intent); - String provisionResponse = getResourceForActiveDataSubId().getString( - com.android.internal.R.string.config_mobile_hotspot_provision_response); - if (provisionResponse.equals(intent.getAction())) { - if (!mInProvisionCheck) { - Log.e(TAG, "Unexpected provision response " + intent); - return; - } - int checkType = mCurrentTethers.get(mCurrentTypeIndex); - mInProvisionCheck = false; - int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT); - if (result != RESULT_OK) disableTethering(checkType); - fireCallbacksForType(checkType, result); + if (!intent.getAction().equals(mExpectedProvisionResponseAction)) { + Log.e(TAG, "Received provisioning response for unexpected action=" + + intent.getAction() + ", expected=" + mExpectedProvisionResponseAction); + return; + } - if (++mCurrentTypeIndex >= mCurrentTethers.size()) { - // We are done with all checks, time to die. - stopSelf(); - } else { - // Start the next check in our list. - startProvisioning(mCurrentTypeIndex); - } + if (!mInProvisionCheck) { + Log.e(TAG, "Unexpected provisioning response when not in provisioning check" + + intent); + return; + } + int checkType = mCurrentTethers.get(mCurrentTypeIndex); + mInProvisionCheck = false; + int result = intent.getIntExtra(EXTRA_RESULT, RESULT_DEFAULT); + if (result != RESULT_OK) disableTethering(checkType); + fireCallbacksForType(checkType, result); + + if (++mCurrentTypeIndex >= mCurrentTethers.size()) { + // We are done with all checks, time to die. + stopSelf(); + } else { + // Start the next check in our list. + startProvisioning(mCurrentTypeIndex); } } }; @@ -321,8 +364,7 @@ public class TetherService extends Service { /** * A static helper class used for tests. UsageStatsManager cannot be mocked out because - * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot - * be mocked. This class can be mocked out instead. + * it's marked final. This class can be mocked out instead. */ @VisibleForTesting public static class TetherServiceWrapper { @@ -341,10 +383,4 @@ public class TetherService extends Service { return SubscriptionManager.getActiveDataSubscriptionId(); } } - - @VisibleForTesting - Resources getResourceForActiveDataSubId() { - final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); - return Utils.getResourcesForSubId(this, subId); - } } diff --git a/tests/robotests/src/com/android/settings/display/AlwaysOnDisplaySliceTest.java b/tests/robotests/src/com/android/settings/display/AlwaysOnDisplaySliceTest.java new file mode 100644 index 00000000000..217f92122a9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/AlwaysOnDisplaySliceTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.display; + +import static android.provider.Settings.Secure.DOZE_ALWAYS_ON; +import static android.provider.Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.hardware.display.AmbientDisplayConfiguration; +import android.net.Uri; +import android.provider.Settings; + +import androidx.slice.Slice; +import androidx.slice.SliceMetadata; +import androidx.slice.SliceProvider; +import androidx.slice.widget.SliceLiveData; + +import com.android.settings.R; +import com.android.settings.aware.AwareFeatureProvider; +import com.android.settings.slices.CustomSliceRegistry; +import com.android.settings.testutils.FakeFeatureFactory; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(RobolectricTestRunner.class) +public class AlwaysOnDisplaySliceTest { + + private Context mContext; + private AlwaysOnDisplaySlice mSlice; + private FakeFeatureFactory mFeatureFactory; + private AwareFeatureProvider mFeatureProvider; + + @Mock + private AmbientDisplayConfiguration mConfig; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mFeatureFactory = FakeFeatureFactory.setupForTest(); + mFeatureProvider = mFeatureFactory.getAwareFeatureProvider(); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + mSlice = new AlwaysOnDisplaySlice(mContext); + ReflectionHelpers.setField(mSlice, "mConfig", mConfig); + } + + @Test + public void getUri_shouldReturnCorrectSliceUri() { + final Uri uri = mSlice.getUri(); + + assertThat(uri).isEqualTo(CustomSliceRegistry.ALWAYS_ON_SLICE_URI); + } + + @Test + public void getSlice_alwaysOnNotSupported_returnNull() { + when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false); + + final Slice slice = mSlice.getSlice(); + + assertThat(slice).isNull(); + } + + @Test + public void getSlice_alwaysOnSupported_showTitleSubtitle() { + when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(true); + + final Slice slice = mSlice.getSlice(); + final SliceMetadata metadata = SliceMetadata.from(mContext, slice); + + assertThat(metadata.getTitle()).isEqualTo( + mContext.getString(R.string.doze_always_on_title)); + assertThat(metadata.getSubtitle()).isEqualTo( + mContext.getString(R.string.doze_always_on_summary)); + } + + @Test + public void onNotifyChange_toggleOff_disableAoD() { + final Intent intent = new Intent(); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, false); + + mSlice.onNotifyChange(intent); + + final ContentResolver resolver = mContext.getContentResolver(); + assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(0); + assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); + } + + @Test + public void onNotifyChange_toggleOn_awareNotSupported_enableAoD() { + final Intent intent = new Intent(); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); + when(mFeatureProvider.isEnabled(mContext)).thenReturn(false); + when(mFeatureProvider.isSupported(mContext)).thenReturn(false); + + mSlice.onNotifyChange(intent); + + final ContentResolver resolver = mContext.getContentResolver(); + assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); + assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); + } + + @Test + public void onNotifyChange_toggleOn_awareDisabled_enableAoD() { + final Intent intent = new Intent(); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); + when(mFeatureProvider.isEnabled(mContext)).thenReturn(false); + when(mFeatureProvider.isSupported(mContext)).thenReturn(true); + + mSlice.onNotifyChange(intent); + + final ContentResolver resolver = mContext.getContentResolver(); + assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); + assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(0); + } + + @Test + public void onNotifyChange_toggleOn_awareSupported_enableAoD() { + final Intent intent = new Intent(); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); + when(mFeatureProvider.isEnabled(mContext)).thenReturn(true); + when(mFeatureProvider.isSupported(mContext)).thenReturn(true); + + mSlice.onNotifyChange(intent); + + final ContentResolver resolver = mContext.getContentResolver(); + assertThat(Settings.Secure.getInt(resolver, DOZE_ALWAYS_ON, 0)).isEqualTo(1); + assertThat(Settings.Secure.getInt(resolver, DOZE_WAKE_DISPLAY_GESTURE, 0)).isEqualTo(1); + } +} diff --git a/tests/unit/src/com/android/settings/network/TetherProvisioningActivityTest.java b/tests/unit/src/com/android/settings/network/TetherProvisioningActivityTest.java index 6246d9f9c10..af29dcc8a15 100644 --- a/tests/unit/src/com/android/settings/network/TetherProvisioningActivityTest.java +++ b/tests/unit/src/com/android/settings/network/TetherProvisioningActivityTest.java @@ -18,9 +18,10 @@ package com.android.settings.network; import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE; import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK; -import static android.net.TetheringConstants.EXTRA_RUN_PROVISION; import static android.net.TetheringManager.TETHERING_WIFI; +import static com.android.settings.network.TetherProvisioningActivity.EXTRA_TETHER_SUBID; +import static com.android.settings.network.TetherProvisioningActivity.EXTRA_TETHER_UI_PROVISIONING_APP_NAME; import static com.android.settings.network.TetherProvisioningActivity.PROVISION_REQUEST; import static org.junit.Assert.assertEquals; @@ -72,7 +73,7 @@ public class TetherProvisioningActivityTest { new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) - .putExtra(TetherProvisioningActivity.EXTRA_SUBID, 10000))) { + .putExtra(TetherProvisioningActivity.EXTRA_TETHER_SUBID, 10000))) { assertEquals(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, receiver.get()); assertEquals(Lifecycle.State.DESTROYED, scenario.getState()); } @@ -82,12 +83,13 @@ public class TetherProvisioningActivityTest { public void testOnCreate_FinishWithUnavailableProvisioningApp() throws Exception { final WrappedReceiver receiver = new WrappedReceiver(); final int subId = SubscriptionManager.getActiveDataSubscriptionId(); + final String[] emptyProvisioningApp = { "", "" }; try (ActivityScenario scenario = ActivityScenario.launch( new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) - .putExtra(TetherProvisioningActivity.EXTRA_SUBID, subId) - .putExtra(EXTRA_RUN_PROVISION, new String[] { "", "" }))) { + .putExtra(EXTRA_TETHER_SUBID, subId) + .putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, emptyProvisioningApp))) { assertEquals(TetheringManager.TETHER_ERROR_PROVISIONING_FAILED, receiver.get()); assertEquals(Lifecycle.State.DESTROYED, scenario.getState()); } @@ -105,8 +107,8 @@ public class TetherProvisioningActivityTest { new Intent(Settings.ACTION_TETHER_PROVISIONING_UI) .putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI) .putExtra(EXTRA_PROVISION_CALLBACK, receiver) - .putExtra(TetherProvisioningActivity.EXTRA_SUBID, subId) - .putExtra(EXTRA_RUN_PROVISION, provisionApp))) { + .putExtra(EXTRA_TETHER_SUBID, subId) + .putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, provisionApp))) { scenario.onActivity(activity -> { assertFalse(activity.isFinishing()); activity.onActivityResult(PROVISION_REQUEST, Activity.RESULT_OK, null /* intent */); diff --git a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java index 19f29c03cfb..be030bf7dac 100644 --- a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +++ b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java @@ -27,6 +27,10 @@ import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_PROVISIONING_RESPONSE; +import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_SILENT_PROVISIONING_ACTION; +import static com.android.settings.wifi.tether.TetherService.EXTRA_TETHER_SUBID; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; @@ -228,8 +232,10 @@ public class TetherServiceTest extends ServiceTestCase { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, TETHERING_WIFI); intent.putExtra(EXTRA_RUN_PROVISION, true); + intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, TEST_NO_UI_ACTION); intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver); - intent.putExtra(TetherService.EXTRA_SUBID, 1 /* Tested subId number */); + intent.putExtra(EXTRA_TETHER_SUBID, 1 /* Tested subId number */); + intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, TEST_RESPONSE_ACTION); startService(intent); SystemClock.sleep(PROVISION_TIMEOUT); @@ -242,8 +248,10 @@ public class TetherServiceTest extends ServiceTestCase { Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_RUN_PROVISION, true); + intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, TEST_NO_UI_ACTION); intent.putExtra(EXTRA_PROVISION_CALLBACK, mResultReceiver); - intent.putExtra(TetherService.EXTRA_SUBID, INVALID_SUBSCRIPTION_ID); + intent.putExtra(EXTRA_TETHER_SUBID, INVALID_SUBSCRIPTION_ID); + intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, TEST_RESPONSE_ACTION); startService(intent); }