Snap for 11260009 from 2d2fc79edd to 24Q2-release
Change-Id: Ic1fdbe16153c074cf35d3818680db805857cfcab
This commit is contained in:
@@ -787,4 +787,7 @@
|
||||
|
||||
<!-- Whether location services setting is available or not. -->
|
||||
<bool name="config_show_location_services">true</bool>
|
||||
|
||||
<!-- Whether to disable location toggle for ChromeOS devices-->
|
||||
<bool name="config_disable_location_toggle_for_chrome">false</bool>
|
||||
</resources>
|
||||
|
||||
@@ -663,6 +663,8 @@
|
||||
<string name="location_settings_footer_learn_more_content_description">
|
||||
Learn more about Location settings
|
||||
</string>
|
||||
<!-- Tooltip for switchbar on Chrome devices. [CHAR LIMIT=90]-->
|
||||
<string name="location_settings_tooltip_text_for_chrome">To change location access, go to Settings > Security and Privacy > Privacy controls</string>
|
||||
|
||||
<!-- Main Settings screen setting option title for the item to take you to the accounts screen [CHAR LIMIT=22] -->
|
||||
<string name="account_settings_title">Accounts</string>
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
android:title="@string/network_operator_category"
|
||||
settings:controller="com.android.settings.network.telephony.NetworkPreferenceCategoryController">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
<com.android.settings.spa.preference.ComposePreference
|
||||
android:key="auto_select_key"
|
||||
android:title="@string/select_automatically"
|
||||
settings:controller="com.android.settings.network.telephony.gsm.AutoSelectPreferenceController"/>
|
||||
|
||||
@@ -31,7 +31,9 @@ import android.util.Log;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** A class to dynamically manage per apps {@link NetworkPolicyManager} POLICY_ flags. */
|
||||
@@ -183,10 +185,21 @@ public final class DynamicDenylistManager {
|
||||
/** Dump the data stored in the {@link SharedPreferences}. */
|
||||
public void dump(PrintWriter writer) {
|
||||
writer.println("Dump of DynamicDenylistManager:");
|
||||
writer.println("\tManualDenylist: " + getPackageNames(mContext,
|
||||
getDenylistAllUids(getManualDenylistPref())));
|
||||
writer.println("\tDynamicDenylist: " + getPackageNames(mContext,
|
||||
getDenylistAllUids(getDynamicDenylistPref())));
|
||||
final List<String> manualDenyList =
|
||||
getPackageNames(mContext, getDenylistAllUids(getManualDenylistPref()));
|
||||
writer.println("\tManualDenylist:");
|
||||
if (manualDenyList != null) {
|
||||
manualDenyList.forEach(packageName -> writer.println("\t\t" + packageName));
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
final List<String> dynamicDenyList =
|
||||
getPackageNames(mContext, getDenylistAllUids(getDynamicDenylistPref()));
|
||||
writer.println("\tDynamicDenylist:");
|
||||
if (dynamicDenyList != null) {
|
||||
dynamicDenyList.forEach(packageName -> writer.println("\t\t" + packageName));
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Integer> getDenylistAllUids(SharedPreferences sharedPreferences) {
|
||||
@@ -230,13 +243,13 @@ public final class DynamicDenylistManager {
|
||||
return mContext.getSharedPreferences(PREF_KEY_DYNAMIC_DENY, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
private static String getPackageNames(Context context, Set<Integer> uids) {
|
||||
private static List<String> getPackageNames(Context context, Set<Integer> uids) {
|
||||
if (uids == null || uids.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
uids.forEach(uid -> builder.append(pm.getNameForUid(uid) + " "));
|
||||
return builder.toString();
|
||||
final List<String> packageNames = new ArrayList<>(uids.size());
|
||||
uids.forEach(uid -> packageNames.add(pm.getNameForUid(uid)));
|
||||
return packageNames;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,8 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
|
||||
localeInfo.getFullNameNative()),
|
||||
getString(R.string.desc_system_locale_addition),
|
||||
localeTag);
|
||||
mMetricsFeatureProvider.action(this,
|
||||
SettingsEnums.ACTION_NOTIFICATION_FOR_SYSTEM_LOCALE);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "Unable to find info for package: " + mPackageName);
|
||||
|
||||
@@ -245,6 +245,7 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
|
||||
}
|
||||
mAdapter.setCacheItemList();
|
||||
} else if (requestCode == DIALOG_ADD_SYSTEM_LOCALE) {
|
||||
int action = SettingsEnums.ACTION_CANCEL_SYSTEM_LOCALE_FROM_RECOMMENDATION;
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
localeInfo = (LocaleStore.LocaleInfo) data.getExtras().getSerializable(
|
||||
LocaleDialogFragment.ARG_TARGET_LOCALE);
|
||||
@@ -252,7 +253,9 @@ public class LocaleListEditor extends RestrictedSettingsFragment implements View
|
||||
getContext().getContentResolver(),
|
||||
Settings.System.LOCALE_PREFERENCES);
|
||||
mAdapter.addLocale(mayAppendUnicodeTags(localeInfo, preferencesTags));
|
||||
action = SettingsEnums.ACTION_ADD_SYSTEM_LOCALE_FROM_RECOMMENDATION;
|
||||
}
|
||||
mMetricsFeatureProvider.action(getContext(), action);
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.settings.localepicker.AppLocalePickerActivity.EXTRA_NO
|
||||
import static com.android.settings.localepicker.LocaleListEditor.EXTRA_SYSTEM_LOCALE_DIALOG_TYPE;
|
||||
import static com.android.settings.localepicker.LocaleListEditor.LOCALE_SUGGESTION;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
@@ -32,6 +33,8 @@ import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
/**
|
||||
* An Activity that launches the system locale settings page.
|
||||
*/
|
||||
@@ -60,6 +63,8 @@ public class NotificationActionActivity extends AppCompatActivity {
|
||||
actionIntent.putExtra(EXTRA_APP_LOCALE, appLocale);
|
||||
actionIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
getLauncher().launch(actionIntent);
|
||||
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().action(this,
|
||||
SettingsEnums.ACTION_NOTIFICATION_CLICK_FOR_SYSTEM_LOCALE);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.settings.localepicker;
|
||||
import static com.android.settings.localepicker.AppLocalePickerActivity.EXTRA_APP_LOCALE;
|
||||
import static com.android.settings.localepicker.AppLocalePickerActivity.EXTRA_NOTIFICATION_ID;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -26,6 +27,8 @@ import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
|
||||
/**
|
||||
* A Broadcast receiver that handles the locale notification which is swiped away.
|
||||
*/
|
||||
@@ -41,6 +44,8 @@ public class NotificationCancelReceiver extends BroadcastReceiver {
|
||||
Log.i(TAG, "Locale notification is swiped away.");
|
||||
if (savedNotificationID == notificationId) {
|
||||
getNotificationController(context).incrementDismissCount(appLocale);
|
||||
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().action(context,
|
||||
SettingsEnums.ACTION_NOTIFICATION_SWIPE_FOR_SYSTEM_LOCALE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@ import android.location.SettingInjectorService;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceGroup;
|
||||
@@ -72,6 +74,13 @@ public class LocationSettings extends DashboardFragment implements
|
||||
private RecentLocationAccessPreferenceController mController;
|
||||
private ContentObserver mContentObserver;
|
||||
|
||||
/**
|
||||
* Read-only boot property used to enable/disable geolocation toggle as part of privacy hub
|
||||
* feature for chrome.
|
||||
*/
|
||||
private static final String RO_BOOT_ENABLE_PRIVACY_HUB_FOR_CHROME =
|
||||
"ro.boot.enable_privacy_hub_for_chrome";
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.LOCATION;
|
||||
@@ -83,6 +92,7 @@ public class LocationSettings extends DashboardFragment implements
|
||||
final SettingsActivity activity = (SettingsActivity) getActivity();
|
||||
final SettingsMainSwitchBar switchBar = activity.getSwitchBar();
|
||||
switchBar.setTitle(getContext().getString(R.string.location_settings_primary_switch_title));
|
||||
updateChromeSwitchBarPreference(switchBar);
|
||||
switchBar.show();
|
||||
mSwitchBarController = new LocationSwitchBarController(activity, switchBar,
|
||||
getSettingsLifecycle());
|
||||
@@ -161,4 +171,17 @@ public class LocationSettings extends DashboardFragment implements
|
||||
*/
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider(R.xml.location_settings);
|
||||
|
||||
/**
|
||||
* Update switchbar config in case of Chrome devices and location is managed by chrome.
|
||||
*/
|
||||
private void updateChromeSwitchBarPreference(final SettingsMainSwitchBar switchBar) {
|
||||
if (getContext().getResources().getBoolean(R.bool.config_disable_location_toggle_for_chrome)
|
||||
&& SystemProperties.getBoolean(RO_BOOT_ENABLE_PRIVACY_HUB_FOR_CHROME, false)) {
|
||||
Log.i(TAG, "Disabling location toggle for chrome devices");
|
||||
switchBar.setClickable(false);
|
||||
switchBar.setTooltipText(getResources().getString(
|
||||
R.string.location_settings_tooltip_text_for_chrome));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* 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.AnyThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A {@link LifecycleCallbackAdapter} which support carrying a result from any threads back to UI
|
||||
* thread through {@link #postResult(T)}.
|
||||
*
|
||||
* A {@link Consumer<T>} would be invoked from UI thread for further processing on the result.
|
||||
*
|
||||
* Note: Result not in STARTED or RESUMED stage will be discarded silently.
|
||||
* This is to align with the criteria set within
|
||||
* {@link LifecycleCallbackAdapter#onStateChanged()}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public class LifecycleCallbackConverter<T> extends LifecycleCallbackAdapter {
|
||||
private static final String TAG = "LifecycleCallbackConverter";
|
||||
|
||||
private final Thread mUiThread;
|
||||
private final Consumer<T> mResultCallback;
|
||||
|
||||
/**
|
||||
* A record of number of active status change.
|
||||
* Even numbers (0, 2, 4, 6 ...) are inactive status.
|
||||
* Odd numbers (1, 3, 5, 7 ...) are active status.
|
||||
*/
|
||||
private final AtomicLong mNumberOfActiveStatusChange = new AtomicLong();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param lifecycle {@link Lifecycle} to monitor
|
||||
* @param resultCallback for further processing the result
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@UiThread
|
||||
public LifecycleCallbackConverter(
|
||||
@NonNull Lifecycle lifecycle, @NonNull Consumer<T> resultCallback) {
|
||||
super(lifecycle);
|
||||
mUiThread = Thread.currentThread();
|
||||
mResultCallback = resultCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post a result (from any thread) back to UI thread.
|
||||
*
|
||||
* @param result the object ready to be passed back to {@link Consumer<T>}.
|
||||
*/
|
||||
@AnyThread
|
||||
@VisibleForTesting
|
||||
public void postResult(T result) {
|
||||
/**
|
||||
* Since mNumberOfActiveStatusChange only increase, it is a concept of sequence number.
|
||||
* Carry it when sending data in between different threads allow to verify if the data
|
||||
* has arrived on time. And drop the data when expired.
|
||||
*/
|
||||
long currentNumberOfChange = mNumberOfActiveStatusChange.get();
|
||||
if (Thread.currentThread() == mUiThread) {
|
||||
dispatchExtResult(currentNumberOfChange, result); // Dispatch directly
|
||||
} else {
|
||||
postResultToUiThread(currentNumberOfChange, result);
|
||||
}
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
protected void postResultToUiThread(long numberOfStatusChange, T result) {
|
||||
ThreadUtils.postOnMainThread(() -> dispatchExtResult(numberOfStatusChange, result));
|
||||
}
|
||||
|
||||
@UiThread
|
||||
protected void dispatchExtResult(long numberOfStatusChange, T result) {
|
||||
/**
|
||||
* For a postResult() sending in between different threads, not only create a latency
|
||||
* but also enqueued into main UI thread for dispatch.
|
||||
*
|
||||
* To align behavior within {@link LifecycleCallbackAdapter#onStateChanged()},
|
||||
* some checking on both numberOfStatusChange and {@link Lifecycle} status are required.
|
||||
*/
|
||||
if (isActiveStatus(numberOfStatusChange)
|
||||
&& (numberOfStatusChange == mNumberOfActiveStatusChange.get())
|
||||
&& getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
|
||||
mResultCallback.accept(result);
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean isActiveStatus(long numberOfStatusChange) {
|
||||
return ((numberOfStatusChange & 1L) != 0L);
|
||||
}
|
||||
|
||||
/* Implementation of LifecycleCallbackAdapter */
|
||||
@UiThread
|
||||
public boolean isCallbackActive() {
|
||||
return isActiveStatus(mNumberOfActiveStatusChange.get());
|
||||
}
|
||||
|
||||
/* Implementation of LifecycleCallbackAdapter */
|
||||
@UiThread
|
||||
public void setCallbackActive(boolean updatedActiveStatus) {
|
||||
/**
|
||||
* Make sure only increase when active status got changed.
|
||||
* This is to implement the definition of mNumberOfActiveStatusChange.
|
||||
*/
|
||||
if (isCallbackActive() != updatedActiveStatus) {
|
||||
mNumberOfActiveStatusChange.getAndIncrement();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* 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 android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A {@link BroadcastReceiver} for {@link Intent}.
|
||||
*
|
||||
* This is {@link BroadcastReceiver} supported by {@link LifecycleCallbackConverter},
|
||||
* and only register when state is either START or RESUME.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public class LifecycleCallbackIntentReceiver extends LifecycleCallbackConverter<Intent> {
|
||||
private static final String TAG = "LifecycleCallbackIntentReceiver";
|
||||
|
||||
@VisibleForTesting
|
||||
protected final BroadcastReceiver mReceiver;
|
||||
|
||||
private final Runnable mRegisterCallback;
|
||||
private final Runnable mUnRegisterCallback;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param lifecycle {@link Lifecycle} to monitor
|
||||
* @param context for this BroadcastReceiver
|
||||
* @param filter the IntentFilter for BroadcastReceiver
|
||||
* @param broadcastPermission for permission when listening
|
||||
* @param scheduler for running in background thread
|
||||
* @param resultCallback for the Intent from BroadcastReceiver
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public LifecycleCallbackIntentReceiver(@NonNull Lifecycle lifecycle,
|
||||
@NonNull Context context, @NonNull IntentFilter filter,
|
||||
String broadcastPermission, Handler scheduler,
|
||||
@NonNull Consumer<Intent> resultCallback) {
|
||||
super(lifecycle, resultCallback);
|
||||
|
||||
// BroadcastReceiver
|
||||
mReceiver = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (isInitialStickyBroadcast()) {
|
||||
return;
|
||||
}
|
||||
final String action = intent.getAction();
|
||||
if ((action == null) || (action.length() <= 0)) {
|
||||
return;
|
||||
}
|
||||
postResult(intent);
|
||||
}
|
||||
};
|
||||
|
||||
// Register operation
|
||||
mRegisterCallback = () -> {
|
||||
Intent initIntent = context.registerReceiver(mReceiver,
|
||||
filter, broadcastPermission, scheduler);
|
||||
if (initIntent != null) {
|
||||
postResult(initIntent);
|
||||
}
|
||||
};
|
||||
|
||||
// Un-Register operation
|
||||
mUnRegisterCallback = () -> {
|
||||
context.unregisterReceiver(mReceiver);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallbackActive(boolean isActive) {
|
||||
super.setCallbackActive(isActive);
|
||||
Runnable op = (isActive) ? mRegisterCallback : mUnRegisterCallback;
|
||||
op.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
if (isCallbackActive()) {
|
||||
setCallbackActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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 android.telephony.TelephonyCallback;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A {@link LifecycleCallbackConverter} for supporting the register/unregister work for
|
||||
* {@link TelephonyCallback}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public class LifecycleCallbackTelephonyAdapter<T> extends LifecycleCallbackConverter<T> {
|
||||
private static final String TAG = "LifecycleCallbackTelephony";
|
||||
|
||||
private final Runnable mRegisterCallback;
|
||||
private final Runnable mUnRegisterCallback;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param lifecycle {@link Lifecycle} to monitor
|
||||
* @param telephonyManager {@link TelephonyManager} to interact with
|
||||
* @param telephonyCallback {@link TelephonyCallback}
|
||||
* @param executor {@link Executor} for receiving the notify from telephony framework.
|
||||
* @param resultCallback for the result from {@link TelephonyCallback}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public LifecycleCallbackTelephonyAdapter(@NonNull Lifecycle lifecycle,
|
||||
@NonNull TelephonyManager telephonyManager,
|
||||
@NonNull TelephonyCallback telephonyCallback,
|
||||
Executor executor, @NonNull Consumer<T> resultCallback) {
|
||||
super(lifecycle, resultCallback);
|
||||
|
||||
// Register operation
|
||||
mRegisterCallback = () -> {
|
||||
telephonyManager.registerTelephonyCallback(executor, telephonyCallback);
|
||||
};
|
||||
|
||||
// Un-Register operation
|
||||
mUnRegisterCallback = () -> {
|
||||
telephonyManager.unregisterTelephonyCallback(telephonyCallback);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallbackActive(boolean isActive) {
|
||||
super.setCallbackActive(isActive);
|
||||
Runnable op = (isActive) ? mRegisterCallback : mUnRegisterCallback;
|
||||
op.run();
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* 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 android.telephony.ServiceState;
|
||||
import android.telephony.TelephonyCallback;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A {@link LiveData} as a mapping of allowed network types reported from {@link TelephonyCallback}.
|
||||
* Only got update when Lifecycle.State is considered as STARTED or RESUMED.
|
||||
*
|
||||
* {@code null} when status unknown. Other values are {@link ServiceState}.
|
||||
*
|
||||
* @deprecated Please us {@link com.android.settings.network.telephony.ServiceStateFlowKt} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ServiceStateStatus extends LiveData<ServiceState> {
|
||||
private static final String TAG = "ServiceStateStatus";
|
||||
|
||||
@VisibleForTesting
|
||||
protected ServiceStateProducer mServiceStateProducer;
|
||||
|
||||
@VisibleForTesting
|
||||
protected LifecycleCallbackTelephonyAdapter mAdapter;
|
||||
|
||||
@VisibleForTesting
|
||||
protected Consumer<ServiceState> mLiveDataUpdater = status -> setValue(status);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param lifecycle {@link Lifecycle} to monitor
|
||||
* @param telephonyManager {@link TelephonyManager} to interact with
|
||||
* @param executor {@link Executor} for receiving the notify from telephony framework.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public ServiceStateStatus(@NonNull Lifecycle lifecycle,
|
||||
@NonNull TelephonyManager telephonyManager, Executor executor) {
|
||||
super();
|
||||
|
||||
mServiceStateProducer = new ServiceStateProducer(this);
|
||||
|
||||
mAdapter = new LifecycleCallbackTelephonyAdapter<ServiceState>(lifecycle,
|
||||
telephonyManager, mServiceStateProducer, executor, mLiveDataUpdater) {
|
||||
@Override
|
||||
public void setCallbackActive(boolean isActive) {
|
||||
super.setCallbackActive(isActive);
|
||||
if (!isActive) {
|
||||
/**
|
||||
* Set to unknown status when no longer actively monitoring
|
||||
* {@link TelephonyCallback}.
|
||||
*/
|
||||
mLiveDataUpdater.accept(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of TelephonyCallback.
|
||||
*
|
||||
* Change of allowed network type will be forward to
|
||||
* {@link LifecycleCallbackTelephonyAdapter}.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
protected static class ServiceStateProducer extends TelephonyCallback
|
||||
implements TelephonyCallback.ServiceStateListener {
|
||||
private final ServiceStateStatus mStatus;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param status {@link ServiceStateStatus}
|
||||
*/
|
||||
public ServiceStateProducer(ServiceStateStatus status) {
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceStateChanged(ServiceState serviceState) {
|
||||
mStatus.mAdapter.postResult(serviceState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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 android.telephony.TelephonyCallback;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A {@link LiveData} as a mapping of voice call state reported from {@link TelephonyCallback}.
|
||||
* Only got update when Lifecycle.State is considered as STARTED or RESUMED.
|
||||
*
|
||||
* {@code null} when status unknown. Other values are TelephonyManager#CALL_STATE_IDLE,
|
||||
* TelephonyManager#CALL_STATE_RINGING and TelephonyManager#CALL_STATE_OFFHOOK.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public class VoiceCallStatus extends LiveData<Integer> {
|
||||
private static final String TAG = "VoiceCallStatus";
|
||||
|
||||
@VisibleForTesting
|
||||
protected CallStateProducer mCallStateProducer;
|
||||
|
||||
@VisibleForTesting
|
||||
protected LifecycleCallbackTelephonyAdapter mAdapter;
|
||||
|
||||
@VisibleForTesting
|
||||
protected Consumer<Integer> mLiveDataUpdater = status -> setValue(status);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param lifecycle {@link Lifecycle} to monitor
|
||||
* @param telephonyManager {@link TelephonyManager} to interact with
|
||||
* @param executor {@link Executor} for receiving the notify from telephony framework.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public VoiceCallStatus(@NonNull Lifecycle lifecycle,
|
||||
@NonNull TelephonyManager telephonyManager, Executor executor) {
|
||||
super();
|
||||
|
||||
mCallStateProducer = new CallStateProducer(this);
|
||||
|
||||
mAdapter = new LifecycleCallbackTelephonyAdapter<Integer>(lifecycle,
|
||||
telephonyManager, mCallStateProducer, executor, mLiveDataUpdater) {
|
||||
@Override
|
||||
public void setCallbackActive(boolean isActive) {
|
||||
super.setCallbackActive(isActive);
|
||||
if (!isActive) {
|
||||
/**
|
||||
* Set to unknown status when no longer actively monitoring
|
||||
* {@link TelephonyCallback}.
|
||||
*/
|
||||
mLiveDataUpdater.accept(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of TelephonyCallback.
|
||||
*
|
||||
* Status of voice call will be forward to {@link LifecycleCallbackTelephonyAdapter}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
protected static class CallStateProducer extends TelephonyCallback
|
||||
implements TelephonyCallback.CallStateListener {
|
||||
private final VoiceCallStatus mStatus;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param status {@link VoiceCallStatus}
|
||||
*/
|
||||
public CallStateProducer(VoiceCallStatus status) {
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallStateChanged(int state) {
|
||||
mStatus.mAdapter.postResult(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.internal.telephony.flags.Flags;
|
||||
import com.android.settings.network.AllowedNetworkTypesListener;
|
||||
import com.android.settings.network.CarrierConfigCache;
|
||||
import com.android.settings.network.SubscriptionsChangeListener;
|
||||
@@ -241,6 +242,7 @@ public class EnabledNetworkModePreferenceController extends
|
||||
public void updateConfig() {
|
||||
mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
|
||||
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(mSubId);
|
||||
final boolean flagHidePrefer3gItem = Flags.hidePrefer3gItem();
|
||||
mAllowed5gNetworkType = checkSupportedRadioBitmask(
|
||||
mTelephonyManager.getAllowedNetworkTypesForReason(
|
||||
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER),
|
||||
@@ -256,22 +258,28 @@ public class EnabledNetworkModePreferenceController extends
|
||||
CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
|
||||
mDisplay2gOptions = carrierConfig.getBoolean(
|
||||
CarrierConfigManager.KEY_PREFER_2G_BOOL);
|
||||
// TODO: Using the carrier config.
|
||||
mDisplay3gOptions = getResourcesForSubId().getBoolean(
|
||||
R.bool.config_display_network_mode_3g_option);
|
||||
|
||||
int[] carriersWithout3gMenu = getResourcesForSubId().getIntArray(
|
||||
R.array.network_mode_3g_deprecated_carrier_id);
|
||||
if ((carriersWithout3gMenu != null) && (carriersWithout3gMenu.length > 0)) {
|
||||
SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
|
||||
SubscriptionInfo subInfo = sm.getActiveSubscriptionInfo(mSubId);
|
||||
if (subInfo != null) {
|
||||
int carrierId = subInfo.getCarrierId();
|
||||
if (flagHidePrefer3gItem) {
|
||||
mDisplay3gOptions = carrierConfig.getBoolean(
|
||||
CarrierConfigManager.KEY_PREFER_3G_VISIBILITY_BOOL);
|
||||
} else {
|
||||
mDisplay3gOptions = getResourcesForSubId().getBoolean(
|
||||
R.bool.config_display_network_mode_3g_option);
|
||||
|
||||
for (int idx = 0; idx < carriersWithout3gMenu.length; idx++) {
|
||||
if (carrierId == carriersWithout3gMenu[idx]) {
|
||||
mDisplay3gOptions = false;
|
||||
break;
|
||||
int[] carriersWithout3gMenu = getResourcesForSubId().getIntArray(
|
||||
R.array.network_mode_3g_deprecated_carrier_id);
|
||||
if ((carriersWithout3gMenu != null) && (carriersWithout3gMenu.length > 0)) {
|
||||
SubscriptionManager sm = mContext.getSystemService(
|
||||
SubscriptionManager.class);
|
||||
SubscriptionInfo subInfo = sm.getActiveSubscriptionInfo(mSubId);
|
||||
if (subInfo != null) {
|
||||
int carrierId = subInfo.getCarrierId();
|
||||
|
||||
for (int idx = 0; idx < carriersWithout3gMenu.length; idx++) {
|
||||
if (carrierId == carriersWithout3gMenu[idx]) {
|
||||
mDisplay3gOptions = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme
|
||||
use(OpenNetworkSelectPagePreferenceController.class).init(mSubId);
|
||||
final AutoSelectPreferenceController autoSelectPreferenceController =
|
||||
use(AutoSelectPreferenceController.class)
|
||||
.init(getLifecycle(), mSubId)
|
||||
.init(mSubId)
|
||||
.addListener(openNetworkSelectPagePreferenceController);
|
||||
use(NetworkPreferenceCategoryController.class).init(mSubId)
|
||||
.setChildren(Arrays.asList(autoSelectPreferenceController));
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.network.telephony.gsm;
|
||||
|
||||
import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerExecutor;
|
||||
import android.os.Looper;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.ServiceState;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleEventObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.network.AllowedNetworkTypesListener;
|
||||
import com.android.settings.network.CarrierConfigCache;
|
||||
import com.android.settings.network.helper.ServiceStateStatus;
|
||||
import com.android.settings.network.telephony.MobileNetworkUtils;
|
||||
import com.android.settings.network.telephony.TelephonyTogglePreferenceController;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Preference controller for "Auto Select Network"
|
||||
*/
|
||||
public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController
|
||||
implements LifecycleEventObserver{
|
||||
private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1);
|
||||
private static final String LOG_TAG = "AutoSelectPreferenceController";
|
||||
private static final String INTERNAL_LOG_TAG_ONRESUME = "OnResume";
|
||||
private static final String INTERNAL_LOG_TAG_AFTERSET = "AfterSet";
|
||||
|
||||
private final Handler mUiHandler;
|
||||
private PreferenceScreen mPreferenceScreen;
|
||||
private AllowedNetworkTypesListener mAllowedNetworkTypesListener;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
private boolean mOnlyAutoSelectInHome;
|
||||
private List<OnNetworkSelectModeListener> mListeners;
|
||||
@VisibleForTesting
|
||||
ProgressDialog mProgressDialog;
|
||||
@VisibleForTesting
|
||||
TwoStatePreference mSwitchPreference;
|
||||
private AtomicBoolean mUpdatingConfig;
|
||||
private int mCacheOfModeStatus;
|
||||
private AtomicLong mRecursiveUpdate;
|
||||
ServiceStateStatus mServiceStateStatus;
|
||||
|
||||
public AutoSelectPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
mTelephonyManager = context.getSystemService(TelephonyManager.class);
|
||||
mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
mRecursiveUpdate = new AtomicLong();
|
||||
mUpdatingConfig = new AtomicBoolean();
|
||||
mCacheOfModeStatus = TelephonyManager.NETWORK_SELECTION_MODE_UNKNOWN;
|
||||
mListeners = new ArrayList<>();
|
||||
mUiHandler = new Handler(Looper.getMainLooper());
|
||||
mAllowedNetworkTypesListener = new AllowedNetworkTypesListener(
|
||||
new HandlerExecutor(mUiHandler));
|
||||
mAllowedNetworkTypesListener.setAllowedNetworkTypesListener(
|
||||
() -> updatePreference());
|
||||
}
|
||||
|
||||
private void updatePreference() {
|
||||
if (mPreferenceScreen != null) {
|
||||
displayPreference(mPreferenceScreen);
|
||||
}
|
||||
if (mSwitchPreference != null) {
|
||||
mRecursiveUpdate.getAndIncrement();
|
||||
updateState(mSwitchPreference);
|
||||
mRecursiveUpdate.decrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of LifecycleEventObserver.
|
||||
*/
|
||||
@SuppressWarnings("FutureReturnValueIgnored")
|
||||
public void onStateChanged(@NonNull LifecycleOwner lifecycleOwner,
|
||||
@NonNull Lifecycle.Event event) {
|
||||
switch (event) {
|
||||
case ON_START:
|
||||
mAllowedNetworkTypesListener.register(mContext, mSubId);
|
||||
break;
|
||||
case ON_RESUME:
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
queryNetworkSelectionMode(INTERNAL_LOG_TAG_ONRESUME);
|
||||
//Update UI in UI thread
|
||||
mUiHandler.post(() -> {
|
||||
if (mSwitchPreference != null) {
|
||||
mRecursiveUpdate.getAndIncrement();
|
||||
mSwitchPreference.setChecked(isChecked());
|
||||
mRecursiveUpdate.decrementAndGet();
|
||||
updateListenerValue();
|
||||
}
|
||||
});
|
||||
});
|
||||
break;
|
||||
case ON_STOP:
|
||||
mAllowedNetworkTypesListener.unregister(mContext, mSubId);
|
||||
break;
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus(int subId) {
|
||||
return MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId)
|
||||
? AVAILABLE
|
||||
: CONDITIONALLY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreferenceScreen = screen;
|
||||
mSwitchPreference = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mCacheOfModeStatus == TelephonyManager.NETWORK_SELECTION_MODE_AUTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
|
||||
preference.setSummary(null);
|
||||
final ServiceState serviceState = mTelephonyManager.getServiceState();
|
||||
if (serviceState == null) {
|
||||
preference.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (serviceState.getRoaming()) {
|
||||
preference.setEnabled(true);
|
||||
} else {
|
||||
preference.setEnabled(!mOnlyAutoSelectInHome);
|
||||
if (mOnlyAutoSelectInHome) {
|
||||
preference.setSummary(mContext.getString(
|
||||
R.string.manual_mode_disallowed_summary,
|
||||
mTelephonyManager.getSimOperatorName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setChecked(boolean isChecked) {
|
||||
if (mRecursiveUpdate.get() != 0) {
|
||||
// Changing from software are allowed and changing presentation only.
|
||||
return true;
|
||||
}
|
||||
if (isChecked) {
|
||||
setAutomaticSelectionMode();
|
||||
} else {
|
||||
if (mSwitchPreference != null) {
|
||||
Intent intent = new Intent();
|
||||
intent.setClassName(SETTINGS_PACKAGE_NAME,
|
||||
SETTINGS_PACKAGE_NAME + ".Settings$NetworkSelectActivity");
|
||||
intent.putExtra(Settings.EXTRA_SUB_ID, mSubId);
|
||||
mSwitchPreference.setIntent(intent);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Future setAutomaticSelectionMode() {
|
||||
final long startMillis = SystemClock.elapsedRealtime();
|
||||
showAutoSelectProgressBar();
|
||||
if (mSwitchPreference != null) {
|
||||
mSwitchPreference.setIntent(null);
|
||||
mSwitchPreference.setEnabled(false);
|
||||
}
|
||||
return ThreadUtils.postOnBackgroundThread(() -> {
|
||||
// set network selection mode in background
|
||||
mUpdatingConfig.set(true);
|
||||
mTelephonyManager.setNetworkSelectionModeAutomatic();
|
||||
mUpdatingConfig.set(false);
|
||||
|
||||
//Update UI in UI thread
|
||||
final long durationMillis = SystemClock.elapsedRealtime() - startMillis;
|
||||
|
||||
mUiHandler.postDelayed(() -> {
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
queryNetworkSelectionMode(INTERNAL_LOG_TAG_AFTERSET);
|
||||
|
||||
//Update UI in UI thread
|
||||
mUiHandler.post(() -> {
|
||||
mRecursiveUpdate.getAndIncrement();
|
||||
if (mSwitchPreference != null) {
|
||||
mSwitchPreference.setEnabled(true);
|
||||
mSwitchPreference.setChecked(isChecked());
|
||||
}
|
||||
mRecursiveUpdate.decrementAndGet();
|
||||
updateListenerValue();
|
||||
dismissProgressBar();
|
||||
});
|
||||
});
|
||||
}, Math.max(MINIMUM_DIALOG_TIME_MILLIS - durationMillis, 0));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization based on given subscription id.
|
||||
**/
|
||||
public AutoSelectPreferenceController init(Lifecycle lifecycle, int subId) {
|
||||
mSubId = subId;
|
||||
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
|
||||
.createForSubscriptionId(mSubId);
|
||||
final PersistableBundle carrierConfig =
|
||||
CarrierConfigCache.getInstance(mContext).getConfigForSubId(mSubId);
|
||||
mOnlyAutoSelectInHome = carrierConfig != null
|
||||
? carrierConfig.getBoolean(
|
||||
CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL)
|
||||
: false;
|
||||
|
||||
mServiceStateStatus = new ServiceStateStatus(lifecycle, mTelephonyManager,
|
||||
new HandlerExecutor(mUiHandler)) {
|
||||
@Override
|
||||
protected void setValue(ServiceState status) {
|
||||
if (status == null) {
|
||||
return;
|
||||
}
|
||||
updateUiAutoSelectValue(status);
|
||||
}
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public AutoSelectPreferenceController addListener(OnNetworkSelectModeListener lsn) {
|
||||
mListeners.add(lsn);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void queryNetworkSelectionMode(String tag) {
|
||||
mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode();
|
||||
Log.d(LOG_TAG, tag + ": query command done. mCacheOfModeStatus: " + mCacheOfModeStatus);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateUiAutoSelectValue(ServiceState status) {
|
||||
if (status == null) {
|
||||
return;
|
||||
}
|
||||
if (!mUpdatingConfig.get()) {
|
||||
int networkSelectionMode = status.getIsManualSelection()
|
||||
? TelephonyManager.NETWORK_SELECTION_MODE_MANUAL
|
||||
: TelephonyManager.NETWORK_SELECTION_MODE_AUTO;
|
||||
if (mCacheOfModeStatus == networkSelectionMode) {
|
||||
return;
|
||||
}
|
||||
mCacheOfModeStatus = networkSelectionMode;
|
||||
Log.d(LOG_TAG, "updateUiAutoSelectValue: mCacheOfModeStatus: " + mCacheOfModeStatus);
|
||||
|
||||
mRecursiveUpdate.getAndIncrement();
|
||||
updateState(mSwitchPreference);
|
||||
mRecursiveUpdate.decrementAndGet();
|
||||
updateListenerValue();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateListenerValue() {
|
||||
for (OnNetworkSelectModeListener lsn : mListeners) {
|
||||
lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private void showAutoSelectProgressBar() {
|
||||
if (mProgressDialog == null) {
|
||||
mProgressDialog = new ProgressDialog(mContext);
|
||||
mProgressDialog.setMessage(
|
||||
mContext.getResources().getString(R.string.register_automatically));
|
||||
mProgressDialog.setCanceledOnTouchOutside(false);
|
||||
mProgressDialog.setCancelable(false);
|
||||
mProgressDialog.setIndeterminate(true);
|
||||
}
|
||||
mProgressDialog.show();
|
||||
}
|
||||
|
||||
private void dismissProgressBar() {
|
||||
if (mProgressDialog != null && mProgressDialog.isShowing()) {
|
||||
try {
|
||||
mProgressDialog.dismiss();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Ignore exception since the dialog will be gone anyway.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when network select mode might get updated
|
||||
*
|
||||
* @see TelephonyManager#getNetworkSelectionMode()
|
||||
*/
|
||||
public interface OnNetworkSelectModeListener {
|
||||
void onNetworkSelectModeUpdated(int mode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.telephony.gsm
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.PersistableBundle
|
||||
import android.provider.Settings
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.ServiceState
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.android.settings.R
|
||||
import com.android.settings.Settings.NetworkSelectActivity
|
||||
import com.android.settings.network.CarrierConfigCache
|
||||
import com.android.settings.network.telephony.MobileNetworkUtils
|
||||
import com.android.settings.network.telephony.allowedNetworkTypesFlow
|
||||
import com.android.settings.network.telephony.serviceStateFlow
|
||||
import com.android.settings.spa.preference.ComposePreferenceController
|
||||
import com.android.settingslib.spa.framework.compose.OverridableFlow
|
||||
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreference
|
||||
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
|
||||
import kotlin.properties.Delegates.notNull
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
/**
|
||||
* Preference controller for "Auto Select Network"
|
||||
*/
|
||||
class AutoSelectPreferenceController @JvmOverloads constructor(
|
||||
context: Context,
|
||||
key: String,
|
||||
private val allowedNetworkTypesFlowFactory: (subId: Int) -> Flow<Long> =
|
||||
context::allowedNetworkTypesFlow,
|
||||
private val serviceStateFlowFactory: (subId: Int) -> Flow<ServiceState> =
|
||||
context::serviceStateFlow,
|
||||
private val getConfigForSubId: (subId: Int) -> PersistableBundle = { subId ->
|
||||
CarrierConfigCache.getInstance(context).getConfigForSubId(subId)
|
||||
},
|
||||
) : ComposePreferenceController(context, key) {
|
||||
|
||||
private lateinit var telephonyManager: TelephonyManager
|
||||
private val listeners = mutableListOf<OnNetworkSelectModeListener>()
|
||||
|
||||
@VisibleForTesting
|
||||
var progressDialog: ProgressDialog? = null
|
||||
|
||||
private lateinit var preference: Preference
|
||||
|
||||
private var subId by notNull<Int>()
|
||||
|
||||
/**
|
||||
* Initialization based on given subscription id.
|
||||
*/
|
||||
fun init(subId: Int): AutoSelectPreferenceController {
|
||||
this.subId = subId
|
||||
telephonyManager = mContext.getSystemService(TelephonyManager::class.java)!!
|
||||
.createForSubscriptionId(subId)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
override fun getAvailabilityStatus() =
|
||||
if (MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId)) AVAILABLE
|
||||
else CONDITIONALLY_UNAVAILABLE
|
||||
|
||||
override fun displayPreference(screen: PreferenceScreen) {
|
||||
super.displayPreference(screen)
|
||||
preference = screen.findPreference(preferenceKey)!!
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val serviceStateFlow = remember {
|
||||
serviceStateFlowFactory(subId)
|
||||
.stateIn(coroutineScope, SharingStarted.Lazily, null)
|
||||
.filterNotNull()
|
||||
}
|
||||
val isAutoOverridableFlow = remember {
|
||||
OverridableFlow(serviceStateFlow.map { !it.isManualSelection })
|
||||
}
|
||||
val isAuto by isAutoOverridableFlow.flow
|
||||
.onEach(::updateListenerValue)
|
||||
.collectAsStateWithLifecycle(initialValue = null)
|
||||
val disallowedSummary by serviceStateFlow.map(::getDisallowedSummary)
|
||||
.collectAsStateWithLifecycle(initialValue = "")
|
||||
SwitchPreference(object : SwitchPreferenceModel {
|
||||
override val title = stringResource(R.string.select_automatically)
|
||||
override val summary = { disallowedSummary }
|
||||
override val changeable = { disallowedSummary.isEmpty() }
|
||||
override val checked = { isAuto }
|
||||
override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
|
||||
if (newChecked) {
|
||||
coroutineScope.launch { setAutomaticSelectionMode(isAutoOverridableFlow) }
|
||||
} else {
|
||||
mContext.startActivity(Intent().apply {
|
||||
setClass(mContext, NetworkSelectActivity::class.java)
|
||||
putExtra(Settings.EXTRA_SUB_ID, subId)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private suspend fun getDisallowedSummary(serviceState: ServiceState): String =
|
||||
withContext(Dispatchers.Default) {
|
||||
if (!serviceState.roaming && onlyAutoSelectInHome()) {
|
||||
mContext.getString(
|
||||
R.string.manual_mode_disallowed_summary,
|
||||
telephonyManager.simOperatorName
|
||||
)
|
||||
} else ""
|
||||
}
|
||||
|
||||
private fun onlyAutoSelectInHome(): Boolean =
|
||||
getConfigForSubId(subId)
|
||||
.getBoolean(CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL)
|
||||
|
||||
private suspend fun setAutomaticSelectionMode(overrideChannel: OverridableFlow<Boolean>) {
|
||||
showAutoSelectProgressBar()
|
||||
|
||||
withContext(Dispatchers.Default) {
|
||||
val minimumDialogTimeDeferred = async { delay(MINIMUM_DIALOG_TIME) }
|
||||
telephonyManager.setNetworkSelectionModeAutomatic()
|
||||
minimumDialogTimeDeferred.await()
|
||||
}
|
||||
overrideChannel.override(true)
|
||||
|
||||
dismissProgressBar()
|
||||
}
|
||||
|
||||
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
|
||||
allowedNetworkTypesFlowFactory(subId).collectLatestWithLifecycle(viewLifecycleOwner) {
|
||||
preference.isVisible = withContext(Dispatchers.Default) {
|
||||
MobileNetworkUtils.shouldDisplayNetworkSelectOptions(mContext, subId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addListener(listener: OnNetworkSelectModeListener): AutoSelectPreferenceController {
|
||||
listeners.add(listener)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun updateListenerValue(isAuto: Boolean) {
|
||||
for (listener in listeners) {
|
||||
listener.onNetworkSelectModeUpdated(
|
||||
if (isAuto) TelephonyManager.NETWORK_SELECTION_MODE_AUTO
|
||||
else TelephonyManager.NETWORK_SELECTION_MODE_MANUAL
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAutoSelectProgressBar() {
|
||||
if (progressDialog == null) {
|
||||
progressDialog = ProgressDialog(mContext).apply {
|
||||
setMessage(mContext.resources.getString(R.string.register_automatically))
|
||||
setCanceledOnTouchOutside(false)
|
||||
setCancelable(false)
|
||||
isIndeterminate = true
|
||||
}
|
||||
}
|
||||
progressDialog?.show()
|
||||
}
|
||||
|
||||
private fun dismissProgressBar() {
|
||||
if (progressDialog?.isShowing == true) {
|
||||
try {
|
||||
progressDialog?.dismiss()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
// Ignore exception since the dialog will be gone anyway.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when network select mode might get updated
|
||||
*
|
||||
* @see TelephonyManager.getNetworkSelectionMode
|
||||
*/
|
||||
interface OnNetworkSelectModeListener {
|
||||
fun onNetworkSelectModeUpdated(mode: Int)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MINIMUM_DIALOG_TIME = 1.seconds
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import android.app.usage.UsageEvents
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.os.Build
|
||||
import android.os.IUserManager
|
||||
import android.os.RemoteException
|
||||
import android.os.ServiceManager
|
||||
import android.util.Log
|
||||
@@ -66,6 +67,9 @@ class AppNotificationRepository(
|
||||
private val notificationManager: INotificationManager = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE)
|
||||
),
|
||||
private val userManager: IUserManager = IUserManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.USER_SERVICE)
|
||||
),
|
||||
) : IAppNotificationRepository {
|
||||
fun getAggregatedUsageEvents(userIdFlow: Flow<Int>): Flow<Map<String, NotificationSentState>> =
|
||||
userIdFlow.map { userId ->
|
||||
@@ -122,6 +126,15 @@ class AppNotificationRepository(
|
||||
}
|
||||
}
|
||||
|
||||
fun isUserUnlocked(user: Int): Boolean {
|
||||
return try {
|
||||
userManager.isUserUnlocked(user)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Error calling UserManager", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNotificationSummary(app: ApplicationInfo): String {
|
||||
if (!isEnabled(app)) return context.getString(R.string.notifications_disabled)
|
||||
val channelCount = getChannelCount(app)
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.android.settingslib.spa.widget.ui.SpinnerOption
|
||||
import com.android.settingslib.spaprivileged.model.app.AppEntry
|
||||
import com.android.settingslib.spaprivileged.model.app.AppListModel
|
||||
import com.android.settingslib.spaprivileged.model.app.AppRecord
|
||||
import com.android.settingslib.spaprivileged.model.app.userId
|
||||
import com.android.settingslib.spaprivileged.template.app.AppListItemModel
|
||||
import com.android.settingslib.spaprivileged.template.app.AppListTwoTargetSwitchItem
|
||||
import com.android.settingslib.utils.StringUtil
|
||||
@@ -102,13 +103,21 @@ class AppNotificationsListModel(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSpinnerOptions(recordList: List<AppNotificationsRecord>): List<SpinnerOption> =
|
||||
SpinnerItem.entries.map {
|
||||
override fun getSpinnerOptions(recordList: List<AppNotificationsRecord>): List<SpinnerOption> {
|
||||
val options = mutableListOf(SpinnerItem.AllApps, SpinnerItem.TurnedOff)
|
||||
if (repository.isUserUnlocked(recordList[0].app.userId)) {
|
||||
options.add(0, SpinnerItem.MostRecent)
|
||||
options.add(1, SpinnerItem.MostFrequent)
|
||||
}
|
||||
|
||||
return options.map {
|
||||
SpinnerOption(
|
||||
id = it.ordinal,
|
||||
text = context.getString(it.stringResId),
|
||||
id = it.ordinal,
|
||||
text = context.getString(it.stringResId),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun formatLastSent(lastSent: Long) =
|
||||
StringUtil.formatRelativeTime(
|
||||
|
||||
@@ -43,6 +43,7 @@ import androidx.preference.PreferenceScreen;
|
||||
import com.android.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@@ -52,6 +53,7 @@ import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Ignore("b/317934814")
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class GraphicsDriverAppPreferenceControllerTest {
|
||||
|
||||
|
||||
@@ -375,8 +375,8 @@ public class DynamicDenylistManagerTest {
|
||||
mDynamicDenylistManager.dump(printWriter);
|
||||
|
||||
final String dumpResults = stringWriter.toString();
|
||||
assertThat(dumpResults.contains("ManualDenylist: app1")).isTrue();
|
||||
assertThat(dumpResults.contains("DynamicDenylist: app2")).isTrue();
|
||||
assertThat(dumpResults.contains("\tManualDenylist:\n\t\tapp1")).isTrue();
|
||||
assertThat(dumpResults.contains("\tDynamicDenylist:\n\t\tapp2")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -389,8 +389,8 @@ public class DynamicDenylistManagerTest {
|
||||
mDynamicDenylistManager.dump(printWriter);
|
||||
|
||||
final String dumpResults = stringWriter.toString();
|
||||
assertThat(dumpResults.contains("ManualDenylist: null")).isTrue();
|
||||
assertThat(dumpResults.contains("DynamicDenylist: null")).isTrue();
|
||||
assertThat(dumpResults.contains("Dump of DynamicDenylistManager:")).isTrue();
|
||||
assertThat(dumpResults.contains("\tManualDenylist:\n\tDynamicDenylist:")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -314,6 +314,8 @@ public class AppLocalePickerActivityTest {
|
||||
assertThat(info.getNotificationCount()).isEqualTo(1);
|
||||
assertThat(info.getDismissCount()).isEqualTo(0);
|
||||
assertThat(info.getLastNotificationTimeMs()).isNotEqualTo(0);
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
any(), eq(SettingsEnums.ACTION_NOTIFICATION_FOR_SYSTEM_LOCALE));
|
||||
|
||||
mDataManager.clearLocaleNotificationMap();
|
||||
}
|
||||
|
||||
@@ -25,10 +25,13 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -42,6 +45,7 @@ import org.robolectric.android.controller.ActivityController;
|
||||
public class NotificationActionActivityTest {
|
||||
private NotificationActionActivity mNotificationActivity;
|
||||
private ActivityController<NotificationActionActivity> mActivityController;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
@Mock
|
||||
private NotificationController mNotificationController;
|
||||
@Mock
|
||||
@@ -50,6 +54,7 @@ public class NotificationActionActivityTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -70,6 +75,8 @@ public class NotificationActionActivityTest {
|
||||
mNotificationActivity.onCreate(null);
|
||||
|
||||
verify(mLauncher).launch(any(Intent.class));
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
any(), eq(SettingsEnums.ACTION_NOTIFICATION_CLICK_FOR_SYSTEM_LOCALE));
|
||||
verify(mNotificationActivity).finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,12 @@ import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -43,12 +46,14 @@ public class NotificationCancelReceiverTest {
|
||||
private NotificationCancelReceiver mReceiver;
|
||||
@Mock
|
||||
private NotificationController mNotificationController;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = RuntimeEnvironment.application;
|
||||
mReceiver = spy(new NotificationCancelReceiver());
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
doReturn(mNotificationController).when(mReceiver).getNotificationController(any());
|
||||
}
|
||||
|
||||
@@ -64,5 +69,7 @@ public class NotificationCancelReceiverTest {
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
|
||||
verify(mNotificationController).incrementDismissCount(eq(locale));
|
||||
verify(mFeatureFactory.metricsFeatureProvider).action(
|
||||
any(), eq(SettingsEnums.ACTION_NOTIFICATION_SWIPE_FOR_SYSTEM_LOCALE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.telephony.gsm
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Settings
|
||||
import android.telephony.CarrierConfigManager
|
||||
import android.telephony.ServiceState
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotEnabled
|
||||
import androidx.compose.ui.test.assertIsOff
|
||||
import androidx.compose.ui.test.assertIsOn
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.onRoot
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.core.os.persistableBundleOf
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.R
|
||||
import com.android.settings.Settings.NetworkSelectActivity
|
||||
import com.android.settings.spa.preference.ComposePreference
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.doNothing
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AutoSelectPreferenceControllerTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
private val mockTelephonyManager = mock<TelephonyManager> {
|
||||
on { createForSubscriptionId(SUB_ID) } doReturn mock
|
||||
on { simOperatorName } doReturn OPERATOR_NAME
|
||||
}
|
||||
|
||||
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
|
||||
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
|
||||
doNothing().whenever(mock).startActivity(any())
|
||||
}
|
||||
|
||||
private val preference = ComposePreference(context).apply { key = TEST_KEY }
|
||||
private val preferenceScreen = PreferenceManager(context).createPreferenceScreen(context)
|
||||
|
||||
private val serviceState = ServiceState()
|
||||
|
||||
private val carrierConfig = persistableBundleOf()
|
||||
|
||||
private val controller = AutoSelectPreferenceController(
|
||||
context = context,
|
||||
key = TEST_KEY,
|
||||
allowedNetworkTypesFlowFactory = { emptyFlow() },
|
||||
serviceStateFlowFactory = { flowOf(serviceState) },
|
||||
getConfigForSubId = { carrierConfig },
|
||||
).init(subId = SUB_ID)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
preferenceScreen.addPreference(preference)
|
||||
controller.displayPreference(preferenceScreen)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isChecked_isAutoSelection_on() {
|
||||
serviceState.isManualSelection = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.select_automatically))
|
||||
.assertIsOn()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isChecked_isManualSelection_off() {
|
||||
serviceState.isManualSelection = true
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.select_automatically))
|
||||
.assertIsOff()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun isEnabled_isRoaming_enabled() {
|
||||
serviceState.roaming = true
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.select_automatically))
|
||||
.assertIsEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isEnabled_notOnlyAutoSelectInHome_enabled() {
|
||||
serviceState.roaming = false
|
||||
carrierConfig.putBoolean(
|
||||
CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, false
|
||||
)
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText(context.getString(R.string.select_automatically))
|
||||
.assertIsEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isEnabled_onlyAutoSelectInHome_notEnabled() {
|
||||
serviceState.roaming = false
|
||||
carrierConfig.putBoolean(
|
||||
CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL, true
|
||||
)
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText("Unavailable when connected to T-mobile")
|
||||
.assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onClick_turnOff_startNetworkSelectActivity() {
|
||||
serviceState.isManualSelection = false
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
composeTestRule.onRoot().performClick()
|
||||
|
||||
val intent = argumentCaptor<Intent> {
|
||||
verify(context).startActivity(capture())
|
||||
}.firstValue
|
||||
assertThat(intent.component!!.className).isEqualTo(NetworkSelectActivity::class.java.name)
|
||||
assertThat(intent.getIntExtra(Settings.EXTRA_SUB_ID, 0)).isEqualTo(SUB_ID)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onClick_turnOn_setNetworkSelectionModeAutomatic() = runBlocking {
|
||||
serviceState.isManualSelection = true
|
||||
controller.progressDialog = mock()
|
||||
|
||||
composeTestRule.setContent {
|
||||
controller.Content()
|
||||
}
|
||||
composeTestRule.onRoot().performClick()
|
||||
delay(100)
|
||||
|
||||
verify(controller.progressDialog!!).show()
|
||||
verify(mockTelephonyManager).setNetworkSelectionModeAutomatic()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val TEST_KEY = "test_key"
|
||||
const val SUB_ID = 2
|
||||
const val OPERATOR_NAME = "T-mobile"
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.concurrent.Phaser;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class LifecycleCallbackConverterTest implements LifecycleOwner {
|
||||
|
||||
private final LifecycleRegistry mRegistry = LifecycleRegistry.createUnsafe(this);
|
||||
|
||||
private Object mTestData;
|
||||
private TestConsumer mConsumer;
|
||||
private LifecycleCallbackConverter<Object> mConverter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mTestData = new Object();
|
||||
mConsumer = new TestConsumer();
|
||||
}
|
||||
|
||||
private void initEnvPerTestCase() {
|
||||
mConverter = new LifecycleCallbackConverter<Object>(getLifecycle(), mConsumer);
|
||||
}
|
||||
|
||||
public Lifecycle getLifecycle() {
|
||||
return mRegistry;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converter_dropResult_whenInActive() {
|
||||
initEnvPerTestCase();
|
||||
mConverter.postResult(mTestData);
|
||||
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converter_callbackResult_whenActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
mConverter.postResult(mTestData);
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(1);
|
||||
assertThat(mConsumer.getData()).isEqualTo(mTestData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converter_dropResult_whenBackToInActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
mConverter.postResult(mTestData);
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void converter_passResultToUiThread_whenActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
final Phaser phaser = new Phaser(1);
|
||||
Thread executionThread = new Thread(() -> {
|
||||
mConverter.postResult(phaser);
|
||||
});
|
||||
executionThread.start();
|
||||
phaser.awaitAdvance(0);
|
||||
|
||||
assertThat(mConsumer.getData()).isEqualTo(phaser);
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
public static class TestConsumer implements Consumer<Object> {
|
||||
long mNumberOfCallback;
|
||||
AtomicReference<Object> mLatestData;
|
||||
|
||||
public TestConsumer() {
|
||||
mLatestData = new AtomicReference<Object>();
|
||||
}
|
||||
|
||||
public void accept(Object data) {
|
||||
mLatestData.set(data);
|
||||
mNumberOfCallback ++;
|
||||
if ((data != null) && (data instanceof Phaser)) {
|
||||
((Phaser)data).arrive();
|
||||
}
|
||||
}
|
||||
|
||||
protected long getCallbackCount() {
|
||||
return mNumberOfCallback;
|
||||
}
|
||||
|
||||
protected Object getData() {
|
||||
return mLatestData.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* 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 android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LifecycleRegistry;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class LifecycleCallbackIntentReceiverTest implements LifecycleOwner {
|
||||
|
||||
private final LifecycleRegistry mRegistry = LifecycleRegistry.createUnsafe(this);
|
||||
|
||||
private static final String TEST_SCHEDULER_HANDLER = "testScheduler";
|
||||
private static final String TEST_INTENT_ACTION = "testAction";
|
||||
private static final String TEST_INTENT_PERMISSION = "testPermission";
|
||||
|
||||
private Context mContext;
|
||||
private Intent mIntent;
|
||||
private IntentFilter mIntentFilter;
|
||||
private Handler mHandler;
|
||||
private TestConsumer mConsumer;
|
||||
|
||||
private TestObj mTarget;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = ApplicationProvider.getApplicationContext();
|
||||
|
||||
mIntentFilter = new IntentFilter(TEST_INTENT_ACTION);
|
||||
mIntent = new Intent(TEST_INTENT_ACTION);
|
||||
|
||||
HandlerThread thread = new HandlerThread(TEST_SCHEDULER_HANDLER);
|
||||
thread.start();
|
||||
|
||||
mHandler = new Handler(thread.getLooper());
|
||||
mConsumer = new TestConsumer();
|
||||
}
|
||||
|
||||
public Lifecycle getLifecycle() {
|
||||
return mRegistry;
|
||||
}
|
||||
|
||||
private void initEnvPerTestCase() {
|
||||
mTarget = new TestObj(getLifecycle(), mContext,
|
||||
mIntentFilter, TEST_INTENT_PERMISSION,
|
||||
mHandler, mConsumer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiver_register_whenActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
assertThat(mTarget.getCallbackActiveCount(true)
|
||||
+ mTarget.getCallbackActiveCount(false)).isEqualTo(0);
|
||||
|
||||
mTarget.mReceiver.onReceive(mContext, mIntent);
|
||||
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(0);
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mTarget.getCallbackActiveCount(true)).isEqualTo(1);
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(0);
|
||||
|
||||
mTarget.mReceiver.onReceive(mContext, mIntent);
|
||||
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(1);
|
||||
assertThat(mConsumer.getData()).isEqualTo(mIntent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiver_unregister_whenInActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
assertThat(mTarget.getCallbackActiveCount(false)).isEqualTo(1);
|
||||
|
||||
mTarget.mReceiver.onReceive(mContext, mIntent);
|
||||
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiver_register_whenReActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
assertThat(mTarget.getCallbackActiveCount(true)).isEqualTo(2);
|
||||
|
||||
mTarget.mReceiver.onReceive(mContext, mIntent);
|
||||
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(1);
|
||||
assertThat(mConsumer.getData()).isEqualTo(mIntent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void receiver_close_whenDestroy() {
|
||||
initEnvPerTestCase();
|
||||
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.getCallbackActiveCount(false)).isEqualTo(1);
|
||||
|
||||
mTarget.mReceiver.onReceive(mContext, mIntent);
|
||||
|
||||
assertThat(mConsumer.getCallbackCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
public static class TestConsumer implements Consumer<Intent> {
|
||||
long mNumberOfCallback;
|
||||
Intent mLatestData;
|
||||
|
||||
public TestConsumer() {}
|
||||
|
||||
public void accept(Intent data) {
|
||||
mLatestData = data;
|
||||
mNumberOfCallback ++;
|
||||
}
|
||||
|
||||
protected long getCallbackCount() {
|
||||
return mNumberOfCallback;
|
||||
}
|
||||
|
||||
protected Intent getData() {
|
||||
return mLatestData;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestObj extends LifecycleCallbackIntentReceiver {
|
||||
long mCallbackActiveCount;
|
||||
long mCallbackInActiveCount;
|
||||
|
||||
public TestObj(Lifecycle lifecycle, Context context, IntentFilter filter,
|
||||
String broadcastPermission, Handler scheduler, Consumer<Intent> resultCallback) {
|
||||
super(lifecycle, context, filter, broadcastPermission, scheduler, resultCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallbackActive(boolean isActive) {
|
||||
if (isActive) {
|
||||
mCallbackActiveCount ++;
|
||||
} else {
|
||||
mCallbackInActiveCount ++;
|
||||
}
|
||||
super.setCallbackActive(isActive);
|
||||
}
|
||||
|
||||
protected long getCallbackActiveCount(boolean forActive) {
|
||||
return forActive ? mCallbackActiveCount : mCallbackInActiveCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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 org.mockito.ArgumentMatchers.anyObject;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.telephony.TelephonyCallback;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class LifecycleCallbackTelephonyAdapterTest implements LifecycleOwner {
|
||||
|
||||
private final LifecycleRegistry mRegistry = LifecycleRegistry.createUnsafe(this);
|
||||
|
||||
@Mock
|
||||
private TelephonyManager mTelMgr;
|
||||
|
||||
private TestCallback mTestCallback;
|
||||
private AtomicReference<Object> mResult;
|
||||
private LifecycleCallbackTelephonyAdapter<Object> mAdapter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mResult = new AtomicReference<Object>();
|
||||
mTestCallback = new TestCallback();
|
||||
|
||||
doNothing().when(mTelMgr).registerTelephonyCallback(null, mTestCallback);
|
||||
doNothing().when(mTelMgr).unregisterTelephonyCallback(mTestCallback);
|
||||
}
|
||||
|
||||
public Lifecycle getLifecycle() {
|
||||
return mRegistry;
|
||||
}
|
||||
|
||||
private void initEnvPerTestCase() {
|
||||
mAdapter = new LifecycleCallbackTelephonyAdapter<Object>(getLifecycle(), mTelMgr,
|
||||
mTestCallback, null, result -> mResult.set(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void telephonyCallback_register_whenActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
verify(mTelMgr, never()).registerTelephonyCallback(anyObject(), anyObject());
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
verify(mTelMgr).registerTelephonyCallback(anyObject(), anyObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void telephonyCallback_unregister_whenInActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
verify(mTelMgr, never()).unregisterTelephonyCallback(anyObject());
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
verify(mTelMgr, never()).unregisterTelephonyCallback(anyObject());
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
verify(mTelMgr).unregisterTelephonyCallback(anyObject());
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
|
||||
|
||||
verify(mTelMgr, times(1)).unregisterTelephonyCallback(anyObject());
|
||||
}
|
||||
|
||||
protected static class TestCallback extends TelephonyCallback
|
||||
implements TelephonyCallback.CallStateListener {
|
||||
@Override
|
||||
public void onCallStateChanged(int state) {}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* 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 android.telephony.ServiceState;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ServiceStateStatusTest implements LifecycleOwner {
|
||||
|
||||
private final LifecycleRegistry mRegistry = LifecycleRegistry.createUnsafe(this);
|
||||
|
||||
@Mock
|
||||
private TelephonyManager mTelMgr;
|
||||
@Mock
|
||||
private ServiceState mTestData;
|
||||
|
||||
private AtomicReference<ServiceState> mStatusStorage;
|
||||
private ServiceStateStatus mServiceStateStatus;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mStatusStorage = new AtomicReference<ServiceState>();
|
||||
}
|
||||
|
||||
private void initEnvPerTestCase() {
|
||||
mServiceStateStatus = new ServiceStateStatus(getLifecycle(), mTelMgr, null) {
|
||||
@Override
|
||||
protected void setValue(ServiceState status) {
|
||||
mStatusStorage.set(status);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Lifecycle getLifecycle() {
|
||||
return mRegistry;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void telephonyCallback_updateStatus_whenActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
mServiceStateStatus.mServiceStateProducer.onServiceStateChanged(mTestData);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(null);
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
mServiceStateStatus.mServiceStateProducer.onServiceStateChanged(mTestData);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(mTestData);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void telephonyCallback_updateStatusToNull_whenInActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
mServiceStateStatus.mServiceStateProducer.onServiceStateChanged(mTestData);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(mTestData);
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(null);
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* 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 android.telephony.TelephonyManager;
|
||||
|
||||
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;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class VoiceCallStatusTest implements LifecycleOwner {
|
||||
|
||||
private final LifecycleRegistry mRegistry = LifecycleRegistry.createUnsafe(this);
|
||||
|
||||
@Mock
|
||||
private TelephonyManager mTelMgr;
|
||||
|
||||
private AtomicReference<Integer> mStatusStorage;
|
||||
private VoiceCallStatus mVoiceCallStatus;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mStatusStorage = new AtomicReference<Integer>();
|
||||
}
|
||||
|
||||
private void initEnvPerTestCase() {
|
||||
mVoiceCallStatus = new VoiceCallStatus(getLifecycle(), mTelMgr, null) {
|
||||
//ArchTaskExecutor.getMainThreadExecutor()) {
|
||||
@Override
|
||||
protected void setValue(Integer status) {
|
||||
mStatusStorage.set(status);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Lifecycle getLifecycle() {
|
||||
return mRegistry;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void telephonyCallback_updateStatus_whenActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
|
||||
mVoiceCallStatus.mCallStateProducer.onCallStateChanged(
|
||||
TelephonyManager.CALL_STATE_RINGING);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(null);
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
mVoiceCallStatus.mCallStateProducer.onCallStateChanged(
|
||||
TelephonyManager.CALL_STATE_OFFHOOK);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(TelephonyManager.CALL_STATE_OFFHOOK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void telephonyCallback_updateStatusToNull_whenInActive() {
|
||||
initEnvPerTestCase();
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
|
||||
|
||||
mVoiceCallStatus.mCallStateProducer.onCallStateChanged(
|
||||
TelephonyManager.CALL_STATE_OFFHOOK);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(TelephonyManager.CALL_STATE_OFFHOOK);
|
||||
|
||||
mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
|
||||
|
||||
assertThat(mStatusStorage.get()).isEqualTo(null);
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
* 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.network.telephony.gsm;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.PersistableBundle;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.ServiceState;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import com.android.settings.network.CarrierConfigCache;
|
||||
import com.android.settings.testutils.ResourcesUtils;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AutoSelectPreferenceControllerTest {
|
||||
private static final int SUB_ID = 2;
|
||||
private static final String OPERATOR_NAME = "T-mobile";
|
||||
|
||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||
private TelephonyManager mTelephonyManager;
|
||||
@Mock
|
||||
private SubscriptionManager mSubscriptionManager;
|
||||
@Mock
|
||||
private CarrierConfigCache mCarrierConfigCache;
|
||||
@Mock
|
||||
private ProgressDialog mProgressDialog;
|
||||
@Mock
|
||||
private ServiceState mTestServiceState;
|
||||
@Mock
|
||||
private Lifecycle mLifecycle;
|
||||
|
||||
private PersistableBundle mCarrierConfig;
|
||||
private AutoSelectPreferenceController mController;
|
||||
private SwitchPreference mSwitchPreference;
|
||||
private Context mContext;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||
|
||||
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
|
||||
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
|
||||
CarrierConfigCache.setTestInstance(mContext, mCarrierConfigCache);
|
||||
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
|
||||
|
||||
mCarrierConfig = new PersistableBundle();
|
||||
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL,
|
||||
true);
|
||||
when(mCarrierConfigCache.getConfigForSubId(SUB_ID)).thenReturn(mCarrierConfig);
|
||||
|
||||
mSwitchPreference = new SwitchPreference(mContext);
|
||||
mController = new AutoSelectPreferenceController(mContext, "auto_select");
|
||||
mController.mProgressDialog = mProgressDialog;
|
||||
mController.mSwitchPreference = mSwitchPreference;
|
||||
mController.init(mLifecycle, SUB_ID);
|
||||
sleepAfterInit();
|
||||
}
|
||||
|
||||
private void sleepAfterInit() {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (Exception e) {
|
||||
fail("Sleep timeout " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setChecked_isChecked_showProgressDialog() {
|
||||
when(mTelephonyManager.getNetworkSelectionMode()).thenReturn(
|
||||
TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
|
||||
|
||||
// Wait for asynchronous thread to finish, otherwise test will flake.
|
||||
Future thread = mController.setAutomaticSelectionMode();
|
||||
try {
|
||||
thread.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
fail("Exception during automatic selection");
|
||||
}
|
||||
|
||||
verify(mProgressDialog).show();
|
||||
verify(mTelephonyManager).setNetworkSelectionModeAutomatic();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_isRoaming_enabled() {
|
||||
when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState);
|
||||
when(mTestServiceState.getRoaming()).thenReturn(true);
|
||||
|
||||
mController.updateState(mSwitchPreference);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_notRoamingWithAutoSelectOn_disabled() {
|
||||
when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState);
|
||||
when(mTestServiceState.getRoaming()).thenReturn(false);
|
||||
doReturn(OPERATOR_NAME).when(mTelephonyManager).getSimOperatorName();
|
||||
|
||||
mController.updateState(mSwitchPreference);
|
||||
|
||||
assertThat(mSwitchPreference.isEnabled()).isFalse();
|
||||
assertThat(mSwitchPreference.getSummary()).isEqualTo(
|
||||
ResourcesUtils.getResourcesString(mContext, "manual_mode_disallowed_summary",
|
||||
mTelephonyManager.getSimOperatorName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void init_carrierConfigNull_shouldNotCrash() {
|
||||
when(mCarrierConfigCache.getConfigForSubId(SUB_ID)).thenReturn(null);
|
||||
|
||||
// Should not crash
|
||||
mController.init(mLifecycle, SUB_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateUiAutoSelectValue_serviceStateGetIsManualSelection_isCheckedFalse() {
|
||||
when(mTelephonyManager.getNetworkSelectionMode()).thenReturn(
|
||||
TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
|
||||
when(mTestServiceState.getIsManualSelection()).thenReturn(true);
|
||||
mController.init(mLifecycle, SUB_ID);
|
||||
sleepAfterInit();
|
||||
|
||||
mController.updateUiAutoSelectValue(mTestServiceState);
|
||||
|
||||
assertThat(mController.isChecked()).isFalse();
|
||||
assertThat(mSwitchPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateUiAutoSelectValue_serviceStateGetIsAutoSelection_isCheckedTrue() {
|
||||
when(mTelephonyManager.getNetworkSelectionMode()).thenReturn(
|
||||
TelephonyManager.NETWORK_SELECTION_MODE_MANUAL);
|
||||
when(mTestServiceState.getIsManualSelection()).thenReturn(false);
|
||||
mController.init(mLifecycle, SUB_ID);
|
||||
sleepAfterInit();
|
||||
|
||||
mController.updateUiAutoSelectValue(mTestServiceState);
|
||||
|
||||
assertThat(mController.isChecked()).isTrue();
|
||||
assertThat(mSwitchPreference.isChecked()).isTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user