Merge changes I89c4176c,Ib100e117
* changes: Refactor USB permission and confirm dialogs. Add TV specific TvUsbConfirmActivity and TvUsbPermissionActivity.
This commit is contained in:
committed by
Android (Google) Code Review
commit
a658db4124
@@ -45,5 +45,18 @@
|
||||
|
||||
<!-- Component name of the activity used to inform a user about a sensory being blocked because
|
||||
of privacy settings. -->
|
||||
<string name="config_sensorUseStartedActivity">com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity</string>
|
||||
<string name="config_sensorUseStartedActivity" translatable="false">
|
||||
com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
|
||||
</string>
|
||||
|
||||
<!-- Component name of the activity that shows the request for access to a usb device. -->
|
||||
<string name="config_usbPermissionActivity" translatable="false">
|
||||
com.android.systemui/com.android.systemui.usb.tv.TvUsbPermissionActivity
|
||||
</string>
|
||||
|
||||
<!-- Component name of the activity that confirms the activity to start when a usb device is
|
||||
plugged in. -->
|
||||
<string name="config_usbConfirmActivity" translatable="false">
|
||||
com.android.systemui/com.android.systemui.usb.tv.TvUsbConfirmActivity
|
||||
</string>
|
||||
</resources>
|
||||
|
||||
@@ -442,6 +442,26 @@
|
||||
android:excludeFromRecents="true">
|
||||
</activity>
|
||||
|
||||
<!-- started from UsbDeviceSettingsManager -->
|
||||
<activity android:name=".usb.tv.TvUsbConfirmActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:permission="android.permission.MANAGE_USB"
|
||||
android:theme="@style/BottomSheet"
|
||||
android:finishOnCloseSystemDialogs="true"
|
||||
android:excludeFromRecents="true">
|
||||
</activity>
|
||||
|
||||
<!-- started from UsbDeviceSettingsManager -->
|
||||
<activity android:name=".usb.tv.TvUsbPermissionActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:permission="android.permission.MANAGE_USB"
|
||||
android:theme="@style/BottomSheet"
|
||||
android:finishOnCloseSystemDialogs="true"
|
||||
android:excludeFromRecents="true">
|
||||
</activity>
|
||||
|
||||
<!-- started from UsbDeviceSettingsManager -->
|
||||
<activity android:name=".usb.UsbResolverActivity"
|
||||
android:exported="true"
|
||||
|
||||
@@ -16,180 +16,46 @@
|
||||
|
||||
package com.android.systemui.usb;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.hardware.usb.IUsbManager;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
import com.android.systemui.R;
|
||||
|
||||
public class UsbConfirmActivity extends AlertActivity
|
||||
implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
|
||||
|
||||
private static final String TAG = "UsbConfirmActivity";
|
||||
|
||||
private CheckBox mAlwaysUse;
|
||||
private TextView mClearDefaultHint;
|
||||
private UsbDevice mDevice;
|
||||
private UsbAccessory mAccessory;
|
||||
private ResolveInfo mResolveInfo;
|
||||
private boolean mPermissionGranted;
|
||||
private UsbDisconnectedReceiver mDisconnectedReceiver;
|
||||
/**
|
||||
* Dialog shown to confirm the package to start when a USB device or accessory is attached and there
|
||||
* is only one package that claims to handle this USB device or accessory.
|
||||
*/
|
||||
public class UsbConfirmActivity extends UsbDialogActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
getWindow().addSystemFlags(
|
||||
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
|
||||
super.onCreate(icicle);
|
||||
|
||||
Intent intent = getIntent();
|
||||
mDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
|
||||
mResolveInfo = (ResolveInfo) intent.getParcelableExtra("rinfo");
|
||||
String packageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
|
||||
|
||||
PackageManager packageManager = getPackageManager();
|
||||
String appName = mResolveInfo.loadLabel(packageManager).toString();
|
||||
|
||||
final AlertController.AlertParams ap = mAlertParams;
|
||||
ap.mTitle = appName;
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
final int strId;
|
||||
boolean useRecordWarning = false;
|
||||
if (mDevice == null) {
|
||||
ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName,
|
||||
mAccessory.getDescription());
|
||||
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
|
||||
} else {
|
||||
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
|
||||
boolean hasRecordPermission =
|
||||
PermissionChecker.checkPermissionForPreflight(
|
||||
this, android.Manifest.permission.RECORD_AUDIO, -1, uid,
|
||||
packageName)
|
||||
== android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
|
||||
useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
|
||||
|
||||
int strID = useRecordWarning
|
||||
if (mDialogHelper.isUsbDevice()) {
|
||||
useRecordWarning = mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission();
|
||||
strId = useRecordWarning
|
||||
? R.string.usb_device_confirm_prompt_warn
|
||||
: R.string.usb_device_confirm_prompt;
|
||||
|
||||
ap.mMessage = getString(strID, appName, mDevice.getProductName());
|
||||
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
|
||||
} else {
|
||||
// UsbAccessory case
|
||||
strId = R.string.usb_accessory_confirm_prompt;
|
||||
}
|
||||
ap.mPositiveButtonText = getString(android.R.string.ok);
|
||||
ap.mNegativeButtonText = getString(android.R.string.cancel);
|
||||
ap.mPositiveButtonListener = this;
|
||||
ap.mNegativeButtonListener = this;
|
||||
|
||||
// add "always use" checkbox
|
||||
setAlertParams(strId);
|
||||
// Only show the "always use" checkbox if there is no USB/Record warning
|
||||
if (!useRecordWarning) {
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE);
|
||||
ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
|
||||
mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
|
||||
if (mDevice == null) {
|
||||
mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
|
||||
mAccessory.getDescription()));
|
||||
} else {
|
||||
mAlwaysUse.setText(getString(R.string.always_use_device, appName,
|
||||
mDevice.getProductName()));
|
||||
}
|
||||
mAlwaysUse.setOnCheckedChangeListener(this);
|
||||
mClearDefaultHint = (TextView) ap.mView.findViewById(
|
||||
com.android.internal.R.id.clearDefaultHint);
|
||||
mClearDefaultHint.setVisibility(View.GONE);
|
||||
addAlwaysUseCheckbox();
|
||||
}
|
||||
setupAlert();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mDisconnectedReceiver != null) {
|
||||
unregisterReceiver(mDisconnectedReceiver);
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == AlertDialog.BUTTON_POSITIVE) {
|
||||
try {
|
||||
IBinder b = ServiceManager.getService(USB_SERVICE);
|
||||
IUsbManager service = IUsbManager.Stub.asInterface(b);
|
||||
final int uid = mResolveInfo.activityInfo.applicationInfo.uid;
|
||||
final int userId = UserHandle.myUserId();
|
||||
boolean alwaysUse = mAlwaysUse != null ? mAlwaysUse.isChecked() : false;
|
||||
Intent intent = null;
|
||||
|
||||
if (mDevice != null) {
|
||||
intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
|
||||
|
||||
// grant permission for the device
|
||||
service.grantDevicePermission(mDevice, uid);
|
||||
// set or clear default setting
|
||||
if (alwaysUse) {
|
||||
service.setDevicePackage(
|
||||
mDevice, mResolveInfo.activityInfo.packageName, userId);
|
||||
} else {
|
||||
service.setDevicePackage(mDevice, null, userId);
|
||||
}
|
||||
} else if (mAccessory != null) {
|
||||
intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
|
||||
|
||||
// grant permission for the accessory
|
||||
service.grantAccessoryPermission(mAccessory, uid);
|
||||
// set or clear default setting
|
||||
if (alwaysUse) {
|
||||
service.setAccessoryPackage(
|
||||
mAccessory, mResolveInfo.activityInfo.packageName, userId);
|
||||
} else {
|
||||
service.setAccessoryPackage(mAccessory, null, userId);
|
||||
}
|
||||
}
|
||||
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setComponent(
|
||||
new ComponentName(mResolveInfo.activityInfo.packageName,
|
||||
mResolveInfo.activityInfo.name));
|
||||
startActivityAsUser(intent, new UserHandle(userId));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to start activity", e);
|
||||
}
|
||||
void onConfirm() {
|
||||
mDialogHelper.grantUidAccessPermission();
|
||||
if (isAlwaysUseChecked()) {
|
||||
mDialogHelper.setDefaultPackage();
|
||||
} else {
|
||||
mDialogHelper.clearDefaultPackage();
|
||||
}
|
||||
mDialogHelper.confirmDialogStartActivity();
|
||||
finish();
|
||||
}
|
||||
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (mClearDefaultHint == null) return;
|
||||
|
||||
if(isChecked) {
|
||||
mClearDefaultHint.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mClearDefaultHint.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.systemui.usb;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
import com.android.systemui.R;
|
||||
|
||||
abstract class UsbDialogActivity extends AlertActivity
|
||||
implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
|
||||
|
||||
private static final String TAG = UsbDialogActivity.class.getSimpleName();
|
||||
|
||||
UsbDialogHelper mDialogHelper;
|
||||
private CheckBox mAlwaysUse;
|
||||
private TextView mClearDefaultHint;
|
||||
|
||||
@Override
|
||||
protected final void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addSystemFlags(
|
||||
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
try {
|
||||
mDialogHelper = new UsbDialogHelper(getApplicationContext(), getIntent());
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "unable to initialize", e);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mDialogHelper.registerUsbDisconnectedReceiver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (mDialogHelper != null) {
|
||||
mDialogHelper.unregisterUsbDisconnectedReceiver(this);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == AlertDialog.BUTTON_POSITIVE) {
|
||||
onConfirm();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (mClearDefaultHint == null) return;
|
||||
|
||||
if (isChecked) {
|
||||
mClearDefaultHint.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mClearDefaultHint.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
void setAlertParams(int strId) {
|
||||
final AlertController.AlertParams ap = mAlertParams;
|
||||
ap.mTitle = mDialogHelper.getAppName();
|
||||
ap.mMessage = getString(strId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription());
|
||||
ap.mPositiveButtonText = getString(android.R.string.ok);
|
||||
ap.mNegativeButtonText = getString(android.R.string.cancel);
|
||||
ap.mPositiveButtonListener = this;
|
||||
ap.mNegativeButtonListener = this;
|
||||
}
|
||||
|
||||
void addAlwaysUseCheckbox() {
|
||||
final AlertController.AlertParams ap = mAlertParams;
|
||||
LayoutInflater inflater = getSystemService(LayoutInflater.class);
|
||||
ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
|
||||
mAlwaysUse = ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
|
||||
if (mDialogHelper.isUsbAccessory()) {
|
||||
mAlwaysUse.setText(getString(R.string.always_use_accessory, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription()));
|
||||
} else {
|
||||
// UsbDevice case
|
||||
mAlwaysUse.setText(getString(R.string.always_use_device, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription()));
|
||||
}
|
||||
mAlwaysUse.setOnCheckedChangeListener(this);
|
||||
mClearDefaultHint = ap.mView.findViewById(com.android.internal.R.id.clearDefaultHint);
|
||||
mClearDefaultHint.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
boolean isAlwaysUseChecked() {
|
||||
return mAlwaysUse != null && mAlwaysUse.isChecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the dialog is confirmed.
|
||||
*/
|
||||
abstract void onConfirm();
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.systemui.usb;
|
||||
|
||||
import static android.Manifest.permission.RECORD_AUDIO;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.hardware.usb.IUsbManager;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.systemui.usb.tv.TvUsbPermissionActivity;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to separate model and view for USB permission and confirm dialogs.
|
||||
*/
|
||||
public class UsbDialogHelper {
|
||||
private static final String TAG = TvUsbPermissionActivity.class.getSimpleName();
|
||||
private static final String EXTRA_RESOLVE_INFO = "rinfo";
|
||||
|
||||
private final UsbDevice mDevice;
|
||||
private final UsbAccessory mAccessory;
|
||||
private final ResolveInfo mResolveInfo;
|
||||
private final String mPackageName;
|
||||
private final CharSequence mAppName;
|
||||
private final Context mContext;
|
||||
private final PendingIntent mPendingIntent;
|
||||
private final IUsbManager mUsbService;
|
||||
private final int mUid;
|
||||
private final boolean mCanBeDefault;
|
||||
|
||||
private UsbDisconnectedReceiver mDisconnectedReceiver;
|
||||
private boolean mIsUsbDevice;
|
||||
private boolean mResponseSent;
|
||||
|
||||
/**
|
||||
* @param context The Context of the caller.
|
||||
* @param intent The intent of the caller.
|
||||
* @throws IllegalStateException Thrown if both UsbDevice and UsbAccessory are null or if the
|
||||
* query for the matching ApplicationInfo is unsuccessful.
|
||||
*/
|
||||
public UsbDialogHelper(Context context, Intent intent) throws IllegalStateException {
|
||||
mContext = context;
|
||||
mDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
mAccessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
|
||||
mCanBeDefault = intent.getBooleanExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, false);
|
||||
if (mDevice == null && mAccessory == null) {
|
||||
throw new IllegalStateException("Device and accessory are both null.");
|
||||
}
|
||||
if (mDevice != null) {
|
||||
mIsUsbDevice = true;
|
||||
}
|
||||
mResolveInfo = intent.getParcelableExtra(EXTRA_RESOLVE_INFO);
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
if (mResolveInfo != null) {
|
||||
// If a ResolveInfo is provided it will be used to determine the activity to start
|
||||
mUid = mResolveInfo.activityInfo.applicationInfo.uid;
|
||||
mPackageName = mResolveInfo.activityInfo.packageName;
|
||||
mPendingIntent = null;
|
||||
} else {
|
||||
mUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
|
||||
mPackageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
|
||||
mPendingIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
}
|
||||
try {
|
||||
ApplicationInfo aInfo = packageManager.getApplicationInfo(mPackageName, 0);
|
||||
mAppName = aInfo.loadLabel(packageManager);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new IllegalStateException("unable to look up package name", e);
|
||||
}
|
||||
IBinder b = ServiceManager.getService(Context.USB_SERVICE);
|
||||
mUsbService = IUsbManager.Stub.asInterface(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers UsbDisconnectedReceiver to dismiss dialog automatically when device or accessory
|
||||
* gets disconnected
|
||||
* @param activity The activity to finish when device / accessory gets disconnected.
|
||||
*/
|
||||
public void registerUsbDisconnectedReceiver(Activity activity) {
|
||||
if (mIsUsbDevice) {
|
||||
mDisconnectedReceiver = new UsbDisconnectedReceiver(activity, mDevice);
|
||||
} else {
|
||||
mDisconnectedReceiver = new UsbDisconnectedReceiver(activity, mAccessory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the UsbDisconnectedReceiver. To be called when the activity is destroyed.
|
||||
* @param activity The activity registered to finish when device / accessory gets disconnected.
|
||||
*/
|
||||
public void unregisterUsbDisconnectedReceiver(Activity activity) {
|
||||
if (mDisconnectedReceiver != null) {
|
||||
try {
|
||||
activity.unregisterReceiver(mDisconnectedReceiver);
|
||||
} catch (Exception e) {
|
||||
// pass
|
||||
}
|
||||
mDisconnectedReceiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the intent contains a UsbDevice which can capture audio.
|
||||
*/
|
||||
public boolean deviceHasAudioCapture() {
|
||||
return mDevice != null && mDevice.getHasAudioCapture();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the package has RECORD_AUDIO permission specified in its manifest.
|
||||
*/
|
||||
public boolean packageHasAudioRecordingPermission() {
|
||||
return PermissionChecker.checkPermissionForPreflight(mContext, RECORD_AUDIO,
|
||||
PermissionChecker.PID_UNKNOWN, mUid, mPackageName)
|
||||
== android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the intent contains a UsbDevice.
|
||||
*/
|
||||
public boolean isUsbDevice() {
|
||||
return mIsUsbDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the intent contains a UsbAccessory.
|
||||
*/
|
||||
public boolean isUsbAccessory() {
|
||||
return !mIsUsbDevice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants USB permission to the device / accessory to the calling uid.
|
||||
*/
|
||||
public void grantUidAccessPermission() {
|
||||
try {
|
||||
if (mIsUsbDevice) {
|
||||
mUsbService.grantDevicePermission(mDevice, mUid);
|
||||
} else {
|
||||
mUsbService.grantAccessoryPermission(mAccessory, mUid);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "IUsbService connection failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the package as default for the device / accessory.
|
||||
*/
|
||||
public void setDefaultPackage() {
|
||||
final int userId = UserHandle.myUserId();
|
||||
try {
|
||||
if (mIsUsbDevice) {
|
||||
mUsbService.setDevicePackage(mDevice, mPackageName, userId);
|
||||
} else {
|
||||
mUsbService.setAccessoryPackage(mAccessory, mPackageName, userId);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "IUsbService connection failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the default package of the device / accessory.
|
||||
*/
|
||||
public void clearDefaultPackage() {
|
||||
final int userId = UserHandle.myUserId();
|
||||
try {
|
||||
if (mIsUsbDevice) {
|
||||
mUsbService.setDevicePackage(mDevice, null, userId);
|
||||
} else {
|
||||
mUsbService.setAccessoryPackage(mAccessory, null, userId);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "IUsbService connection failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the activity which was selected to handle the device / accessory.
|
||||
*/
|
||||
public void confirmDialogStartActivity() {
|
||||
final int userId = UserHandle.myUserId();
|
||||
Intent intent;
|
||||
|
||||
if (mIsUsbDevice) {
|
||||
intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
|
||||
} else {
|
||||
intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
|
||||
}
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setComponent(
|
||||
new ComponentName(mResolveInfo.activityInfo.packageName,
|
||||
mResolveInfo.activityInfo.name));
|
||||
try {
|
||||
mContext.startActivityAsUser(intent, new UserHandle(userId));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to start activity", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the result of the permission dialog via the provided PendingIntent.
|
||||
*
|
||||
* @param permissionGranted True if the user pressed ok in the permission dialog.
|
||||
*/
|
||||
public void sendPermissionDialogResponse(boolean permissionGranted) {
|
||||
if (!mResponseSent) {
|
||||
// send response via pending intent
|
||||
Intent intent = new Intent();
|
||||
if (mIsUsbDevice) {
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
|
||||
} else {
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
|
||||
}
|
||||
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, permissionGranted);
|
||||
try {
|
||||
mPendingIntent.send(mContext, 0, intent);
|
||||
mResponseSent = true;
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
Log.w(TAG, "PendingIntent was cancelled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A description of the device / accessory
|
||||
*/
|
||||
public String getDeviceDescription() {
|
||||
String desc;
|
||||
if (mIsUsbDevice) {
|
||||
desc = mDevice.getProductName();
|
||||
if (desc == null) {
|
||||
desc = mDevice.getDeviceName();
|
||||
}
|
||||
} else {
|
||||
// UsbAccessory
|
||||
desc = mAccessory.getDescription();
|
||||
if (desc == null) {
|
||||
desc = String.format("%s %s", mAccessory.getManufacturer(), mAccessory.getModel());
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the calling package can set as default handler of the USB device or accessory.
|
||||
* In case of a UsbAccessory this is the case if the calling package has an intent filter for
|
||||
* {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} with a usb-accessory filter matching the
|
||||
* attached accessory. In case of a UsbDevice this is the case if the calling package has an
|
||||
* intent filter for {@link UsbManager#ACTION_USB_DEVICE_ATTACHED} with a usb-device filter
|
||||
* matching the attached device.
|
||||
*
|
||||
* @return True if the package can be default for the USB device.
|
||||
*/
|
||||
public boolean canBeDefault() {
|
||||
return mCanBeDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the app which requested permission or the name of the app which will be
|
||||
* opened if the user allows it to handle the USB device.
|
||||
*/
|
||||
public CharSequence getAppName() {
|
||||
return mAppName;
|
||||
}
|
||||
}
|
||||
@@ -16,186 +16,53 @@
|
||||
|
||||
package com.android.systemui.usb;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.PermissionChecker;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.usb.IUsbManager;
|
||||
import android.hardware.usb.UsbAccessory;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
import com.android.systemui.R;
|
||||
|
||||
public class UsbPermissionActivity extends AlertActivity
|
||||
implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
|
||||
/**
|
||||
* Dialog shown when a package requests access to a USB device or accessory.
|
||||
*/
|
||||
public class UsbPermissionActivity extends UsbDialogActivity {
|
||||
|
||||
private static final String TAG = "UsbPermissionActivity";
|
||||
|
||||
private CheckBox mAlwaysUse;
|
||||
private TextView mClearDefaultHint;
|
||||
private UsbDevice mDevice;
|
||||
private UsbAccessory mAccessory;
|
||||
private PendingIntent mPendingIntent;
|
||||
private String mPackageName;
|
||||
private int mUid;
|
||||
private boolean mPermissionGranted;
|
||||
private UsbDisconnectedReceiver mDisconnectedReceiver;
|
||||
private boolean mPermissionGranted = false;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
getWindow().addPrivateFlags(
|
||||
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
Intent intent = getIntent();
|
||||
mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
|
||||
mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
mUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
|
||||
mPackageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
|
||||
boolean canBeDefault = intent.getBooleanExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, false);
|
||||
|
||||
PackageManager packageManager = getPackageManager();
|
||||
ApplicationInfo aInfo;
|
||||
try {
|
||||
aInfo = packageManager.getApplicationInfo(mPackageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "unable to look up package name", e);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
String appName = aInfo.loadLabel(packageManager).toString();
|
||||
|
||||
final AlertController.AlertParams ap = mAlertParams;
|
||||
ap.mTitle = appName;
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
final int strId;
|
||||
boolean useRecordWarning = false;
|
||||
if (mDevice == null) {
|
||||
// Accessory Case
|
||||
|
||||
ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName,
|
||||
mAccessory.getDescription());
|
||||
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
|
||||
} else {
|
||||
boolean hasRecordPermission =
|
||||
PermissionChecker.checkPermissionForPreflight(
|
||||
this, android.Manifest.permission.RECORD_AUDIO, -1, aInfo.uid,
|
||||
mPackageName)
|
||||
== android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
|
||||
useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
|
||||
|
||||
int strID = useRecordWarning
|
||||
if (mDialogHelper.isUsbDevice()) {
|
||||
useRecordWarning = mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission();
|
||||
strId = useRecordWarning
|
||||
? R.string.usb_device_permission_prompt_warn
|
||||
: R.string.usb_device_permission_prompt;
|
||||
ap.mMessage = getString(strID, appName, mDevice.getProductName());
|
||||
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
|
||||
|
||||
} else {
|
||||
// UsbAccessory case
|
||||
strId = R.string.usb_accessory_permission_prompt;
|
||||
}
|
||||
|
||||
ap.mPositiveButtonText = getString(android.R.string.ok);
|
||||
ap.mNegativeButtonText = getString(android.R.string.cancel);
|
||||
ap.mPositiveButtonListener = this;
|
||||
ap.mNegativeButtonListener = this;
|
||||
|
||||
// Don't show the "always use" checkbox if the USB/Record warning is in effect
|
||||
if (!useRecordWarning && canBeDefault && (mDevice != null || mAccessory != null)) {
|
||||
// add "open when" checkbox
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE);
|
||||
ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
|
||||
mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
|
||||
if (mDevice == null) {
|
||||
mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
|
||||
mAccessory.getDescription()));
|
||||
} else {
|
||||
mAlwaysUse.setText(getString(R.string.always_use_device, appName,
|
||||
mDevice.getProductName()));
|
||||
}
|
||||
mAlwaysUse.setOnCheckedChangeListener(this);
|
||||
|
||||
mClearDefaultHint = (TextView)ap.mView.findViewById(
|
||||
com.android.internal.R.id.clearDefaultHint);
|
||||
mClearDefaultHint.setVisibility(View.GONE);
|
||||
setAlertParams(strId);
|
||||
// Only show the "always use" checkbox if there is no USB/Record warning
|
||||
if (!useRecordWarning && mDialogHelper.canBeDefault()) {
|
||||
addAlwaysUseCheckbox();
|
||||
}
|
||||
|
||||
setupAlert();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
IBinder b = ServiceManager.getService(USB_SERVICE);
|
||||
IUsbManager service = IUsbManager.Stub.asInterface(b);
|
||||
|
||||
// send response via pending intent
|
||||
Intent intent = new Intent();
|
||||
try {
|
||||
if (mDevice != null) {
|
||||
intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
|
||||
if (mPermissionGranted) {
|
||||
service.grantDevicePermission(mDevice, mUid);
|
||||
if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
|
||||
final int userId = UserHandle.getUserId(mUid);
|
||||
service.setDevicePackage(mDevice, mPackageName, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mAccessory != null) {
|
||||
intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
|
||||
if (mPermissionGranted) {
|
||||
service.grantAccessoryPermission(mAccessory, mUid);
|
||||
if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
|
||||
final int userId = UserHandle.getUserId(mUid);
|
||||
service.setAccessoryPackage(mAccessory, mPackageName, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
|
||||
mPendingIntent.send(this, 0, intent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
Log.w(TAG, "PendingIntent was cancelled");
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "IUsbService connection failed", e);
|
||||
protected void onPause() {
|
||||
if (isFinishing()) {
|
||||
mDialogHelper.sendPermissionDialogResponse(mPermissionGranted);
|
||||
}
|
||||
|
||||
if (mDisconnectedReceiver != null) {
|
||||
unregisterReceiver(mDisconnectedReceiver);
|
||||
}
|
||||
super.onDestroy();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == AlertDialog.BUTTON_POSITIVE) {
|
||||
mPermissionGranted = true;
|
||||
@Override
|
||||
void onConfirm() {
|
||||
mDialogHelper.grantUidAccessPermission();
|
||||
if (isAlwaysUseChecked()) {
|
||||
mDialogHelper.setDefaultPackage();
|
||||
}
|
||||
mPermissionGranted = true;
|
||||
finish();
|
||||
}
|
||||
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
if (mClearDefaultHint == null) return;
|
||||
|
||||
if(isChecked) {
|
||||
mClearDefaultHint.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mClearDefaultHint.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.usb;
|
||||
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.hardware.usb.IUsbManager;
|
||||
@@ -109,7 +110,9 @@ public class UsbResolverActivity extends ResolverActivity {
|
||||
mOtherProfileIntent.putParcelableArrayListExtra(EXTRA_RESOLVE_INFOS,
|
||||
rListOtherProfile);
|
||||
} else {
|
||||
mOtherProfileIntent = new Intent(this, UsbConfirmActivity.class);
|
||||
mOtherProfileIntent.setComponent(ComponentName.unflattenFromString(
|
||||
this.getResources().getString(
|
||||
com.android.internal.R.string.config_usbConfirmActivity)));
|
||||
mOtherProfileIntent.putExtra(EXTRA_RESOLVE_INFO, rListOtherProfile.get(0));
|
||||
|
||||
if (mDevice != null) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.systemui.usb.tv;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
/**
|
||||
* Dialog shown to confirm the package to start when a USB device or accessory is attached and there
|
||||
* is only one package that claims to handle this USB device or accessory.
|
||||
*/
|
||||
public class TvUsbConfirmActivity extends TvUsbDialogActivity {
|
||||
private static final String TAG = TvUsbConfirmActivity.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
final int strId;
|
||||
if (mDialogHelper.isUsbDevice()) {
|
||||
boolean useRecordWarning = mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission();
|
||||
strId = useRecordWarning
|
||||
? R.string.usb_device_confirm_prompt_warn
|
||||
: R.string.usb_device_confirm_prompt;
|
||||
} else {
|
||||
// UsbAccessory case
|
||||
strId = R.string.usb_accessory_confirm_prompt;
|
||||
}
|
||||
CharSequence text = getString(strId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription());
|
||||
initUI(mDialogHelper.getAppName(), text);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onConfirm() {
|
||||
mDialogHelper.grantUidAccessPermission();
|
||||
mDialogHelper.confirmDialogStartActivity();
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.systemui.usb.tv;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.tv.TvBottomSheetActivity;
|
||||
import com.android.systemui.usb.UsbDialogHelper;
|
||||
|
||||
abstract class TvUsbDialogActivity extends TvBottomSheetActivity implements View.OnClickListener {
|
||||
private static final String TAG = TvUsbDialogActivity.class.getSimpleName();
|
||||
UsbDialogHelper mDialogHelper;
|
||||
|
||||
@Override
|
||||
public final void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
getWindow().addPrivateFlags(
|
||||
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
try {
|
||||
mDialogHelper = new UsbDialogHelper(getApplicationContext(), getIntent());
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "unable to initialize", e);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mDialogHelper.registerUsbDisconnectedReceiver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (mDialogHelper != null) {
|
||||
mDialogHelper.unregisterUsbDisconnectedReceiver(this);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v.getId() == R.id.bottom_sheet_positive_button) {
|
||||
onConfirm();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the ok button is clicked.
|
||||
*/
|
||||
abstract void onConfirm();
|
||||
|
||||
void initUI(CharSequence title, CharSequence text) {
|
||||
TextView titleTextView = findViewById(R.id.bottom_sheet_title);
|
||||
TextView contentTextView = findViewById(R.id.bottom_sheet_body);
|
||||
ImageView icon = findViewById(R.id.bottom_sheet_icon);
|
||||
ImageView secondIcon = findViewById(R.id.bottom_sheet_second_icon);
|
||||
Button okButton = findViewById(R.id.bottom_sheet_positive_button);
|
||||
Button cancelButton = findViewById(R.id.bottom_sheet_negative_button);
|
||||
|
||||
titleTextView.setText(title);
|
||||
contentTextView.setText(text);
|
||||
icon.setImageResource(com.android.internal.R.drawable.ic_usb_48dp);
|
||||
secondIcon.setVisibility(View.GONE);
|
||||
okButton.setText(android.R.string.ok);
|
||||
okButton.setOnClickListener(this);
|
||||
|
||||
cancelButton.setText(android.R.string.cancel);
|
||||
cancelButton.setOnClickListener(this);
|
||||
cancelButton.requestFocus();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.systemui.usb.tv;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
/**
|
||||
* Dialog shown when a package requests access to a USB device or accessory on TVs.
|
||||
*/
|
||||
public class TvUsbPermissionActivity extends TvUsbDialogActivity {
|
||||
private static final String TAG = TvUsbPermissionActivity.class.getSimpleName();
|
||||
|
||||
private boolean mPermissionGranted = false;
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
final int strId;
|
||||
if (mDialogHelper.isUsbDevice()) {
|
||||
boolean useRecordWarning = mDialogHelper.deviceHasAudioCapture()
|
||||
&& !mDialogHelper.packageHasAudioRecordingPermission();
|
||||
strId = useRecordWarning
|
||||
? R.string.usb_device_permission_prompt_warn
|
||||
: R.string.usb_device_permission_prompt;
|
||||
} else {
|
||||
// UsbAccessory case
|
||||
strId = R.string.usb_accessory_permission_prompt;
|
||||
}
|
||||
CharSequence text = getString(strId, mDialogHelper.getAppName(),
|
||||
mDialogHelper.getDeviceDescription());
|
||||
initUI(mDialogHelper.getAppName(), text);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (isFinishing()) {
|
||||
mDialogHelper.sendPermissionDialogResponse(mPermissionGranted);
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
void onConfirm() {
|
||||
mDialogHelper.grantUidAccessPermission();
|
||||
mPermissionGranted = true;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user