Merge "DO NOT MERGE Add Slices for WifiCalling" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
15602b3f48
@@ -2340,6 +2340,17 @@
|
||||
<!-- Message of private dns that provides a help link. [CHAR LIMIT=NONE] -->
|
||||
<string name="private_dns_help_message"><annotation id="url">Learn more</annotation> about Private DNS features</string>
|
||||
|
||||
<!-- Message to display when setting wifi calling are not editable [CHAR LIMIT=NONE] -->
|
||||
<string name="wifi_calling_pref_managed_by_carrier">Setting managed by carrier</string>
|
||||
<!-- Message to display when wifi calling needs activation [CHAR LIMIT=NONE] -->
|
||||
<string name="wifi_calling_settings_activation_instructions">Activate Wi\u2011Fi Calling</string>
|
||||
<!-- Message to display when wifi calling should be on [CHAR LIMIT=NONE] -->
|
||||
<string name="wifi_calling_turn_on">Turn on Wi\u2011Fi calling</string>
|
||||
<!-- Message to display when carrier does not support wifi calling or doesn't want the user
|
||||
to modify the settings [CHAR LIMIT=NONE] -->
|
||||
<string name="wifi_calling_not_supported">Wi\u2011Fi calling is not supported for %1$s</string>
|
||||
<!-- Carrier string to use in other messages -->
|
||||
<string name="carrier">Carrier</string>
|
||||
<!-- Sound and alerts settings -->
|
||||
<skip/>
|
||||
<string name="display_settings_title">Display</string>
|
||||
|
@@ -18,6 +18,8 @@ package com.android.settings.slices;
|
||||
|
||||
import static android.Manifest.permission.READ_SEARCH_INDEXABLES;
|
||||
|
||||
import static com.android.settings.wifi.calling.WifiCallingSliceHelper.PATH_WIFI_CALLING;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.slice.SliceManager;
|
||||
import android.content.ContentResolver;
|
||||
@@ -34,7 +36,13 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceProvider;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
import androidx.slice.builders.SliceAction;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
@@ -45,11 +53,6 @@ import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceProvider;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
import androidx.slice.builders.SliceAction;
|
||||
|
||||
/**
|
||||
* A {@link SliceProvider} for Settings to enabled inline results in system apps.
|
||||
*
|
||||
@@ -160,6 +163,11 @@ public class SettingsSliceProvider extends SliceProvider {
|
||||
switch (path) {
|
||||
case "/" + PATH_WIFI:
|
||||
return createWifiSlice(sliceUri);
|
||||
case "/" + PATH_WIFI_CALLING:
|
||||
return FeatureFactory.getFactory(getContext())
|
||||
.getSlicesFeatureProvider()
|
||||
.getNewWifiCallingSliceHelper(getContext())
|
||||
.createWifiCallingSlice(sliceUri);
|
||||
}
|
||||
|
||||
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
|
||||
|
@@ -21,6 +21,7 @@ import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CH
|
||||
import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED;
|
||||
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
|
||||
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
|
||||
import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED;
|
||||
|
||||
import android.app.slice.Slice;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -79,6 +80,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
|
||||
context.getContentResolver().notifyChange(uri, null);
|
||||
}, 1000);
|
||||
break;
|
||||
case ACTION_WIFI_CALLING_CHANGED:
|
||||
FeatureFactory.getFactory(context)
|
||||
.getSlicesFeatureProvider()
|
||||
.getNewWifiCallingSliceHelper(context)
|
||||
.handleWifiCallingChanged(intent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,8 @@ package com.android.settings.slices;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
|
||||
|
||||
/**
|
||||
* Manages Slices in Settings.
|
||||
*/
|
||||
@@ -24,4 +26,9 @@ public interface SlicesFeatureProvider {
|
||||
* If the data is already indexed, the data will not change.
|
||||
*/
|
||||
void indexSliceData(Context context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets new WifiCallingSliceHelper object
|
||||
*/
|
||||
WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context);
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package com.android.settings.slices;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
/**
|
||||
@@ -39,4 +40,9 @@ public class SlicesFeatureProviderImpl implements SlicesFeatureProvider {
|
||||
SlicesIndexer indexer = getSliceIndexer(context);
|
||||
indexer.indexSliceData();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WifiCallingSliceHelper getNewWifiCallingSliceHelper(Context context) {
|
||||
return new WifiCallingSliceHelper(context);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* 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.wifi.calling;
|
||||
|
||||
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.PersistableBundle;
|
||||
import android.support.v4.graphics.drawable.IconCompat;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.builders.ListBuilder;
|
||||
import androidx.slice.builders.SliceAction;
|
||||
|
||||
import com.android.ims.ImsManager;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.slices.SliceBroadcastReceiver;
|
||||
import com.android.settings.slices.SliceBuilderUtils;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to control slices for wifi calling settings.
|
||||
*/
|
||||
public class WifiCallingSliceHelper {
|
||||
|
||||
private static final String TAG = "WifiCallingSliceHelper";
|
||||
|
||||
/**
|
||||
* Settings slice path to wifi calling setting.
|
||||
*/
|
||||
public static final String PATH_WIFI_CALLING = "wifi_calling";
|
||||
|
||||
/**
|
||||
* Action passed for changes to wifi calling slice (toggle).
|
||||
*/
|
||||
public static final String ACTION_WIFI_CALLING_CHANGED =
|
||||
"com.android.settings.wifi.calling.action.WIFI_CALLING_CHANGED";
|
||||
|
||||
/**
|
||||
* Action for Wifi calling Settings activity which
|
||||
* allows setting configuration for Wifi calling
|
||||
* related settings
|
||||
*/
|
||||
public static final String ACTION_WIFI_CALLING_SETTINGS_ACTIVITY =
|
||||
"android.settings.WIFI_CALLING_SETTINGS";
|
||||
|
||||
/**
|
||||
* Timeout for querying wifi calling setting from ims manager.
|
||||
*/
|
||||
private static final int TIMEOUT_MILLIS = 2000;
|
||||
|
||||
/**
|
||||
* Time for which data contained in the slice can remain fresh.
|
||||
*/
|
||||
private static final int SLICE_TTL_MILLIS = 60000;
|
||||
|
||||
protected SubscriptionManager mSubscriptionManager;
|
||||
private final Context mContext;
|
||||
|
||||
@VisibleForTesting
|
||||
public WifiCallingSliceHelper(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Slice object for wifi calling settings.
|
||||
*
|
||||
* If wifi calling is being turned on and if wifi calling activation is needed for the current
|
||||
* carrier, this method will return Slice with instructions to go to Settings App.
|
||||
*
|
||||
* If wifi calling is not supported for the current carrier, this method will return slice with
|
||||
* not supported message.
|
||||
*
|
||||
* If wifi calling setting can be changed, this method will return the slice to toggle wifi
|
||||
* calling option with ACTION_WIFI_CALLING_CHANGED as endItem.
|
||||
*/
|
||||
public Slice createWifiCallingSlice(Uri sliceUri) {
|
||||
final int subId = getDefaultVoiceSubId();
|
||||
final String carrierName = getSimCarrierName();
|
||||
|
||||
if (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
Log.d(TAG, "Invalid subscription Id");
|
||||
return getNonActionableWifiCallingSlice(
|
||||
mContext.getString(R.string.wifi_calling_settings_title),
|
||||
mContext.getString(R.string.wifi_calling_not_supported, carrierName),
|
||||
sliceUri, SliceBuilderUtils.getSettingsIntent(mContext));
|
||||
}
|
||||
|
||||
final ImsManager imsManager = getImsManager(subId);
|
||||
|
||||
if (!imsManager.isWfcEnabledByPlatform()
|
||||
|| !imsManager.isWfcProvisionedOnDevice()) {
|
||||
Log.d(TAG, "Wifi calling is either not provisioned or not enabled by Platform");
|
||||
return getNonActionableWifiCallingSlice(
|
||||
mContext.getString(R.string.wifi_calling_settings_title),
|
||||
mContext.getString(R.string.wifi_calling_not_supported, carrierName),
|
||||
sliceUri, SliceBuilderUtils.getSettingsIntent(mContext));
|
||||
}
|
||||
|
||||
try {
|
||||
final boolean isWifiCallingEnabled = isWifiCallingEnabled(imsManager);
|
||||
final Intent activationAppIntent =
|
||||
getWifiCallingCarrierActivityIntent(subId);
|
||||
|
||||
// Send this actionable wifi calling slice to toggle the setting
|
||||
// only when there is no need for wifi calling activation with the server
|
||||
if (activationAppIntent != null && !isWifiCallingEnabled) {
|
||||
Log.d(TAG, "Needs Activation");
|
||||
// Activation needed for the next action of the user
|
||||
// Give instructions to go to settings app
|
||||
return getNonActionableWifiCallingSlice(
|
||||
mContext.getString(R.string.wifi_calling_settings_title),
|
||||
mContext.getString(
|
||||
R.string.wifi_calling_settings_activation_instructions),
|
||||
sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
|
||||
}
|
||||
return getWifiCallingSlice(sliceUri, mContext, isWifiCallingEnabled);
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException e) {
|
||||
Log.e(TAG, "Unable to read the current WiFi calling status", e);
|
||||
return getNonActionableWifiCallingSlice(
|
||||
mContext.getString(R.string.wifi_calling_settings_title),
|
||||
mContext.getString(R.string.wifi_calling_turn_on),
|
||||
sliceUri, getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWifiCallingEnabled(ImsManager imsManager)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
final FutureTask<Boolean> isWifiOnTask = new FutureTask<>(new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() {
|
||||
return imsManager.isWfcEnabledByUser();
|
||||
}
|
||||
});
|
||||
final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
executor.execute(isWifiOnTask);
|
||||
|
||||
Boolean isWifiEnabledByUser = false;
|
||||
isWifiEnabledByUser = isWifiOnTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
||||
|
||||
return isWifiEnabledByUser && imsManager.isNonTtyOrTtyOnVolteEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a toggle slice where the intent takes you to the wifi calling page and the toggle
|
||||
* enables/disables wifi calling.
|
||||
*/
|
||||
private Slice getWifiCallingSlice(Uri sliceUri, Context mContext,
|
||||
boolean isWifiCallingEnabled) {
|
||||
|
||||
final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
|
||||
final String title = mContext.getString(R.string.wifi_calling_settings_title);
|
||||
return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
|
||||
.setColor(R.color.material_blue_500)
|
||||
.addRow(b -> b
|
||||
.setTitle(title)
|
||||
.addEndItem(
|
||||
new SliceAction(
|
||||
getBroadcastIntent(ACTION_WIFI_CALLING_CHANGED),
|
||||
null /* actionTitle */, isWifiCallingEnabled))
|
||||
.setPrimaryAction(new SliceAction(
|
||||
getActivityIntent(ACTION_WIFI_CALLING_SETTINGS_ACTIVITY),
|
||||
icon,
|
||||
title)))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected ImsManager getImsManager(int subId) {
|
||||
return ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(subId));
|
||||
}
|
||||
|
||||
private Integer getWfcMode(ImsManager imsManager)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
FutureTask<Integer> wfcModeTask = new FutureTask<>(new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() {
|
||||
return imsManager.getWfcMode(false);
|
||||
}
|
||||
});
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
executor.execute(wfcModeTask);
|
||||
return wfcModeTask.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles wifi calling setting change from wifi calling slice and posts notification. Should be
|
||||
* called when intent action is ACTION_WIFI_CALLING_CHANGED. Executed in @WorkerThread
|
||||
*
|
||||
* @param intent action performed
|
||||
*/
|
||||
public void handleWifiCallingChanged(Intent intent) {
|
||||
final int subId = getDefaultVoiceSubId();
|
||||
|
||||
if (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
final ImsManager imsManager = getImsManager(subId);
|
||||
if (imsManager.isWfcEnabledByPlatform()
|
||||
|| imsManager.isWfcProvisionedOnDevice()) {
|
||||
final boolean currentValue = imsManager.isWfcEnabledByUser()
|
||||
&& imsManager.isNonTtyOrTtyOnVolteEnabled();
|
||||
final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE,
|
||||
currentValue);
|
||||
final Intent activationAppIntent =
|
||||
getWifiCallingCarrierActivityIntent(subId);
|
||||
if (!newValue || activationAppIntent == null) {
|
||||
// If either the action is to turn off wifi calling setting
|
||||
// or there is no activation involved - Update the setting
|
||||
if (newValue != currentValue) {
|
||||
imsManager.setWfcSetting(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// notify change in slice in any case to get re-queried. This would result in displaying
|
||||
// appropriate message with the updated setting.
|
||||
final Uri uri = SliceBuilderUtils.getUri(PATH_WIFI_CALLING, false /*isPlatformSlice*/);
|
||||
mContext.getContentResolver().notifyChange(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Slice with the title and subtitle provided as arguments with wifi signal Icon.
|
||||
*
|
||||
* @param title Title of the slice
|
||||
* @param subtitle Subtitle of the slice
|
||||
* @param sliceUri slice uri
|
||||
* @return Slice with title and subtitle
|
||||
*/
|
||||
// TODO(b/79548264) asses different scenarios and return null instead of non-actionable slice
|
||||
private Slice getNonActionableWifiCallingSlice(String title, String subtitle, Uri sliceUri,
|
||||
PendingIntent primaryActionIntent) {
|
||||
final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal);
|
||||
return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS)
|
||||
.setColor(R.color.material_blue_500)
|
||||
.addRow(b -> b
|
||||
.setTitle(title)
|
||||
.setSubtitle(subtitle)
|
||||
.setPrimaryAction(new SliceAction(
|
||||
primaryActionIntent, icon,
|
||||
title)))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise.
|
||||
*/
|
||||
private boolean isCarrierConfigManagerKeyEnabled(Context mContext, String key,
|
||||
int subId, boolean defaultValue) {
|
||||
final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
|
||||
boolean ret = false;
|
||||
if (configManager != null) {
|
||||
final PersistableBundle bundle = configManager.getConfigForSubId(subId);
|
||||
if (bundle != null) {
|
||||
ret = bundle.getBoolean(key, defaultValue);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected CarrierConfigManager getCarrierConfigManager(Context mContext) {
|
||||
return mContext.getSystemService(CarrierConfigManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current default voice subId obtained from SubscriptionManager
|
||||
*/
|
||||
protected int getDefaultVoiceSubId() {
|
||||
if (mSubscriptionManager == null) {
|
||||
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
|
||||
}
|
||||
return SubscriptionManager.getDefaultVoiceSubscriptionId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Intent of the activation app required to activate wifi calling or null if there is no
|
||||
* need for activation.
|
||||
*/
|
||||
protected Intent getWifiCallingCarrierActivityIntent(int subId) {
|
||||
final CarrierConfigManager configManager = getCarrierConfigManager(mContext);
|
||||
if (configManager == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PersistableBundle bundle = configManager.getConfigForSubId(subId);
|
||||
if (bundle == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String carrierApp = bundle.getString(
|
||||
CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING);
|
||||
if (TextUtils.isEmpty(carrierApp)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ComponentName componentName = ComponentName.unflattenFromString(carrierApp);
|
||||
if (componentName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent();
|
||||
intent.setComponent(componentName);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private PendingIntent getBroadcastIntent(String action) {
|
||||
final Intent intent = new Intent(action);
|
||||
intent.setClass(mContext, SliceBroadcastReceiver.class);
|
||||
return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PendingIntent to start activity specified by action
|
||||
*/
|
||||
private PendingIntent getActivityIntent(String action) {
|
||||
final Intent intent = new Intent(action);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns carrier id name of the current Subscription
|
||||
*/
|
||||
private String getSimCarrierName() {
|
||||
final TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
|
||||
final CharSequence carrierName = telephonyManager.getSimCarrierIdName();
|
||||
if (carrierName == null) {
|
||||
return mContext.getString(R.string.carrier);
|
||||
}
|
||||
return carrierName.toString();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* 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.wifi.calling;
|
||||
|
||||
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
|
||||
import static android.app.slice.Slice.HINT_TITLE;
|
||||
import static android.app.slice.SliceItem.FORMAT_TEXT;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
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.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
|
||||
import androidx.slice.Slice;
|
||||
import androidx.slice.SliceItem;
|
||||
import androidx.slice.SliceMetadata;
|
||||
import androidx.slice.SliceProvider;
|
||||
import androidx.slice.core.SliceAction;
|
||||
import androidx.slice.core.SliceQuery;
|
||||
import androidx.slice.widget.SliceLiveData;
|
||||
|
||||
import com.android.ims.ImsManager;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.slices.SettingsSliceProvider;
|
||||
import com.android.settings.slices.SliceBroadcastReceiver;
|
||||
import com.android.settings.slices.SliceBuilderUtils;
|
||||
import com.android.settings.slices.SliceData;
|
||||
import com.android.settings.slices.SlicesFeatureProvider;
|
||||
import com.android.settings.testutils.FakeFeatureFactory;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class WifiCallingSliceHelperTest {
|
||||
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private CarrierConfigManager mMockCarrierConfigManager;
|
||||
|
||||
@Mock
|
||||
private ImsManager mMockImsManager;
|
||||
|
||||
private final Uri mWfcURI = Uri.parse("content://com.android.settings.slices/wifi_calling");
|
||||
|
||||
private FakeWifiCallingSliceHelper mWfcSliceHelper;
|
||||
private SettingsSliceProvider mProvider;
|
||||
private SliceBroadcastReceiver mReceiver;
|
||||
private FakeFeatureFactory mFeatureFactory;
|
||||
private SlicesFeatureProvider mSlicesFeatureProvider;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
|
||||
//setup for SettingsSliceProvider tests
|
||||
mProvider = spy(new SettingsSliceProvider());
|
||||
doReturn(mContext).when(mProvider).getContext();
|
||||
|
||||
//setup for SliceBroadcastReceiver test
|
||||
mReceiver = spy(new SliceBroadcastReceiver());
|
||||
|
||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||
mSlicesFeatureProvider = mFeatureFactory.getSlicesFeatureProvider();
|
||||
|
||||
// Prevent crash in SliceMetadata.
|
||||
Resources resources = spy(mContext.getResources());
|
||||
doReturn(60).when(resources).getDimensionPixelSize(anyInt());
|
||||
doReturn(resources).when(mContext).getResources();
|
||||
|
||||
mWfcSliceHelper = new FakeWifiCallingSliceHelper(mContext);
|
||||
|
||||
// Set-up specs for SliceMetadata.
|
||||
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CreateWifiCallingSlice_invalidSubId() {
|
||||
mWfcSliceHelper.setDefaultVoiceSubId(-1);
|
||||
|
||||
final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
|
||||
|
||||
testWifiCallingSettingsUnavailableSlice(slice, null,
|
||||
SliceBuilderUtils.getSettingsIntent(mContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CreateWifiCallingSlice_wfcNotSupported() {
|
||||
doReturn(false).when(mMockImsManager).isWfcEnabledByPlatform();
|
||||
|
||||
final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
|
||||
|
||||
assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
|
||||
testWifiCallingSettingsUnavailableSlice(slice, null,
|
||||
SliceBuilderUtils.getSettingsIntent(mContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CreateWifiCallingSlice_needsActivation() {
|
||||
/* In cases where activation is needed and the user action
|
||||
would be turning on the wifi calling (i.e. if wifi calling is
|
||||
turned off) we need to guide the user to wifi calling settings
|
||||
activity so the user can perform the activation there.(PrimaryAction)
|
||||
*/
|
||||
doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
|
||||
doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
|
||||
doReturn(false).when(mMockImsManager).isWfcEnabledByUser();
|
||||
doReturn(false).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
|
||||
doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
|
||||
mWfcSliceHelper.setActivationAppIntent(new Intent()); // dummy Intent
|
||||
|
||||
final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
|
||||
|
||||
assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
|
||||
testWifiCallingSettingsUnavailableSlice(slice, null,
|
||||
getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_CreateWifiCallingSlice_success() {
|
||||
doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
|
||||
doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
|
||||
doReturn(true).when(mMockImsManager).isWfcEnabledByUser();
|
||||
doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
|
||||
doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
|
||||
|
||||
final Slice slice = mWfcSliceHelper.createWifiCallingSlice(mWfcURI);
|
||||
|
||||
assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
|
||||
testWifiCallingSettingsToggleSlice(slice, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_SettingSliceProvider_getsRightSliceWifiCalling() {
|
||||
doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
|
||||
doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
|
||||
doReturn(true).when(mMockImsManager).isWfcEnabledByUser();
|
||||
doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
|
||||
doReturn(null).when(mMockCarrierConfigManager).getConfigForSubId(1);
|
||||
doReturn(mWfcSliceHelper).when(mSlicesFeatureProvider)
|
||||
.getNewWifiCallingSliceHelper(mContext);
|
||||
|
||||
final Slice slice = mProvider.onBindSlice(mWfcURI);
|
||||
|
||||
assertThat(mWfcSliceHelper.getDefaultVoiceSubId()).isEqualTo(1);
|
||||
testWifiCallingSettingsToggleSlice(slice, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_SliceBroadcastReceiver_toggleOffWifiCalling() {
|
||||
doReturn(true).when(mMockImsManager).isWfcEnabledByPlatform();
|
||||
doReturn(true).when(mMockImsManager).isWfcProvisionedOnDevice();
|
||||
doReturn(false).when(mMockImsManager).isWfcEnabledByUser();
|
||||
doReturn(true).when(mMockImsManager).isNonTtyOrTtyOnVolteEnabled();
|
||||
doReturn(mWfcSliceHelper).when(mSlicesFeatureProvider)
|
||||
.getNewWifiCallingSliceHelper(mContext);
|
||||
mWfcSliceHelper.setActivationAppIntent(null);
|
||||
|
||||
ArgumentCaptor<Boolean> mWfcSettingCaptor = ArgumentCaptor.forClass(Boolean.class);
|
||||
|
||||
// turn on Wifi calling setting
|
||||
Intent intent = new Intent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED);
|
||||
intent.putExtra(EXTRA_TOGGLE_STATE, true);
|
||||
|
||||
// change the setting
|
||||
mReceiver.onReceive(mContext, intent);
|
||||
|
||||
verify((mMockImsManager)).setWfcSetting(mWfcSettingCaptor.capture());
|
||||
|
||||
// assert the change
|
||||
assertThat(mWfcSettingCaptor.getValue()).isTrue();
|
||||
}
|
||||
|
||||
private void testWifiCallingSettingsUnavailableSlice(Slice slice,
|
||||
SliceData sliceData, PendingIntent expectedPrimaryAction) {
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
|
||||
|
||||
//Check there is no toggle action
|
||||
final List<SliceAction> toggles = metadata.getToggles();
|
||||
assertThat(toggles).isEmpty();
|
||||
|
||||
// Check whether the primary action is to open wifi calling settings activity
|
||||
final PendingIntent primaryPendingIntent =
|
||||
metadata.getPrimaryAction().getAction();
|
||||
assertThat(primaryPendingIntent).isEqualTo(expectedPrimaryAction);
|
||||
|
||||
// Check the title
|
||||
final List<SliceItem> sliceItems = slice.getItems();
|
||||
assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title));
|
||||
}
|
||||
|
||||
private void testWifiCallingSettingsToggleSlice(Slice slice,
|
||||
SliceData sliceData) {
|
||||
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
|
||||
|
||||
final List<SliceAction> toggles = metadata.getToggles();
|
||||
assertThat(toggles).hasSize(1);
|
||||
|
||||
final SliceAction mainToggleAction = toggles.get(0);
|
||||
|
||||
// Check intent in Toggle Action
|
||||
final PendingIntent togglePendingIntent = mainToggleAction.getAction();
|
||||
final PendingIntent expectedToggleIntent = getBroadcastIntent(
|
||||
WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED);
|
||||
assertThat(togglePendingIntent).isEqualTo(expectedToggleIntent);
|
||||
|
||||
// Check primary intent
|
||||
final PendingIntent primaryPendingIntent = metadata.getPrimaryAction().getAction();
|
||||
final PendingIntent expectedPendingIntent =
|
||||
getActivityIntent(WifiCallingSliceHelper.ACTION_WIFI_CALLING_SETTINGS_ACTIVITY);
|
||||
assertThat(primaryPendingIntent).isEqualTo(expectedPendingIntent);
|
||||
|
||||
// Check the title
|
||||
final List<SliceItem> sliceItems = slice.getItems();
|
||||
assertTitle(sliceItems, mContext.getString(R.string.wifi_calling_settings_title));
|
||||
}
|
||||
|
||||
private PendingIntent getBroadcastIntent(String action) {
|
||||
final Intent intent = new Intent(action);
|
||||
intent.setClass(mContext, SliceBroadcastReceiver.class);
|
||||
return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
}
|
||||
|
||||
private PendingIntent getActivityIntent(String action) {
|
||||
final Intent intent = new Intent(action);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */);
|
||||
}
|
||||
|
||||
private void assertTitle(List<SliceItem> sliceItems, String title) {
|
||||
boolean hasTitle = false;
|
||||
for (SliceItem item : sliceItems) {
|
||||
List<SliceItem> titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE,
|
||||
null /* non-hints */);
|
||||
if (titleItems == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hasTitle = true;
|
||||
for (SliceItem subTitleItem : titleItems) {
|
||||
assertThat(subTitleItem.getText()).isEqualTo(title);
|
||||
}
|
||||
}
|
||||
assertThat(hasTitle).isTrue();
|
||||
}
|
||||
private class FakeWifiCallingSliceHelper extends WifiCallingSliceHelper {
|
||||
int mSubId = 1;
|
||||
|
||||
private Intent mActivationAppIntent;
|
||||
FakeWifiCallingSliceHelper(Context context) {
|
||||
super(context);
|
||||
mActivationAppIntent = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CarrierConfigManager getCarrierConfigManager(Context mContext) {
|
||||
return mMockCarrierConfigManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImsManager getImsManager(int subId) {
|
||||
return mMockImsManager;
|
||||
}
|
||||
|
||||
protected int getDefaultVoiceSubId() {
|
||||
return mSubId;
|
||||
}
|
||||
|
||||
protected void setDefaultVoiceSubId(int id) {
|
||||
mSubId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Intent getWifiCallingCarrierActivityIntent(int subId) {
|
||||
return mActivationAppIntent;
|
||||
}
|
||||
|
||||
public void setActivationAppIntent(Intent intent) {
|
||||
mActivationAppIntent = intent;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user