Loading packages/CompanionDeviceManager/AndroidManifest.xml +2 −2 Original line number Diff line number Diff line Loading @@ -41,13 +41,13 @@ android:supportsRtl="true"> <service android:name=".DeviceDiscoveryService" android:name=".CompanionDeviceDiscoveryService" android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE" android:exported="true"> </service> <activity android:name=".DeviceChooserActivity" android:name=".CompanionDeviceActivity" android:theme="@style/ChooserActivity" android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE" android:exported="true"> Loading packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java→packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +118 −18 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.companion.AssociationRequest; Loading @@ -31,41 +32,52 @@ import android.companion.CompanionDeviceManager; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.Html; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.widget.AdapterView; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.android.companiondevicemanager.DeviceDiscoveryService.DeviceFilterPair; import com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DeviceFilterPair; import com.android.internal.util.Preconditions; public class DeviceChooserActivity extends Activity { public class CompanionDeviceActivity extends Activity { private static final boolean DEBUG = false; private static final String LOG_TAG = "DeviceChooserActivity"; private static final String LOG_TAG = CompanionDeviceActivity.class.getSimpleName(); static CompanionDeviceActivity sInstance; View mLoadingIndicator = null; ListView mDeviceListView; private View mPairButton; private View mCancelButton; DevicesAdapter mDevicesAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (DEBUG) Log.i(LOG_TAG, "Started with intent " + getIntent()); Log.i(LOG_TAG, "Starting UI for " + getService().mRequest); if (getService().mDevicesFound.isEmpty()) { Log.e(LOG_TAG, "About to show UI, but no devices to show"); } getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); sInstance = this; String deviceProfile = getRequest().getDeviceProfile(); String profilePrivacyDisclaimer = emptyIfNull(getRequest() Loading Loading @@ -96,17 +108,14 @@ public class DeviceChooserActivity extends Activity { profileName, getCallingAppName()), 0)); mDeviceListView = findViewById(R.id.device_list); final DeviceDiscoveryService.DevicesAdapter adapter = getService().mDevicesAdapter; mDeviceListView.setAdapter(adapter); mDeviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) { mDevicesAdapter = new DevicesAdapter(); mDeviceListView.setAdapter(mDevicesAdapter); mDeviceListView.setOnItemClickListener((adapterView, view, pos, l) -> { getService().mSelectedDevice = (DeviceFilterPair) adapterView.getItemAtPosition(pos); adapter.notifyDataSetChanged(); } mDevicesAdapter.notifyDataSetChanged(); }); adapter.registerDataSetObserver(new DataSetObserver() { mDevicesAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { onSelectionUpdate(); Loading @@ -133,6 +142,12 @@ public class DeviceChooserActivity extends Activity { mCancelButton.setOnClickListener(v -> cancel()); } static void notifyDevicesChanged() { if (sInstance != null && !sInstance.isFinishing()) { sInstance.mDevicesAdapter.notifyDataSetChanged(); } } private AssociationRequest getRequest() { return getService().mRequest; } Loading @@ -156,6 +171,7 @@ public class DeviceChooserActivity extends Activity { } private void cancel() { Log.i(LOG_TAG, "cancel()"); getService().onCancel(); setResult(RESULT_CANCELED); finish(); Loading @@ -170,6 +186,14 @@ public class DeviceChooserActivity extends Activity { } } @Override protected void onDestroy() { super.onDestroy(); if (sInstance == this) { sInstance = null; } } private CharSequence getCallingAppName() { try { final PackageManager packageManager = getPackageManager(); Loading Loading @@ -217,15 +241,91 @@ public class DeviceChooserActivity extends Activity { } } private DeviceDiscoveryService getService() { return DeviceDiscoveryService.sInstance; private CompanionDeviceDiscoveryService getService() { return CompanionDeviceDiscoveryService.sInstance; } protected void onDeviceConfirmed(DeviceFilterPair selectedDevice) { Log.i(LOG_TAG, "onDeviceConfirmed(selectedDevice = " + selectedDevice + ")"); getService().onDeviceSelected( getCallingPackage(), getDeviceMacAddress(selectedDevice.device)); setResult(RESULT_OK, new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice.device)); finish(); } class DevicesAdapter extends BaseAdapter { private final Drawable mBluetoothIcon = icon(android.R.drawable.stat_sys_data_bluetooth); private final Drawable mWifiIcon = icon(com.android.internal.R.drawable.ic_wifi_signal_3); private SparseArray<Integer> mColors = new SparseArray(); private Drawable icon(int drawableRes) { Drawable icon = getResources().getDrawable(drawableRes, null); icon.setTint(Color.DKGRAY); return icon; } @Override public View getView( int position, @Nullable View convertView, @NonNull ViewGroup parent) { TextView view = convertView instanceof TextView ? (TextView) convertView : newView(); bind(view, getItem(position)); return view; } private void bind(TextView textView, DeviceFilterPair device) { textView.setText(device.getDisplayName()); textView.setBackgroundColor( device.equals(getService().mSelectedDevice) ? getColor(android.R.attr.colorControlHighlight) : Color.TRANSPARENT); textView.setCompoundDrawablesWithIntrinsicBounds( device.device instanceof android.net.wifi.ScanResult ? mWifiIcon : mBluetoothIcon, null, null, null); textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground)); } private TextView newView() { final TextView textView = new TextView(CompanionDeviceActivity.this); textView.setTextColor(getColor(android.R.attr.colorForeground)); final int padding = CompanionDeviceActivity.getPadding(getResources()); textView.setPadding(padding, padding, padding, padding); textView.setCompoundDrawablePadding(padding); return textView; } private int getColor(int colorAttr) { if (mColors.contains(colorAttr)) { return mColors.get(colorAttr); } TypedValue typedValue = new TypedValue(); TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr }); int result = a.getColor(0, 0); a.recycle(); mColors.put(colorAttr, result); return result; } @Override public int getCount() { return getService().mDevicesFound.size(); } @Override public DeviceFilterPair getItem(int position) { return getService().mDevicesFound.get(position); } @Override public long getItemId(int position) { return position; } } } packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java→packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java +17 −100 Original line number Diff line number Diff line Loading @@ -50,9 +50,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.wifi.WifiManager; import android.os.Handler; import android.os.IBinder; Loading @@ -60,12 +57,6 @@ import android.os.Parcelable; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.ArrayUtils; Loading @@ -76,14 +67,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; public class DeviceDiscoveryService extends Service { public class CompanionDeviceDiscoveryService extends Service { private static final boolean DEBUG = false; private static final String LOG_TAG = "DeviceDiscoveryService"; private static final String LOG_TAG = CompanionDeviceDiscoveryService.class.getSimpleName(); private static final long SCAN_TIMEOUT = 20000; static DeviceDiscoveryService sInstance; static CompanionDeviceDiscoveryService sInstance; private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; Loading @@ -102,12 +93,12 @@ public class DeviceDiscoveryService extends Service { AssociationRequest mRequest; List<DeviceFilterPair> mDevicesFound; DeviceFilterPair mSelectedDevice; DevicesAdapter mDevicesAdapter; IFindDeviceCallback mFindCallback; AndroidFuture<Association> mServiceCallback; boolean mIsScanning = false; @Nullable DeviceChooserActivity mActivity = null; @Nullable CompanionDeviceActivity mActivity = null; private final ICompanionDeviceDiscoveryService mBinder = new ICompanionDeviceDiscoveryService.Stub() { Loading @@ -125,7 +116,8 @@ public class DeviceDiscoveryService extends Service { mFindCallback = findCallback; mServiceCallback = serviceCallback; Handler.getMain().sendMessage(obtainMessage( DeviceDiscoveryService::startDiscovery, DeviceDiscoveryService.this, request)); CompanionDeviceDiscoveryService::startDiscovery, CompanionDeviceDiscoveryService.this, request)); } }; Loading @@ -151,7 +143,6 @@ public class DeviceDiscoveryService extends Service { mWifiManager = getSystemService(WifiManager.class); mDevicesFound = new ArrayList<>(); mDevicesAdapter = new DevicesAdapter(); sInstance = this; } Loading @@ -165,7 +156,8 @@ public class DeviceDiscoveryService extends Service { mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class); mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class); mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLeDeviceFilter.class); mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter); mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter); reset(); } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request); Loading Loading @@ -223,7 +215,7 @@ public class DeviceDiscoveryService extends Service { } mIsScanning = true; Handler.getMain().sendMessageDelayed( obtainMessage(DeviceDiscoveryService::stopScan, this), obtainMessage(CompanionDeviceDiscoveryService::stopScan, this), SCAN_TIMEOUT); } Loading @@ -237,7 +229,7 @@ public class DeviceDiscoveryService extends Service { stopScan(); mDevicesFound.clear(); mSelectedDevice = null; mDevicesAdapter.notifyDataSetChanged(); CompanionDeviceActivity.notifyDevicesChanged(); } @Override Loading @@ -252,7 +244,7 @@ public class DeviceDiscoveryService extends Service { if (!mIsScanning) return; mIsScanning = false; DeviceChooserActivity activity = mActivity; CompanionDeviceActivity activity = mActivity; if (activity != null) { if (activity.mDeviceListView != null) { activity.mDeviceListView.removeFooterView(activity.mLoadingIndicator); Loading @@ -276,7 +268,7 @@ public class DeviceDiscoveryService extends Service { if (device == null) return; Handler.getMain().sendMessage(obtainMessage( DeviceDiscoveryService::onDeviceFoundMainThread, this, device)); CompanionDeviceDiscoveryService::onDeviceFoundMainThread, this, device)); } @MainThread Loading @@ -292,7 +284,7 @@ public class DeviceDiscoveryService extends Service { onReadyToShowUI(); } mDevicesFound.add(device); mDevicesAdapter.notifyDataSetChanged(); CompanionDeviceActivity.notifyDevicesChanged(); } //TODO also, on timeout -> call onFailure Loading @@ -300,7 +292,7 @@ public class DeviceDiscoveryService extends Service { try { mFindCallback.onSuccess(PendingIntent.getActivity( this, 0, new Intent(this, DeviceChooserActivity.class), new Intent(this, CompanionDeviceActivity.class), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE)); } catch (RemoteException e) { Loading @@ -311,13 +303,13 @@ public class DeviceDiscoveryService extends Service { private void onDeviceLost(@Nullable DeviceFilterPair device) { Log.i(LOG_TAG, "Lost device " + device.getDisplayName()); Handler.getMain().sendMessage(obtainMessage( DeviceDiscoveryService::onDeviceLostMainThread, this, device)); CompanionDeviceDiscoveryService::onDeviceLostMainThread, this, device)); } @MainThread void onDeviceLostMainThread(@Nullable DeviceFilterPair device) { mDevicesFound.remove(device); mDevicesAdapter.notifyDataSetChanged(); CompanionDeviceActivity.notifyDevicesChanged(); } void onDeviceSelected(String callingPackage, String deviceAddress) { Loading @@ -331,81 +323,6 @@ public class DeviceDiscoveryService extends Service { mServiceCallback.cancel(true); } class DevicesAdapter extends BaseAdapter { private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth); private Drawable WIFI_ICON = icon(com.android.internal.R.drawable.ic_wifi_signal_3); private SparseArray<Integer> mColors = new SparseArray(); private Drawable icon(int drawableRes) { Drawable icon = getResources().getDrawable(drawableRes, null); icon.setTint(Color.DKGRAY); return icon; } @Override public View getView( int position, @Nullable View convertView, @NonNull ViewGroup parent) { TextView view = convertView instanceof TextView ? (TextView) convertView : newView(); bind(view, getItem(position)); return view; } private void bind(TextView textView, DeviceFilterPair device) { textView.setText(device.getDisplayName()); textView.setBackgroundColor( device.equals(mSelectedDevice) ? getColor(android.R.attr.colorControlHighlight) : Color.TRANSPARENT); textView.setCompoundDrawablesWithIntrinsicBounds( device.device instanceof android.net.wifi.ScanResult ? WIFI_ICON : BLUETOOTH_ICON, null, null, null); textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground)); } private TextView newView() { final TextView textView = new TextView(DeviceDiscoveryService.this); textView.setTextColor(getColor(android.R.attr.colorForeground)); final int padding = DeviceChooserActivity.getPadding(getResources()); textView.setPadding(padding, padding, padding, padding); textView.setCompoundDrawablePadding(padding); return textView; } private int getColor(int colorAttr) { if (mColors.contains(colorAttr)) { return mColors.get(colorAttr); } TypedValue typedValue = new TypedValue(); TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr }); int result = a.getColor(0, 0); a.recycle(); mColors.put(colorAttr, result); return result; } @Override public int getCount() { return mDevicesFound.size(); } @Override public DeviceFilterPair getItem(int position) { return mDevicesFound.get(position); } @Override public long getItemId(int position) { return position; } } /** * A pair of device and a filter that matched this device if any. * Loading services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +1 −6 Original line number Diff line number Diff line Loading @@ -142,18 +142,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; //TODO onStop schedule unbind in 5 seconds //TODO make sure APIs are only callable from currently focused app //TODO schedule stopScan on activity destroy(except if configuration change) //TODO on associate called again after configuration change -> replace old callback with new //TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example) /** @hide */ @SuppressLint("LongLogTag") public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient { private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative( CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, ".DeviceDiscoveryService"); ".CompanionDeviceDiscoveryService"); private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000; private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000; Loading Loading
packages/CompanionDeviceManager/AndroidManifest.xml +2 −2 Original line number Diff line number Diff line Loading @@ -41,13 +41,13 @@ android:supportsRtl="true"> <service android:name=".DeviceDiscoveryService" android:name=".CompanionDeviceDiscoveryService" android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE" android:exported="true"> </service> <activity android:name=".DeviceChooserActivity" android:name=".CompanionDeviceActivity" android:theme="@style/ChooserActivity" android:permission="android.permission.BIND_COMPANION_DEVICE_MANAGER_SERVICE" android:exported="true"> Loading
packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java→packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java +118 −18 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.companion.AssociationRequest; Loading @@ -31,41 +32,52 @@ import android.companion.CompanionDeviceManager; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.Html; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.widget.AdapterView; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import com.android.companiondevicemanager.DeviceDiscoveryService.DeviceFilterPair; import com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DeviceFilterPair; import com.android.internal.util.Preconditions; public class DeviceChooserActivity extends Activity { public class CompanionDeviceActivity extends Activity { private static final boolean DEBUG = false; private static final String LOG_TAG = "DeviceChooserActivity"; private static final String LOG_TAG = CompanionDeviceActivity.class.getSimpleName(); static CompanionDeviceActivity sInstance; View mLoadingIndicator = null; ListView mDeviceListView; private View mPairButton; private View mCancelButton; DevicesAdapter mDevicesAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (DEBUG) Log.i(LOG_TAG, "Started with intent " + getIntent()); Log.i(LOG_TAG, "Starting UI for " + getService().mRequest); if (getService().mDevicesFound.isEmpty()) { Log.e(LOG_TAG, "About to show UI, but no devices to show"); } getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); sInstance = this; String deviceProfile = getRequest().getDeviceProfile(); String profilePrivacyDisclaimer = emptyIfNull(getRequest() Loading Loading @@ -96,17 +108,14 @@ public class DeviceChooserActivity extends Activity { profileName, getCallingAppName()), 0)); mDeviceListView = findViewById(R.id.device_list); final DeviceDiscoveryService.DevicesAdapter adapter = getService().mDevicesAdapter; mDeviceListView.setAdapter(adapter); mDeviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) { mDevicesAdapter = new DevicesAdapter(); mDeviceListView.setAdapter(mDevicesAdapter); mDeviceListView.setOnItemClickListener((adapterView, view, pos, l) -> { getService().mSelectedDevice = (DeviceFilterPair) adapterView.getItemAtPosition(pos); adapter.notifyDataSetChanged(); } mDevicesAdapter.notifyDataSetChanged(); }); adapter.registerDataSetObserver(new DataSetObserver() { mDevicesAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { onSelectionUpdate(); Loading @@ -133,6 +142,12 @@ public class DeviceChooserActivity extends Activity { mCancelButton.setOnClickListener(v -> cancel()); } static void notifyDevicesChanged() { if (sInstance != null && !sInstance.isFinishing()) { sInstance.mDevicesAdapter.notifyDataSetChanged(); } } private AssociationRequest getRequest() { return getService().mRequest; } Loading @@ -156,6 +171,7 @@ public class DeviceChooserActivity extends Activity { } private void cancel() { Log.i(LOG_TAG, "cancel()"); getService().onCancel(); setResult(RESULT_CANCELED); finish(); Loading @@ -170,6 +186,14 @@ public class DeviceChooserActivity extends Activity { } } @Override protected void onDestroy() { super.onDestroy(); if (sInstance == this) { sInstance = null; } } private CharSequence getCallingAppName() { try { final PackageManager packageManager = getPackageManager(); Loading Loading @@ -217,15 +241,91 @@ public class DeviceChooserActivity extends Activity { } } private DeviceDiscoveryService getService() { return DeviceDiscoveryService.sInstance; private CompanionDeviceDiscoveryService getService() { return CompanionDeviceDiscoveryService.sInstance; } protected void onDeviceConfirmed(DeviceFilterPair selectedDevice) { Log.i(LOG_TAG, "onDeviceConfirmed(selectedDevice = " + selectedDevice + ")"); getService().onDeviceSelected( getCallingPackage(), getDeviceMacAddress(selectedDevice.device)); setResult(RESULT_OK, new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice.device)); finish(); } class DevicesAdapter extends BaseAdapter { private final Drawable mBluetoothIcon = icon(android.R.drawable.stat_sys_data_bluetooth); private final Drawable mWifiIcon = icon(com.android.internal.R.drawable.ic_wifi_signal_3); private SparseArray<Integer> mColors = new SparseArray(); private Drawable icon(int drawableRes) { Drawable icon = getResources().getDrawable(drawableRes, null); icon.setTint(Color.DKGRAY); return icon; } @Override public View getView( int position, @Nullable View convertView, @NonNull ViewGroup parent) { TextView view = convertView instanceof TextView ? (TextView) convertView : newView(); bind(view, getItem(position)); return view; } private void bind(TextView textView, DeviceFilterPair device) { textView.setText(device.getDisplayName()); textView.setBackgroundColor( device.equals(getService().mSelectedDevice) ? getColor(android.R.attr.colorControlHighlight) : Color.TRANSPARENT); textView.setCompoundDrawablesWithIntrinsicBounds( device.device instanceof android.net.wifi.ScanResult ? mWifiIcon : mBluetoothIcon, null, null, null); textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground)); } private TextView newView() { final TextView textView = new TextView(CompanionDeviceActivity.this); textView.setTextColor(getColor(android.R.attr.colorForeground)); final int padding = CompanionDeviceActivity.getPadding(getResources()); textView.setPadding(padding, padding, padding, padding); textView.setCompoundDrawablePadding(padding); return textView; } private int getColor(int colorAttr) { if (mColors.contains(colorAttr)) { return mColors.get(colorAttr); } TypedValue typedValue = new TypedValue(); TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr }); int result = a.getColor(0, 0); a.recycle(); mColors.put(colorAttr, result); return result; } @Override public int getCount() { return getService().mDevicesFound.size(); } @Override public DeviceFilterPair getItem(int position) { return getService().mDevicesFound.get(position); } @Override public long getItemId(int position) { return position; } } }
packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java→packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java +17 −100 Original line number Diff line number Diff line Loading @@ -50,9 +50,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.wifi.WifiManager; import android.os.Handler; import android.os.IBinder; Loading @@ -60,12 +57,6 @@ import android.os.Parcelable; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.ArrayUtils; Loading @@ -76,14 +67,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; public class DeviceDiscoveryService extends Service { public class CompanionDeviceDiscoveryService extends Service { private static final boolean DEBUG = false; private static final String LOG_TAG = "DeviceDiscoveryService"; private static final String LOG_TAG = CompanionDeviceDiscoveryService.class.getSimpleName(); private static final long SCAN_TIMEOUT = 20000; static DeviceDiscoveryService sInstance; static CompanionDeviceDiscoveryService sInstance; private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; Loading @@ -102,12 +93,12 @@ public class DeviceDiscoveryService extends Service { AssociationRequest mRequest; List<DeviceFilterPair> mDevicesFound; DeviceFilterPair mSelectedDevice; DevicesAdapter mDevicesAdapter; IFindDeviceCallback mFindCallback; AndroidFuture<Association> mServiceCallback; boolean mIsScanning = false; @Nullable DeviceChooserActivity mActivity = null; @Nullable CompanionDeviceActivity mActivity = null; private final ICompanionDeviceDiscoveryService mBinder = new ICompanionDeviceDiscoveryService.Stub() { Loading @@ -125,7 +116,8 @@ public class DeviceDiscoveryService extends Service { mFindCallback = findCallback; mServiceCallback = serviceCallback; Handler.getMain().sendMessage(obtainMessage( DeviceDiscoveryService::startDiscovery, DeviceDiscoveryService.this, request)); CompanionDeviceDiscoveryService::startDiscovery, CompanionDeviceDiscoveryService.this, request)); } }; Loading @@ -151,7 +143,6 @@ public class DeviceDiscoveryService extends Service { mWifiManager = getSystemService(WifiManager.class); mDevicesFound = new ArrayList<>(); mDevicesAdapter = new DevicesAdapter(); sInstance = this; } Loading @@ -165,7 +156,8 @@ public class DeviceDiscoveryService extends Service { mWifiFilters = CollectionUtils.filter(mFilters, WifiDeviceFilter.class); mBluetoothFilters = CollectionUtils.filter(mFilters, BluetoothDeviceFilter.class); mBLEFilters = CollectionUtils.filter(mFilters, BluetoothLeDeviceFilter.class); mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter); mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLeDeviceFilter::getScanFilter); reset(); } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request); Loading Loading @@ -223,7 +215,7 @@ public class DeviceDiscoveryService extends Service { } mIsScanning = true; Handler.getMain().sendMessageDelayed( obtainMessage(DeviceDiscoveryService::stopScan, this), obtainMessage(CompanionDeviceDiscoveryService::stopScan, this), SCAN_TIMEOUT); } Loading @@ -237,7 +229,7 @@ public class DeviceDiscoveryService extends Service { stopScan(); mDevicesFound.clear(); mSelectedDevice = null; mDevicesAdapter.notifyDataSetChanged(); CompanionDeviceActivity.notifyDevicesChanged(); } @Override Loading @@ -252,7 +244,7 @@ public class DeviceDiscoveryService extends Service { if (!mIsScanning) return; mIsScanning = false; DeviceChooserActivity activity = mActivity; CompanionDeviceActivity activity = mActivity; if (activity != null) { if (activity.mDeviceListView != null) { activity.mDeviceListView.removeFooterView(activity.mLoadingIndicator); Loading @@ -276,7 +268,7 @@ public class DeviceDiscoveryService extends Service { if (device == null) return; Handler.getMain().sendMessage(obtainMessage( DeviceDiscoveryService::onDeviceFoundMainThread, this, device)); CompanionDeviceDiscoveryService::onDeviceFoundMainThread, this, device)); } @MainThread Loading @@ -292,7 +284,7 @@ public class DeviceDiscoveryService extends Service { onReadyToShowUI(); } mDevicesFound.add(device); mDevicesAdapter.notifyDataSetChanged(); CompanionDeviceActivity.notifyDevicesChanged(); } //TODO also, on timeout -> call onFailure Loading @@ -300,7 +292,7 @@ public class DeviceDiscoveryService extends Service { try { mFindCallback.onSuccess(PendingIntent.getActivity( this, 0, new Intent(this, DeviceChooserActivity.class), new Intent(this, CompanionDeviceActivity.class), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE)); } catch (RemoteException e) { Loading @@ -311,13 +303,13 @@ public class DeviceDiscoveryService extends Service { private void onDeviceLost(@Nullable DeviceFilterPair device) { Log.i(LOG_TAG, "Lost device " + device.getDisplayName()); Handler.getMain().sendMessage(obtainMessage( DeviceDiscoveryService::onDeviceLostMainThread, this, device)); CompanionDeviceDiscoveryService::onDeviceLostMainThread, this, device)); } @MainThread void onDeviceLostMainThread(@Nullable DeviceFilterPair device) { mDevicesFound.remove(device); mDevicesAdapter.notifyDataSetChanged(); CompanionDeviceActivity.notifyDevicesChanged(); } void onDeviceSelected(String callingPackage, String deviceAddress) { Loading @@ -331,81 +323,6 @@ public class DeviceDiscoveryService extends Service { mServiceCallback.cancel(true); } class DevicesAdapter extends BaseAdapter { private Drawable BLUETOOTH_ICON = icon(android.R.drawable.stat_sys_data_bluetooth); private Drawable WIFI_ICON = icon(com.android.internal.R.drawable.ic_wifi_signal_3); private SparseArray<Integer> mColors = new SparseArray(); private Drawable icon(int drawableRes) { Drawable icon = getResources().getDrawable(drawableRes, null); icon.setTint(Color.DKGRAY); return icon; } @Override public View getView( int position, @Nullable View convertView, @NonNull ViewGroup parent) { TextView view = convertView instanceof TextView ? (TextView) convertView : newView(); bind(view, getItem(position)); return view; } private void bind(TextView textView, DeviceFilterPair device) { textView.setText(device.getDisplayName()); textView.setBackgroundColor( device.equals(mSelectedDevice) ? getColor(android.R.attr.colorControlHighlight) : Color.TRANSPARENT); textView.setCompoundDrawablesWithIntrinsicBounds( device.device instanceof android.net.wifi.ScanResult ? WIFI_ICON : BLUETOOTH_ICON, null, null, null); textView.getCompoundDrawables()[0].setTint(getColor(android.R.attr.colorForeground)); } private TextView newView() { final TextView textView = new TextView(DeviceDiscoveryService.this); textView.setTextColor(getColor(android.R.attr.colorForeground)); final int padding = DeviceChooserActivity.getPadding(getResources()); textView.setPadding(padding, padding, padding, padding); textView.setCompoundDrawablePadding(padding); return textView; } private int getColor(int colorAttr) { if (mColors.contains(colorAttr)) { return mColors.get(colorAttr); } TypedValue typedValue = new TypedValue(); TypedArray a = obtainStyledAttributes(typedValue.data, new int[] { colorAttr }); int result = a.getColor(0, 0); a.recycle(); mColors.put(colorAttr, result); return result; } @Override public int getCount() { return mDevicesFound.size(); } @Override public DeviceFilterPair getItem(int position) { return mDevicesFound.get(position); } @Override public long getItemId(int position) { return position; } } /** * A pair of device and a filter that matched this device if any. * Loading
services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +1 −6 Original line number Diff line number Diff line Loading @@ -142,18 +142,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; //TODO onStop schedule unbind in 5 seconds //TODO make sure APIs are only callable from currently focused app //TODO schedule stopScan on activity destroy(except if configuration change) //TODO on associate called again after configuration change -> replace old callback with new //TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example) /** @hide */ @SuppressLint("LongLogTag") public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient { private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative( CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, ".DeviceDiscoveryService"); ".CompanionDeviceDiscoveryService"); private static final long DEVICE_DISAPPEARED_TIMEOUT_MS = 10 * 1000; private static final long DEVICE_DISAPPEARED_UNBIND_TIMEOUT_MS = 10 * 60 * 1000; Loading