Base implementation of WFC disclaimer UI
Test: manual - Check that no error occurred when changing the wifi calling settings to turn on. Test: auto - Passed WifiCallingSettingsForSubTest, WifiCallingDisclaimerFragmentTest and DisclaimerItemListAdapterTest. Bug: 67872298 Change-Id: I789f530d3e16baa6e56feaa4269f6696976f747e
This commit is contained in:
committed by
Hall Liu
parent
60d64cecd4
commit
9fae73915c
@@ -3124,6 +3124,18 @@
|
|||||||
|
|
||||||
<activity android:name=".homepage.contextualcards.ContextualCardFeedbackDialog"
|
<activity android:name=".homepage.contextualcards.ContextualCardFeedbackDialog"
|
||||||
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
|
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="Settings$WifiCallingDisclaimerActivity"
|
||||||
|
android:label="@string/wifi_calling_settings_title"
|
||||||
|
android:taskAffinity="com.android.settings">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||||
|
android:value="com.android.settings.wifi.calling.WifiCallingDisclaimerFragment" />
|
||||||
|
</activity>
|
||||||
<!-- This is the longest AndroidManifest.xml ever. -->
|
<!-- This is the longest AndroidManifest.xml ever. -->
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
67
res/layout/wfc_disclaimer_fragment.xml
Normal file
67
res/layout/wfc_disclaimer_fragment.xml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:text="@string/wfc_disclaimer_title_text" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/disclaimer_item_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/disagree_button"
|
||||||
|
style="@style/DisclaimerNegativeButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="@string/wfc_disclaimer_disagree_text" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/agree_button"
|
||||||
|
style="@style/DisclaimerPositiveButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="@string/wfc_disclaimer_agree_button_text" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
36
res/layout/wfc_simple_disclaimer_item.xml
Normal file
36
res/layout/wfc_simple_disclaimer_item.xml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 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.
|
||||||
|
-->
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="20dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/disclaimer_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@android:style/TextAppearance.Material.Subhead" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/disclaimer_desc"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@android:style/TextAppearance.Material.Body1"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:layout_below="@id/disclaimer_title" />
|
||||||
|
</RelativeLayout>
|
@@ -10758,6 +10758,15 @@
|
|||||||
<!-- Summary for represent which device is playing media [CHAR LIMIT=NONE] -->
|
<!-- Summary for represent which device is playing media [CHAR LIMIT=NONE] -->
|
||||||
<string name="media_output_panel_summary_of_playing_device">Currently playing on <xliff:g id="device_name" example="Bose headphone">%1$s</xliff:g></string>
|
<string name="media_output_panel_summary_of_playing_device">Currently playing on <xliff:g id="device_name" example="Bose headphone">%1$s</xliff:g></string>
|
||||||
|
|
||||||
|
<!-- Label for the title on wfc disclaimer fragment. [CHAR LIMIT=40] -->
|
||||||
|
<string name="wfc_disclaimer_title_text">Important information</string>
|
||||||
|
|
||||||
|
<!-- Label for the agree button on wfc disclaimer fragment. [CHAR LIMIT=30] -->
|
||||||
|
<string name="wfc_disclaimer_agree_button_text">CONTINUE</string>
|
||||||
|
|
||||||
|
<!-- Label for the disagree button on wfc disclaimer fragment. [CHAR LIMIT=30] -->
|
||||||
|
<string name="wfc_disclaimer_disagree_text">NO THANKS</string>
|
||||||
|
|
||||||
<!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
|
<!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
|
||||||
<string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
|
<string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
|
||||||
|
|
||||||
|
@@ -520,4 +520,17 @@
|
|||||||
<!-- Padding between content and the start icon is 8dp. -->
|
<!-- Padding between content and the start icon is 8dp. -->
|
||||||
<item name="contentStartPadding">8dp</item>
|
<item name="contentStartPadding">8dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="DisclaimerPositiveButton" parent="@style/SudGlifButton.Primary">
|
||||||
|
<item name="android:layout_margin">16dp</item>
|
||||||
|
<item name="android:paddingStart">8dp</item>
|
||||||
|
<item name="android:paddingEnd">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="DisclaimerNegativeButton" parent="@style/SudGlifButton.Secondary">
|
||||||
|
<item name="android:layout_margin">16dp</item>
|
||||||
|
<item name="android:paddingStart">8dp</item>
|
||||||
|
<item name="android:paddingEnd">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@@ -159,6 +159,7 @@ public class Settings extends SettingsActivity {
|
|||||||
public static class WebViewAppPickerActivity extends SettingsActivity { /* empty */ }
|
public static class WebViewAppPickerActivity extends SettingsActivity { /* empty */ }
|
||||||
public static class AdvancedConnectedDeviceActivity extends SettingsActivity { /* empty */ }
|
public static class AdvancedConnectedDeviceActivity extends SettingsActivity { /* empty */ }
|
||||||
public static class BluetoothDeviceDetailActivity extends SettingsActivity { /* empty */ }
|
public static class BluetoothDeviceDetailActivity extends SettingsActivity { /* empty */ }
|
||||||
|
public static class WifiCallingDisclaimerActivity extends SettingsActivity { /* empty */ }
|
||||||
|
|
||||||
// Top level categories for new IA
|
// Top level categories for new IA
|
||||||
public static class NetworkDashboardActivity extends SettingsActivity {}
|
public static class NetworkDashboardActivity extends SettingsActivity {}
|
||||||
|
@@ -135,6 +135,7 @@ import com.android.settings.wifi.ConfigureWifiSettings;
|
|||||||
import com.android.settings.wifi.WifiAPITest;
|
import com.android.settings.wifi.WifiAPITest;
|
||||||
import com.android.settings.wifi.WifiInfo;
|
import com.android.settings.wifi.WifiInfo;
|
||||||
import com.android.settings.wifi.WifiSettings;
|
import com.android.settings.wifi.WifiSettings;
|
||||||
|
import com.android.settings.wifi.calling.WifiCallingDisclaimerFragment;
|
||||||
import com.android.settings.wifi.calling.WifiCallingSettings;
|
import com.android.settings.wifi.calling.WifiCallingSettings;
|
||||||
import com.android.settings.wifi.p2p.WifiP2pSettings;
|
import com.android.settings.wifi.p2p.WifiP2pSettings;
|
||||||
import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
|
import com.android.settings.wifi.savedaccesspoints.SavedAccessPointsWifiSettings;
|
||||||
@@ -260,6 +261,7 @@ public class SettingsGateway {
|
|||||||
ConnectedDeviceDashboardFragment.class.getName(),
|
ConnectedDeviceDashboardFragment.class.getName(),
|
||||||
UsbDetailsFragment.class.getName(),
|
UsbDetailsFragment.class.getName(),
|
||||||
AppAndNotificationDashboardFragment.class.getName(),
|
AppAndNotificationDashboardFragment.class.getName(),
|
||||||
|
WifiCallingDisclaimerFragment.class.getName(),
|
||||||
AccountDashboardFragment.class.getName(),
|
AccountDashboardFragment.class.getName(),
|
||||||
EnterprisePrivacySettings.class.getName(),
|
EnterprisePrivacySettings.class.getName(),
|
||||||
WebViewAppPicker.class.getName(),
|
WebViewAppPicker.class.getName(),
|
||||||
|
137
src/com/android/settings/wifi/calling/DisclaimerItem.java
Normal file
137
src/com/android/settings/wifi/calling/DisclaimerItem.java
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
import android.telephony.CarrierConfigManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to control disclaimer item from {@link WifiCallingDisclaimerFragment}.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public abstract class DisclaimerItem {
|
||||||
|
private static final String SHARED_PREFERENCES_NAME = "wfc_disclaimer_prefs";
|
||||||
|
|
||||||
|
protected final Context mContext;
|
||||||
|
protected final int mSubId;
|
||||||
|
private final CarrierConfigManager mCarrierConfigManager;
|
||||||
|
|
||||||
|
DisclaimerItem(Context context, int subId) {
|
||||||
|
mContext = context;
|
||||||
|
mSubId = subId;
|
||||||
|
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the {@link WifiCallingDisclaimerFragment} when a user has clicked the agree button.
|
||||||
|
*/
|
||||||
|
void onAgreed() {
|
||||||
|
setBooleanSharedPrefs(getPrefKey(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the disclaimer item need to be displayed or not.
|
||||||
|
*
|
||||||
|
* @return Returns {@code true} if disclaimer item need to be displayed,
|
||||||
|
* {@code false} if not displayed.
|
||||||
|
*/
|
||||||
|
boolean shouldShow() {
|
||||||
|
if (getBooleanSharedPrefs(getPrefKey(), false)) {
|
||||||
|
logd("shouldShow: false due to a user has already agreed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logd("shouldShow: true");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the configuration values for a particular sub id.
|
||||||
|
*
|
||||||
|
* @return The {@link PersistableBundle} instance containing the config value for a
|
||||||
|
* particular phone id, or default values.
|
||||||
|
*/
|
||||||
|
protected PersistableBundle getCarrierConfig() {
|
||||||
|
PersistableBundle config = mCarrierConfigManager.getConfigForSubId(mSubId);
|
||||||
|
if (config != null) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
// Return static default defined in CarrierConfigManager.
|
||||||
|
return CarrierConfigManager.getDefaultConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void logd(String msg) {
|
||||||
|
Log.d(getName(), "[" + mSubId + "] " + msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a title id for disclaimer item.
|
||||||
|
*
|
||||||
|
* @return Title id for disclaimer item.
|
||||||
|
*/
|
||||||
|
protected abstract int getTitleId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a message id for disclaimer item.
|
||||||
|
*
|
||||||
|
* @return Message id for disclaimer item.
|
||||||
|
*/
|
||||||
|
protected abstract int getMessageId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a name of disclaimer item.
|
||||||
|
*
|
||||||
|
* @return Name of disclaimer item.
|
||||||
|
*/
|
||||||
|
protected abstract String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a preference key to keep user's consent.
|
||||||
|
*
|
||||||
|
* @return Preference key to keep user's consent.
|
||||||
|
*/
|
||||||
|
protected abstract String getPrefKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the boolean value from shared preferences.
|
||||||
|
*
|
||||||
|
* @param key The key for the preference item.
|
||||||
|
* @param defValue Value to return if this preference does not exist.
|
||||||
|
* @return The boolean value of corresponding key, or defValue.
|
||||||
|
*/
|
||||||
|
private boolean getBooleanSharedPrefs(String key, boolean defValue) {
|
||||||
|
SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||||
|
Context.MODE_PRIVATE);
|
||||||
|
return prefs.getBoolean(key + mSubId, defValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the boolean value to shared preferences.
|
||||||
|
*
|
||||||
|
* @param key The key for the preference item.
|
||||||
|
* @param value The value to be set for shared preferences.
|
||||||
|
*/
|
||||||
|
private void setBooleanSharedPrefs(String key, boolean value) {
|
||||||
|
SharedPreferences prefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
|
||||||
|
Context.MODE_PRIVATE);
|
||||||
|
prefs.edit().putBoolean(key + mSubId, value).apply();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.content.Context;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class to create disclaimer items list.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
public final class DisclaimerItemFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates disclaimer items list.
|
||||||
|
*
|
||||||
|
* @param context The application context
|
||||||
|
* @param subId The subscription id.
|
||||||
|
* @return The {@link DisclaimerItem} list instance, if there are no items, return empty list.
|
||||||
|
*/
|
||||||
|
public static List<DisclaimerItem> create(Context context, int subId) {
|
||||||
|
List<DisclaimerItem> itemList = getDisclaimerItemList(context, subId);
|
||||||
|
Iterator itr = itemList.iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
DisclaimerItem item = (DisclaimerItem) itr.next();
|
||||||
|
if (!item.shouldShow()) {
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return itemList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<DisclaimerItem> getDisclaimerItemList(Context context, int subId) {
|
||||||
|
List<DisclaimerItem> itemList = new ArrayList<DisclaimerItem>();
|
||||||
|
|
||||||
|
return itemList;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter for disclaimer items list.
|
||||||
|
*/
|
||||||
|
public class DisclaimerItemListAdapter extends
|
||||||
|
RecyclerView.Adapter<DisclaimerItemListAdapter.DisclaimerItemViewHolder> {
|
||||||
|
|
||||||
|
private List<DisclaimerItem> mDisclaimerItemList;
|
||||||
|
|
||||||
|
public DisclaimerItemListAdapter(List<DisclaimerItem> list) {
|
||||||
|
mDisclaimerItemList = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisclaimerItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(
|
||||||
|
Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
View view = inflater.inflate(R.layout.wfc_simple_disclaimer_item, null, false);
|
||||||
|
return new DisclaimerItemViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(DisclaimerItemViewHolder holder, int position) {
|
||||||
|
holder.titleView.setText(mDisclaimerItemList.get(position).getTitleId());
|
||||||
|
holder.descriptionView.setText(mDisclaimerItemList.get(position).getMessageId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mDisclaimerItemList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DisclaimerItemViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int ID_DISCLAIMER_ITEM_TITLE = R.id.disclaimer_title;
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int ID_DISCLAIMER_ITEM_DESCRIPTION = R.id.disclaimer_desc;
|
||||||
|
|
||||||
|
public final TextView titleView;
|
||||||
|
public final TextView descriptionView;
|
||||||
|
|
||||||
|
public DisclaimerItemViewHolder(View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
titleView = itemView.findViewById(ID_DISCLAIMER_ITEM_TITLE);
|
||||||
|
descriptionView = itemView.findViewById(ID_DISCLAIMER_ITEM_DESCRIPTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* 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 android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.telephony.SubscriptionManager;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.InstrumentedFragment;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragment for displaying disclaimers for WFC.
|
||||||
|
*/
|
||||||
|
public class WifiCallingDisclaimerFragment extends InstrumentedFragment
|
||||||
|
implements View.OnClickListener {
|
||||||
|
private static final String TAG = "WifiCallingDisclaimerFragment";
|
||||||
|
|
||||||
|
private static final String STATE_IS_SCROLL_TO_BOTTOM = "state_is_scroll_to_bottom";
|
||||||
|
|
||||||
|
private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<DisclaimerItem>();
|
||||||
|
private Button mAgreeButton;
|
||||||
|
private Button mDisagreeButton;
|
||||||
|
private boolean mScrollToBottom;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return MetricsEvent.WIFI_CALLING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
final Bundle args = getArguments();
|
||||||
|
final int subId = (args != null) ? args.getInt(WifiCallingSettingsForSub.EXTRA_SUB_ID)
|
||||||
|
: SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
|
||||||
|
|
||||||
|
mDisclaimerItemList = DisclaimerItemFactory.create(getActivity(), subId);
|
||||||
|
if (mDisclaimerItemList.isEmpty()) {
|
||||||
|
finish(Activity.RESULT_OK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
mScrollToBottom = savedInstanceState.getBoolean(
|
||||||
|
STATE_IS_SCROLL_TO_BOTTOM, mScrollToBottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
final View view = inflater.inflate(R.layout.wfc_disclaimer_fragment, container, false);
|
||||||
|
|
||||||
|
mAgreeButton = view.findViewById(R.id.agree_button);
|
||||||
|
mAgreeButton.setOnClickListener(this);
|
||||||
|
mDisagreeButton = view.findViewById(R.id.disagree_button);
|
||||||
|
mDisagreeButton.setOnClickListener(this);
|
||||||
|
|
||||||
|
final RecyclerView recyclerView = (RecyclerView) view.findViewById(
|
||||||
|
R.id.disclaimer_item_list);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
|
recyclerView.setAdapter(new DisclaimerItemListAdapter(mDisclaimerItemList));
|
||||||
|
|
||||||
|
RecyclerView.ItemDecoration itemDecoration =
|
||||||
|
new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL);
|
||||||
|
recyclerView.addItemDecoration(itemDecoration);
|
||||||
|
|
||||||
|
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
|
@Override
|
||||||
|
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy);
|
||||||
|
if (!recyclerView.canScrollVertically(1 /* scrolling down */)) {
|
||||||
|
mScrollToBottom = true;
|
||||||
|
updateButtonState();
|
||||||
|
recyclerView.removeOnScrollListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
updateButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putBoolean(STATE_IS_SCROLL_TO_BOTTOM, mScrollToBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateButtonState() {
|
||||||
|
mAgreeButton.setEnabled(mScrollToBottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (v == mAgreeButton) {
|
||||||
|
for (DisclaimerItem item : mDisclaimerItemList) {
|
||||||
|
item.onAgreed();
|
||||||
|
}
|
||||||
|
finish(Activity.RESULT_OK);
|
||||||
|
} else if (v == mDisagreeButton) {
|
||||||
|
finish(Activity.RESULT_CANCELED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void finish(int result) {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
activity.setResult(result, null);
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
}
|
@@ -53,6 +53,7 @@ import com.android.settings.R;
|
|||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.widget.SwitchBar;
|
import com.android.settings.widget.SwitchBar;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,9 +70,13 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
||||||
private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
|
private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
|
||||||
|
|
||||||
private static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
|
@VisibleForTesting
|
||||||
|
static final int REQUEST_CHECK_WFC_EMERGENCY_ADDRESS = 1;
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int REQUEST_CHECK_WFC_DISCLAIMER = 2;
|
||||||
|
|
||||||
public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
|
public static final String EXTRA_LAUNCH_CARRIER_APP = "EXTRA_LAUNCH_CARRIER_APP";
|
||||||
|
public static final String EXTRA_SUB_ID = "EXTRA_SUB_ID";
|
||||||
|
|
||||||
protected static final String FRAGMENT_BUNDLE_SUBID = "subId";
|
protected static final String FRAGMENT_BUNDLE_SUBID = "subId";
|
||||||
|
|
||||||
@@ -172,7 +177,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
|
|
||||||
mEmptyView = getView().findViewById(android.R.id.empty);
|
mEmptyView = getView().findViewById(android.R.id.empty);
|
||||||
setEmptyView(mEmptyView);
|
setEmptyView(mEmptyView);
|
||||||
final Resources res = SubscriptionManager.getResourcesForSubId(getContext(), mSubId);
|
final Resources res = getResourcesForSubId();
|
||||||
String emptyViewText = res.getString(R.string.wifi_calling_off_explanation,
|
String emptyViewText = res.getString(R.string.wifi_calling_off_explanation,
|
||||||
res.getString(R.string.wifi_calling_off_explanation_2));
|
res.getString(R.string.wifi_calling_off_explanation_2));
|
||||||
mEmptyView.setText(emptyViewText);
|
mEmptyView.setText(emptyViewText);
|
||||||
@@ -416,14 +421,17 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call address management activity before turning on WFC
|
// Launch disclaimer fragment before turning on WFC
|
||||||
Intent carrierAppIntent = getCarrierActivityIntent();
|
final Context context = getActivity();
|
||||||
if (carrierAppIntent != null) {
|
final Bundle args = new Bundle();
|
||||||
carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
|
args.putInt(EXTRA_SUB_ID, mSubId);
|
||||||
startActivityForResult(carrierAppIntent, REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
|
new SubSettingLauncher(context)
|
||||||
} else {
|
.setDestination(WifiCallingDisclaimerFragment.class.getName())
|
||||||
updateWfcMode(true);
|
.setArguments(args)
|
||||||
}
|
.setTitleRes(R.string.wifi_calling_settings_title)
|
||||||
|
.setSourceMetricsCategory(getMetricsCategory())
|
||||||
|
.setResultListener(this, REQUEST_CHECK_WFC_DISCLAIMER)
|
||||||
|
.launch();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -476,12 +484,30 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
|
|
||||||
final Context context = getActivity();
|
final Context context = getActivity();
|
||||||
|
|
||||||
if (requestCode == REQUEST_CHECK_WFC_EMERGENCY_ADDRESS) {
|
Log.d(TAG, "WFC activity request = " + requestCode + " result = " + resultCode);
|
||||||
Log.d(TAG, "WFC emergency address activity result = " + resultCode);
|
|
||||||
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
switch (requestCode) {
|
||||||
updateWfcMode(true);
|
case REQUEST_CHECK_WFC_EMERGENCY_ADDRESS:
|
||||||
}
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
updateWfcMode(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REQUEST_CHECK_WFC_DISCLAIMER:
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
// Call address management activity before turning on WFC
|
||||||
|
Intent carrierAppIntent = getCarrierActivityIntent();
|
||||||
|
if (carrierAppIntent != null) {
|
||||||
|
carrierAppIntent.putExtra(EXTRA_LAUNCH_CARRIER_APP, LAUCH_APP_ACTIVATE);
|
||||||
|
startActivityForResult(carrierAppIntent,
|
||||||
|
REQUEST_CHECK_WFC_EMERGENCY_ADDRESS);
|
||||||
|
} else {
|
||||||
|
updateWfcMode(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Unexpected request: " + requestCode);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,4 +594,9 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
return resId;
|
return resId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Resources getResourcesForSubId() {
|
||||||
|
return SubscriptionManager.getResourcesForSubId(getContext(), mSubId, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.testutils.shadow;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.android.settings.wifi.calling.DisclaimerItemFactory;
|
||||||
|
import com.android.settings.wifi.calling.DisclaimerItem;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.robolectric.annotation.Implementation;
|
||||||
|
import org.robolectric.annotation.Implements;
|
||||||
|
|
||||||
|
@Implements(DisclaimerItemFactory.class)
|
||||||
|
public final class ShadowDisclaimerItemFactory {
|
||||||
|
private static List<DisclaimerItem> sMockDisclaimerItemList;
|
||||||
|
|
||||||
|
public static void setDisclaimerItemList(List<DisclaimerItem> list) {
|
||||||
|
sMockDisclaimerItemList = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Implementation
|
||||||
|
public static List<DisclaimerItem> create(Context context, int subId) {
|
||||||
|
return sMockDisclaimerItemList;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.android.settings.wifi.calling.DisclaimerItemListAdapter
|
||||||
|
.DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_TITLE;
|
||||||
|
import static com.android.settings.wifi.calling.DisclaimerItemListAdapter
|
||||||
|
.DisclaimerItemViewHolder.ID_DISCLAIMER_ITEM_DESCRIPTION;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class DisclaimerItemListAdapterTest {
|
||||||
|
|
||||||
|
private static final int ITEM_POSITION = 0;
|
||||||
|
private static final int DISCLAIMER_TITLE_STRING_ID = 0;
|
||||||
|
private static final int DISCLAIMER_MESSAGE_STRING_ID = 1;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private LayoutInflater mLayoutInflater;
|
||||||
|
@Mock
|
||||||
|
private TextView mTestView;
|
||||||
|
@Mock
|
||||||
|
private TextView mDescView;
|
||||||
|
@Mock
|
||||||
|
private View mView;
|
||||||
|
@Mock
|
||||||
|
private ViewGroup mViewGroup;
|
||||||
|
@Mock
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
private MockDisclaimerItem mDisclaimerItem;
|
||||||
|
private DisclaimerItemListAdapter mDisclaimerItemListAdapter;
|
||||||
|
private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mDisclaimerItem = spy(new MockDisclaimerItem(mContext, 0 /* subId */));
|
||||||
|
mDisclaimerItemList.add(mDisclaimerItem);
|
||||||
|
|
||||||
|
when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
|
||||||
|
when(mViewGroup.getContext()).thenReturn(mContext);
|
||||||
|
when(mViewGroup.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).thenReturn(
|
||||||
|
mLayoutInflater);
|
||||||
|
when(mView.findViewById(ID_DISCLAIMER_ITEM_TITLE)).thenReturn(mTestView);
|
||||||
|
when(mView.findViewById(ID_DISCLAIMER_ITEM_DESCRIPTION)).thenReturn(mDescView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_haveItem_shouldSetText() {
|
||||||
|
final DisclaimerItemListAdapter.DisclaimerItemViewHolder viewHolder =
|
||||||
|
new DisclaimerItemListAdapter.DisclaimerItemViewHolder(mView);
|
||||||
|
|
||||||
|
mDisclaimerItemListAdapter = new DisclaimerItemListAdapter(mDisclaimerItemList);
|
||||||
|
mDisclaimerItemListAdapter.onCreateViewHolder(mViewGroup, 0 /* viewType */);
|
||||||
|
mDisclaimerItemListAdapter.onBindViewHolder(viewHolder, ITEM_POSITION);
|
||||||
|
|
||||||
|
// Check the text is set when the DisclaimerItem exists.
|
||||||
|
verify(viewHolder.titleView).setText(DISCLAIMER_TITLE_STRING_ID);
|
||||||
|
verify(viewHolder.descriptionView).setText(DISCLAIMER_MESSAGE_STRING_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MockDisclaimerItem extends DisclaimerItem {
|
||||||
|
MockDisclaimerItem(Context context, int subId) {
|
||||||
|
super(context, subId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getTitleId() {
|
||||||
|
return DISCLAIMER_TITLE_STRING_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getMessageId() {
|
||||||
|
return DISCLAIMER_MESSAGE_STRING_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getName() {
|
||||||
|
return "MockDisclaimerItem";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPrefKey() {
|
||||||
|
return "mock_pref_key";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowDisclaimerItemFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.Robolectric;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = ShadowDisclaimerItemFactory.class)
|
||||||
|
public class WifiCallingDisclaimerFragmentTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Activity mActivity;
|
||||||
|
@Mock
|
||||||
|
private DisclaimerItem mDisclaimerItem;
|
||||||
|
@Mock
|
||||||
|
private LayoutInflater mLayoutInflater;
|
||||||
|
@Mock
|
||||||
|
private View mView;
|
||||||
|
@Mock
|
||||||
|
private ViewGroup mViewGroup;
|
||||||
|
@Mock
|
||||||
|
private Button mAgreeButton;
|
||||||
|
@Mock
|
||||||
|
private Button mDisagreeButton;
|
||||||
|
@Mock
|
||||||
|
private RecyclerView mRecyclerView;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
ArgumentCaptor<OnClickListener> mOnClickListenerCaptor;
|
||||||
|
@Captor
|
||||||
|
ArgumentCaptor<OnScrollListener> mOnScrollListenerCaptor;
|
||||||
|
|
||||||
|
private WifiCallingDisclaimerFragment mFragment;
|
||||||
|
private List<DisclaimerItem> mDisclaimerItemList = new ArrayList<>();
|
||||||
|
private List<DisclaimerItem> mEmptyDisclaimerItemList = new ArrayList<>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mActivity = Robolectric.setupActivity(Activity.class);
|
||||||
|
mFragment = spy(new WifiCallingDisclaimerFragment());
|
||||||
|
|
||||||
|
doReturn(mActivity).when(mFragment).getActivity();
|
||||||
|
|
||||||
|
when(mLayoutInflater.inflate(anyInt(), anyObject(), anyBoolean())).thenReturn(mView);
|
||||||
|
when(mView.findViewById(R.id.agree_button)).thenReturn(mAgreeButton);
|
||||||
|
when(mView.findViewById(R.id.disagree_button)).thenReturn(mDisagreeButton);
|
||||||
|
when(mView.findViewById(R.id.disclaimer_item_list)).thenReturn(mRecyclerView);
|
||||||
|
when(mView.getId()).thenReturn(R.id.agree_button);
|
||||||
|
|
||||||
|
mOnScrollListenerCaptor = ArgumentCaptor.forClass(OnScrollListener.class);
|
||||||
|
doNothing().when(mRecyclerView).addOnScrollListener(mOnScrollListenerCaptor.capture());
|
||||||
|
mOnClickListenerCaptor = ArgumentCaptor.forClass(OnClickListener.class);
|
||||||
|
doNothing().when(mAgreeButton).setOnClickListener(mOnClickListenerCaptor.capture());
|
||||||
|
|
||||||
|
mDisclaimerItemList.add(mDisclaimerItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onCreate_notHaveItem_shouldFinishFragment() {
|
||||||
|
ShadowDisclaimerItemFactory.setDisclaimerItemList(mEmptyDisclaimerItemList);
|
||||||
|
|
||||||
|
mFragment.onCreate(null /* savedInstanceState */);
|
||||||
|
|
||||||
|
// Check the fragment is finished when the DisclaimerItemList is empty.
|
||||||
|
verify(mFragment).finish(Activity.RESULT_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onCreate_haveItem_shouldNotFinishFragment() {
|
||||||
|
ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
|
||||||
|
|
||||||
|
mFragment.onCreate(null /* savedInstanceState */);
|
||||||
|
|
||||||
|
// Check the fragment is not finished when the DisclaimerItemList is not empty.
|
||||||
|
verify(mFragment, never()).finish(Activity.RESULT_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onScrolled_canNotScroll_shouldEnableAgreeButton() {
|
||||||
|
ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
|
||||||
|
|
||||||
|
when(mRecyclerView.canScrollVertically(1)).thenReturn(false);
|
||||||
|
|
||||||
|
mFragment.onCreate(null /* savedInstanceState */);
|
||||||
|
mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
|
||||||
|
|
||||||
|
mOnScrollListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 0);
|
||||||
|
|
||||||
|
// Check the agreeButton is enabled when the view is scrolled to the bottom end.
|
||||||
|
verify(mAgreeButton).setEnabled(true);
|
||||||
|
// Check the OnScrollListener is removed when the view is scrolled to the bottom end.
|
||||||
|
verify(mRecyclerView).removeOnScrollListener(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onScrolled_canScroll_shouldNotEnableAgreeButton() {
|
||||||
|
ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
|
||||||
|
|
||||||
|
when(mRecyclerView.canScrollVertically(1)).thenReturn(true);
|
||||||
|
|
||||||
|
mFragment.onCreate(null /* savedInstanceState */);
|
||||||
|
mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
|
||||||
|
|
||||||
|
mOnScrollListenerCaptor.getValue().onScrolled(mRecyclerView, 0, 0);
|
||||||
|
|
||||||
|
// Check the agreeButton is not enabled when the view is not scrolled to the bottom end.
|
||||||
|
verify(mAgreeButton, never()).setEnabled(anyBoolean());
|
||||||
|
// Check the OnScrollListener is not removed when the view is not scrolled to
|
||||||
|
// the bottom end.
|
||||||
|
verify(mRecyclerView, never()).removeOnScrollListener(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onClick_agreeButton_shouldFinishFragment() {
|
||||||
|
ShadowDisclaimerItemFactory.setDisclaimerItemList(mDisclaimerItemList);
|
||||||
|
|
||||||
|
mFragment.onCreate(null /* savedInstanceState */);
|
||||||
|
mFragment.onCreateView(mLayoutInflater, mViewGroup, null /* savedInstanceState */);
|
||||||
|
|
||||||
|
mOnClickListenerCaptor.getValue().onClick(mAgreeButton);
|
||||||
|
|
||||||
|
// Check the onAgreed callback is called when "CONTINUE" button is clicked.
|
||||||
|
verify(mDisclaimerItem).onAgreed();
|
||||||
|
// Check the WFC disclaimer fragment is finished when "CONTINUE" button is clicked.
|
||||||
|
verify(mFragment).finish(Activity.RESULT_OK);
|
||||||
|
}
|
||||||
|
}
|
@@ -16,11 +16,14 @@
|
|||||||
|
|
||||||
package com.android.settings.wifi.calling;
|
package com.android.settings.wifi.calling;
|
||||||
|
|
||||||
|
import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyBoolean;
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.eq;
|
import static org.mockito.Mockito.eq;
|
||||||
@@ -31,6 +34,8 @@ import static org.mockito.Mockito.times;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -41,18 +46,22 @@ import android.telephony.ims.ProvisioningManager;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.ims.ImsConfig;
|
import com.android.ims.ImsConfig;
|
||||||
import com.android.ims.ImsManager;
|
import com.android.ims.ImsManager;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||||
import com.android.settings.widget.SwitchBar;
|
import com.android.settings.widget.SwitchBar;
|
||||||
import com.android.settings.widget.ToggleSwitch;
|
import com.android.settings.widget.ToggleSwitch;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@@ -63,6 +72,8 @@ import org.robolectric.util.ReflectionHelpers;
|
|||||||
public class WifiCallingSettingsForSubTest {
|
public class WifiCallingSettingsForSubTest {
|
||||||
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
|
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
|
||||||
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
||||||
|
private static final String TEST_EMERGENCY_ADDRESS_CARRIER_APP =
|
||||||
|
"com.android.settings/.wifi.calling.TestEmergencyAddressCarrierApp";
|
||||||
|
|
||||||
private TestFragment mFragment;
|
private TestFragment mFragment;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
@@ -70,6 +81,7 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
private final PersistableBundle mBundle = new PersistableBundle();
|
private final PersistableBundle mBundle = new PersistableBundle();
|
||||||
|
|
||||||
@Mock private static CarrierConfigManager sCarrierConfigManager;
|
@Mock private static CarrierConfigManager sCarrierConfigManager;
|
||||||
|
@Mock private CarrierConfigManager mMockConfigManager;
|
||||||
@Mock private ImsManager mImsManager;
|
@Mock private ImsManager mImsManager;
|
||||||
@Mock private TelephonyManager mTelephonyManager;
|
@Mock private TelephonyManager mTelephonyManager;
|
||||||
@Mock private PreferenceScreen mPreferenceScreen;
|
@Mock private PreferenceScreen mPreferenceScreen;
|
||||||
@@ -80,6 +92,7 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
@Mock private ImsConfig mImsConfig;
|
@Mock private ImsConfig mImsConfig;
|
||||||
@Mock private ListWithEntrySummaryPreference mButtonWfcMode;
|
@Mock private ListWithEntrySummaryPreference mButtonWfcMode;
|
||||||
@Mock private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
|
@Mock private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
|
||||||
|
@Mock private Preference mUpdateAddress;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -121,6 +134,11 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
doReturn(mBundle).when(sCarrierConfigManager).getConfigForSubId(anyInt());
|
doReturn(mBundle).when(sCarrierConfigManager).getConfigForSubId(anyInt());
|
||||||
setDefaultCarrierConfigValues();
|
setDefaultCarrierConfigValues();
|
||||||
|
|
||||||
|
doReturn(sCarrierConfigManager).when(mActivity).getSystemService(
|
||||||
|
CarrierConfigManager.class);
|
||||||
|
doReturn(mContext.getResources()).when(mFragment).getResourcesForSubId();
|
||||||
|
doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt());
|
||||||
|
|
||||||
mFragment.onAttach(mContext);
|
mFragment.onAttach(mContext);
|
||||||
mFragment.onCreate(null);
|
mFragment.onCreate(null);
|
||||||
mFragment.onActivityCreated(null);
|
mFragment.onActivityCreated(null);
|
||||||
@@ -131,6 +149,9 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
|
CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
|
||||||
mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, true);
|
mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL, true);
|
||||||
mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
|
mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
|
||||||
|
mBundle.putString(
|
||||||
|
CarrierConfigManager.KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING,
|
||||||
|
TEST_EMERGENCY_ADDRESS_CARRIER_APP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -259,6 +280,61 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
eq(true));
|
eq(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onSwitchChanged_enableSetting_shouldLaunchWfcDisclaimerFragment() {
|
||||||
|
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
|
||||||
|
mFragment.onSwitchChanged(null, true);
|
||||||
|
|
||||||
|
// Check the WFC disclaimer fragment is launched.
|
||||||
|
verify(mFragment).startActivityForResult(intentCaptor.capture(),
|
||||||
|
eq(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_DISCLAIMER));
|
||||||
|
Intent intent = intentCaptor.getValue();
|
||||||
|
assertThat(intent.getStringExtra(EXTRA_SHOW_FRAGMENT))
|
||||||
|
.isEqualTo(WifiCallingDisclaimerFragment.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onActivityResult_finishWfcDisclaimerFragment_shouldLaunchCarrierActivity() {
|
||||||
|
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
|
||||||
|
// Emulate the WfcDisclaimerActivity finish.
|
||||||
|
mFragment.onActivityResult(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_DISCLAIMER,
|
||||||
|
Activity.RESULT_OK, null);
|
||||||
|
|
||||||
|
// Check the WFC emergency address activity is launched.
|
||||||
|
verify(mFragment).startActivityForResult(intentCaptor.capture(),
|
||||||
|
eq(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_EMERGENCY_ADDRESS));
|
||||||
|
Intent intent = intentCaptor.getValue();
|
||||||
|
assertEquals(intent.getComponent(), ComponentName.unflattenFromString(
|
||||||
|
TEST_EMERGENCY_ADDRESS_CARRIER_APP));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onActivityResult_finishCarrierActivity_shouldShowWfcPreference() {
|
||||||
|
ReflectionHelpers.setField(mFragment, "mButtonWfcMode", mButtonWfcMode);
|
||||||
|
ReflectionHelpers.setField(mFragment, "mButtonWfcRoamingMode", mButtonWfcRoamingMode);
|
||||||
|
ReflectionHelpers.setField(mFragment, "mUpdateAddress", mUpdateAddress);
|
||||||
|
|
||||||
|
mFragment.onActivityResult(WifiCallingSettingsForSub.REQUEST_CHECK_WFC_EMERGENCY_ADDRESS,
|
||||||
|
Activity.RESULT_OK, null);
|
||||||
|
|
||||||
|
// Check the WFC preferences is added.
|
||||||
|
verify(mPreferenceScreen).addPreference(mButtonWfcMode);
|
||||||
|
verify(mPreferenceScreen).addPreference(mButtonWfcRoamingMode);
|
||||||
|
verify(mPreferenceScreen).addPreference(mUpdateAddress);
|
||||||
|
// Check the WFC enable request.
|
||||||
|
verify(mImsManager).setWfcSetting(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onSwitchChanged_disableSetting_shouldNotLaunchWfcDisclaimerFragment() {
|
||||||
|
mFragment.onSwitchChanged(null, false);
|
||||||
|
|
||||||
|
// Check the WFC disclaimer fragment is not launched.
|
||||||
|
verify(mFragment, never()).startActivityForResult(any(Intent.class), anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
protected class TestFragment extends WifiCallingSettingsForSub {
|
protected class TestFragment extends WifiCallingSettingsForSub {
|
||||||
@Override
|
@Override
|
||||||
protected Object getSystemService(final String name) {
|
protected Object getSystemService(final String name) {
|
||||||
|
Reference in New Issue
Block a user