Apply bullet permission UI to multiple device dialog
Sepreate to two dialogs for non-null profile. One for the device chooser and another one for bullet permission dialog. Test: Cts Fix: 271311544, 267646302 Change-Id: I8229ce00f17281736aa91a1a9cceea9aaeee35ee
This commit is contained in:
@@ -144,7 +144,7 @@
|
||||
android:visibility="gone"
|
||||
android:duplicateParentState="true"
|
||||
android:clickable="false"
|
||||
android:text="@string/consent_no" />
|
||||
android:text="@string/consent_cancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -28,13 +28,13 @@
|
||||
<string name="profile_name_watch">watch</string>
|
||||
|
||||
<!-- Title of the device selection dialog. -->
|
||||
<string name="chooser_title">Choose a <xliff:g id="profile_name" example="watch">%1$s</xliff:g> to be managed by <strong><xliff:g id="app_name" example="Android Wear">%2$s</xliff:g></strong></string>
|
||||
<string name="chooser_title_non_profile">Choose a device to be managed by <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong></string>
|
||||
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of WATCH profile (type) [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_watch">This app is needed to manage your <xliff:g id="device_name" example="My Watch">%1$s</xliff:g>. <xliff:g id="app_name" example="Android Wear">%2$s</xliff:g> will be allowed to sync info, like the name of someone calling, interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.</string>
|
||||
<!-- Tile of the multiple devices' dialog. -->
|
||||
<string name="chooser_title">Choose a <xliff:g id="profile_name" example="watch">%1$s</xliff:g> to set up</string>
|
||||
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of WATCH profile for singleDevice(type) [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_watch_single_device">This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="device_type" example="phone">%1$s</xliff:g></string>
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of WATCH profile [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_watch">This app will be allowed to sync info, like the name of someone calling, and access these permissions on your <xliff:g id="device_name" example="phone">%1$s</xliff:g></string>
|
||||
|
||||
<!-- ================= DEVICE_PROFILE_GLASSES ================= -->
|
||||
|
||||
@@ -42,13 +42,10 @@
|
||||
<string name="confirmation_title_glasses">Allow <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> to manage <strong><xliff:g id="device_name" example="Glasses">%2$s</xliff:g></strong>?</string>
|
||||
|
||||
<!-- The name of the "glasses" device type [CHAR LIMIT=30] -->
|
||||
<string name="profile_name_glasses">glasses</string>
|
||||
<string name="profile_name_glasses">device</string>
|
||||
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile (type) [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_glasses_multi_device">This app is needed to manage <xliff:g id="device_name" example="My Glasses">%1$s</xliff:g>. <xliff:g id="app_name" example="Glasses">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Microphone and Nearby devices permissions.</string>
|
||||
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile for singleDevice(type) [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_glasses_single_device">This app will be allowed to access these permissions on your <xliff:g id="device_type" example="phone">%1$s</xliff:g></string>
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of GLASSES profile [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_glasses">This app will be allowed to access these permissions on your <xliff:g id="device_name" example="phone">%1$s</xliff:g></string>
|
||||
|
||||
<!-- ================= DEVICE_PROFILE_APP_STREAMING ================= -->
|
||||
|
||||
@@ -96,9 +93,6 @@
|
||||
<!-- A noun for a companion device with unspecified profile (type) [CHAR LIMIT=30] -->
|
||||
<string name="profile_name_generic">device</string>
|
||||
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of unspecified profile (type) [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_generic_single_device">This app will be able to sync info, like the name of someone calling, between your phone and <xliff:g id="device_name" example="My Watch">%1$s</xliff:g></string>
|
||||
|
||||
<!-- Description of the privileges the application will get if associated with the companion device of unspecified profile (type) [CHAR LIMIT=NONE] -->
|
||||
<string name="summary_generic">This app will be able to sync info, like the name of someone calling, between your phone and the chosen device</string>
|
||||
|
||||
@@ -110,6 +104,9 @@
|
||||
<!-- Negative button for the device-app association consent dialog [CHAR LIMIT=30] -->
|
||||
<string name="consent_no">Don\u2019t allow</string>
|
||||
|
||||
<!-- Cancel button for the device chooser dialog [CHAR LIMIT=30] -->
|
||||
<string name="consent_cancel">Cancel</string>
|
||||
|
||||
<!-- Back button for the helper consent dialog [CHAR LIMIT=30] -->
|
||||
<string name="consent_back">Back</string>
|
||||
|
||||
|
||||
@@ -69,11 +69,13 @@
|
||||
|
||||
<style name="PositiveButton"
|
||||
parent="@android:style/Widget.Material.Button.Borderless.Colored">
|
||||
<item name="android:layout_width">300dp</item>
|
||||
<item name="android:layout_height">56dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginBottom">2dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:layout_marginStart">32dp</item>
|
||||
<item name="android:layout_marginEnd">32dp</item>
|
||||
<item name="android:textColor">@android:color/system_neutral1_900</item>
|
||||
<item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
|
||||
<item name="android:background">@drawable/btn_positive_bottom</item>
|
||||
@@ -81,11 +83,13 @@
|
||||
|
||||
<style name="NegativeButton"
|
||||
parent="@android:style/Widget.Material.Button.Borderless.Colored">
|
||||
<item name="android:layout_width">300dp</item>
|
||||
<item name="android:layout_height">56dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_marginTop">2dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:layout_marginStart">32dp</item>
|
||||
<item name="android:layout_marginEnd">32dp</item>
|
||||
<item name="android:textColor">@android:color/system_neutral1_900</item>
|
||||
<item name="android:layout_marginTop">4dp</item>
|
||||
<item name="android:textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
|
||||
|
||||
@@ -27,10 +27,8 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE
|
||||
|
||||
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceResources.MULTI_DEVICES_SUMMARIES;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceResources.PERMISSION_TYPES;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILES_NAME_MULTI;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_ICON;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceResources.SUMMARIES;
|
||||
import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES;
|
||||
@@ -121,6 +119,9 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
private IAssociationRequestCallback mAppCallback;
|
||||
private ResultReceiver mCdmServiceReceiver;
|
||||
|
||||
// Present for application's name.
|
||||
private CharSequence mAppLabel;
|
||||
|
||||
// Always present widgets.
|
||||
private TextView mTitle;
|
||||
private TextView mSummary;
|
||||
@@ -165,8 +166,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
private @Nullable RecyclerView mDeviceListRecyclerView;
|
||||
private @Nullable DeviceListAdapter mDeviceAdapter;
|
||||
|
||||
|
||||
// The recycler view is only shown for selfManaged and singleDevice association request.
|
||||
// The recycler view is shown for non-null profile association request.
|
||||
private @Nullable RecyclerView mPermissionListRecyclerView;
|
||||
private @Nullable PermissionListAdapter mPermissionListAdapter;
|
||||
|
||||
@@ -178,8 +178,6 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
// onActivityResult() after the association is created.
|
||||
private @Nullable DeviceFilterPair<?> mSelectedDevice;
|
||||
|
||||
private @Nullable List<Integer> mPermissionTypes;
|
||||
|
||||
private LinearLayoutManager mPermissionsLayoutManager = new LinearLayoutManager(this);
|
||||
|
||||
@Override
|
||||
@@ -302,6 +300,8 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
|
||||
setContentView(R.layout.activity_confirmation);
|
||||
|
||||
mAppLabel = appLabel;
|
||||
|
||||
mConstraintList = findViewById(R.id.constraint_list);
|
||||
mAssociationConfirmationDialog = findViewById(R.id.association_confirmation);
|
||||
mVendorHeader = findViewById(R.id.vendor_header);
|
||||
@@ -322,7 +322,6 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
|
||||
mMultipleDeviceSpinner = findViewById(R.id.spinner_multiple_device);
|
||||
mSingleDeviceSpinner = findViewById(R.id.spinner_single_device);
|
||||
mDeviceAdapter = new DeviceListAdapter(this, this::onListItemClick);
|
||||
|
||||
mPermissionListRecyclerView = findViewById(R.id.permission_list);
|
||||
mPermissionListAdapter = new PermissionListAdapter(this);
|
||||
@@ -468,8 +467,6 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
throw new RuntimeException("Unsupported profile " + deviceProfile);
|
||||
}
|
||||
|
||||
mPermissionTypes = new ArrayList<>();
|
||||
|
||||
try {
|
||||
vendorIcon = getVendorHeaderIcon(this, packageName, userId);
|
||||
vendorName = getVendorHeaderName(this, packageName, userId);
|
||||
@@ -486,17 +483,13 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
}
|
||||
|
||||
title = getHtmlFromResources(this, TITLES.get(deviceProfile), deviceName);
|
||||
mPermissionTypes.addAll(PERMISSION_TYPES.get(deviceProfile));
|
||||
setupPermissionList(deviceProfile);
|
||||
|
||||
// Summary is not needed for selfManaged dialog.
|
||||
mSummary.setVisibility(View.GONE);
|
||||
|
||||
setupPermissionList();
|
||||
|
||||
mTitle.setText(title);
|
||||
mVendorHeaderName.setText(vendorName);
|
||||
mVendorHeader.setVisibility(View.VISIBLE);
|
||||
mVendorHeader.setVisibility(View.VISIBLE);
|
||||
mProfileIcon.setVisibility(View.GONE);
|
||||
mDeviceListRecyclerView.setVisibility(View.GONE);
|
||||
// Top and bottom borders should be gone for selfManaged dialog.
|
||||
@@ -509,7 +502,9 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
|
||||
final String deviceProfile = mRequest.getDeviceProfile();
|
||||
|
||||
mPermissionTypes = new ArrayList<>();
|
||||
if (!SUPPORTED_PROFILES.contains(deviceProfile)) {
|
||||
throw new RuntimeException("Unsupported profile " + deviceProfile);
|
||||
}
|
||||
|
||||
CompanionDeviceDiscoveryService.getScanResult().observe(this,
|
||||
deviceFilterPairs -> updateSingleDeviceUi(
|
||||
@@ -529,75 +524,40 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
if (deviceFilterPairs.isEmpty()) return;
|
||||
|
||||
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
|
||||
// No need to show user consent dialog if it is a singleDevice
|
||||
// and isSkipPrompt(true) AssociationRequest.
|
||||
// See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
|
||||
if (mRequest.isSkipPrompt()) {
|
||||
mSingleDeviceSpinner.setVisibility(View.GONE);
|
||||
onUserSelectedDevice(mSelectedDevice);
|
||||
return;
|
||||
}
|
||||
|
||||
final String deviceName = mSelectedDevice.getDisplayName();
|
||||
final Spanned title;
|
||||
final Spanned summary;
|
||||
final Drawable profileIcon;
|
||||
final Drawable profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
|
||||
|
||||
if (!SUPPORTED_PROFILES.contains(deviceProfile)) {
|
||||
throw new RuntimeException("Unsupported profile " + deviceProfile);
|
||||
}
|
||||
updatePermissionUi();
|
||||
|
||||
if (deviceProfile == null) {
|
||||
summary = getHtmlFromResources(this, SUMMARIES.get(null), deviceName);
|
||||
mConstraintList.setVisibility(View.GONE);
|
||||
} else {
|
||||
summary = getHtmlFromResources(
|
||||
this, SUMMARIES.get(deviceProfile), getString(R.string.device_type));
|
||||
mPermissionTypes.addAll(PERMISSION_TYPES.get(deviceProfile));
|
||||
setupPermissionList();
|
||||
}
|
||||
|
||||
title = getHtmlFromResources(this, TITLES.get(deviceProfile), appLabel, deviceName);
|
||||
profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
|
||||
|
||||
mTitle.setText(title);
|
||||
mSummary.setText(summary);
|
||||
mProfileIcon.setImageDrawable(profileIcon);
|
||||
mSingleDeviceSpinner.setVisibility(View.GONE);
|
||||
mAssociationConfirmationDialog.setVisibility(View.VISIBLE);
|
||||
mSingleDeviceSpinner.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void initUiForMultipleDevices(CharSequence appLabel) {
|
||||
if (DEBUG) Log.i(TAG, "initUiFor_MultipleDevices()");
|
||||
|
||||
final String deviceProfile = mRequest.getDeviceProfile();
|
||||
|
||||
final String profileName;
|
||||
final String profileNameMulti;
|
||||
final Spanned summary;
|
||||
final Drawable profileIcon;
|
||||
final int summaryResourceId;
|
||||
final Spanned title;
|
||||
final String deviceProfile = mRequest.getDeviceProfile();
|
||||
|
||||
if (!SUPPORTED_PROFILES.contains(deviceProfile)) {
|
||||
throw new RuntimeException("Unsupported profile " + deviceProfile);
|
||||
}
|
||||
|
||||
profileName = getString(PROFILES_NAME.get(deviceProfile));
|
||||
profileNameMulti = getString(PROFILES_NAME_MULTI.get(deviceProfile));
|
||||
profileIcon = getIcon(this, PROFILE_ICON.get(deviceProfile));
|
||||
summaryResourceId = MULTI_DEVICES_SUMMARIES.get(deviceProfile);
|
||||
|
||||
if (deviceProfile == null) {
|
||||
summary = getHtmlFromResources(this, summaryResourceId);
|
||||
title = getHtmlFromResources(this, R.string.chooser_title_non_profile, appLabel);
|
||||
mButtonNotAllowMultipleDevices.setText(R.string.consent_no);
|
||||
} else {
|
||||
summary = getHtmlFromResources(this, summaryResourceId, profileName, appLabel);
|
||||
title = getHtmlFromResources(this,
|
||||
R.string.chooser_title, getString(PROFILES_NAME.get(deviceProfile)));
|
||||
}
|
||||
|
||||
final Spanned title = getHtmlFromResources(
|
||||
this, R.string.chooser_title, profileNameMulti, appLabel);
|
||||
mDeviceAdapter = new DeviceListAdapter(this, this::onDeviceClicked);
|
||||
|
||||
mTitle.setText(title);
|
||||
mSummary.setText(summary);
|
||||
mProfileIcon.setImageDrawable(profileIcon);
|
||||
|
||||
mDeviceListRecyclerView.setAdapter(mDeviceAdapter);
|
||||
@@ -613,6 +573,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
mDeviceAdapter.setDevices(deviceFilterPairs);
|
||||
});
|
||||
|
||||
mSummary.setVisibility(View.GONE);
|
||||
// "Remove" consent button: users would need to click on the list item.
|
||||
mButtonAllow.setVisibility(View.GONE);
|
||||
mButtonNotAllow.setVisibility(View.GONE);
|
||||
@@ -623,11 +584,9 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
mMultipleDeviceSpinner.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void onListItemClick(int position) {
|
||||
if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
|
||||
|
||||
private void onDeviceClicked(int position) {
|
||||
final DeviceFilterPair<?> selectedDevice = mDeviceAdapter.getItem(position);
|
||||
|
||||
// To prevent double tap on the selected device.
|
||||
if (mSelectedDevice != null) {
|
||||
if (DEBUG) Log.w(TAG, "Already selected.");
|
||||
return;
|
||||
@@ -637,7 +596,47 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
|
||||
mSelectedDevice = requireNonNull(selectedDevice);
|
||||
|
||||
onUserSelectedDevice(selectedDevice);
|
||||
Log.d(TAG, "onDeviceClicked(): " + mSelectedDevice.toShortString());
|
||||
|
||||
updatePermissionUi();
|
||||
|
||||
mSummary.setVisibility(View.VISIBLE);
|
||||
mButtonAllow.setVisibility(View.VISIBLE);
|
||||
mButtonNotAllow.setVisibility(View.VISIBLE);
|
||||
mDeviceListRecyclerView.setVisibility(View.GONE);
|
||||
mNotAllowMultipleDevicesLayout.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void updatePermissionUi() {
|
||||
final String deviceProfile = mRequest.getDeviceProfile();
|
||||
final int summaryResourceId = SUMMARIES.get(deviceProfile);
|
||||
final String remoteDeviceName = mSelectedDevice.getDisplayName();
|
||||
final Spanned title = getHtmlFromResources(
|
||||
this, TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
|
||||
final Spanned summary;
|
||||
|
||||
// No need to show permission consent dialog if it is a isSkipPrompt(true)
|
||||
// AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
|
||||
if (mRequest.isSkipPrompt()) {
|
||||
mSingleDeviceSpinner.setVisibility(View.GONE);
|
||||
onUserSelectedDevice(mSelectedDevice);
|
||||
return;
|
||||
}
|
||||
|
||||
if (deviceProfile == null && mRequest.isSingleDevice()) {
|
||||
summary = getHtmlFromResources(this, summaryResourceId, remoteDeviceName);
|
||||
mConstraintList.setVisibility(View.GONE);
|
||||
} else if (deviceProfile == null) {
|
||||
onUserSelectedDevice(mSelectedDevice);
|
||||
return;
|
||||
} else {
|
||||
summary = getHtmlFromResources(
|
||||
this, summaryResourceId, getString(R.string.device_type));
|
||||
setupPermissionList(deviceProfile);
|
||||
}
|
||||
|
||||
mTitle.setText(title);
|
||||
mSummary.setText(summary);
|
||||
}
|
||||
|
||||
private void onPositiveButtonClick(View v) {
|
||||
@@ -680,8 +679,9 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
// initiate the layoutManager for the recyclerview, add listeners for monitoring the scrolling
|
||||
// and when mPermissionListRecyclerView is fully populated.
|
||||
// Lastly, disable the Allow and Don't allow buttons.
|
||||
private void setupPermissionList() {
|
||||
mPermissionListAdapter.setPermissionType(mPermissionTypes);
|
||||
private void setupPermissionList(String deviceProfile) {
|
||||
final List<Integer> permissionTypes = new ArrayList<>(PERMISSION_TYPES.get(deviceProfile));
|
||||
mPermissionListAdapter.setPermissionType(permissionTypes);
|
||||
mPermissionListRecyclerView.setAdapter(mPermissionListAdapter);
|
||||
mPermissionListRecyclerView.setLayoutManager(mPermissionsLayoutManager);
|
||||
|
||||
|
||||
@@ -84,23 +84,13 @@ final class CompanionDeviceResources {
|
||||
}
|
||||
|
||||
static final Map<String, Integer> SUMMARIES;
|
||||
static {
|
||||
final Map<String, Integer> map = new ArrayMap<>();
|
||||
map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch_single_device);
|
||||
map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses_single_device);
|
||||
map.put(null, R.string.summary_generic_single_device);
|
||||
|
||||
SUMMARIES = unmodifiableMap(map);
|
||||
}
|
||||
|
||||
static final Map<String, Integer> MULTI_DEVICES_SUMMARIES;
|
||||
static {
|
||||
final Map<String, Integer> map = new ArrayMap<>();
|
||||
map.put(DEVICE_PROFILE_WATCH, R.string.summary_watch);
|
||||
map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses_multi_device);
|
||||
map.put(DEVICE_PROFILE_GLASSES, R.string.summary_glasses);
|
||||
map.put(null, R.string.summary_generic);
|
||||
|
||||
MULTI_DEVICES_SUMMARIES = unmodifiableMap(map);
|
||||
SUMMARIES = unmodifiableMap(map);
|
||||
}
|
||||
|
||||
static final Map<String, Integer> PROFILES_NAME;
|
||||
|
||||
Reference in New Issue
Block a user