Introduce LiveData for CDM Activity and Discovery
Test: atest CtsCompanionDeviceManagerCoreTestCases
atest CtsCompanionDeviceManagerUiAutomationTestCases
atest CtsOsTestCases:CompanionDeviceManagerTest
Bug: 211722613
Change-Id: Icb84fe42cf02b1e0db4546fefee70afdd97ee7f3
diff --git a/packages/CompanionDeviceManager/Android.bp b/packages/CompanionDeviceManager/Android.bp
index 4a52650..0e60873 100644
--- a/packages/CompanionDeviceManager/Android.bp
+++ b/packages/CompanionDeviceManager/Android.bp
@@ -36,5 +36,11 @@
defaults: ["platform_app_defaults"],
srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.lifecycle_lifecycle-livedata",
+ "androidx.lifecycle_lifecycle-extensions",
+ "androidx.appcompat_appcompat",
+ ],
+
platform_apis: true,
}
diff --git a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
index a017f41..ef7052d 100644
--- a/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
+++ b/packages/CompanionDeviceManager/res/drawable/dialog_background.xml
@@ -16,7 +16,7 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
- <corners android:radius="?android:attr/dialogCornerRadius" />
+ <corners android:radius="@*android:dimen/config_dialogCornerRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>
</inset>
diff --git a/packages/CompanionDeviceManager/res/values/themes.xml b/packages/CompanionDeviceManager/res/values/themes.xml
index 66729347..8559ef6 100644
--- a/packages/CompanionDeviceManager/res/values/themes.xml
+++ b/packages/CompanionDeviceManager/res/values/themes.xml
@@ -17,7 +17,9 @@
<resources>
<style name="ChooserActivity"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
+ parent="@style/Theme.AppCompat.Light.Dialog">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
<item name="*android:windowFixedHeightMajor">100%</item>
<item name="*android:windowFixedHeightMinor">100%</item>
<item name="android:windowBackground">@android:color/transparent</item>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 27c14af..9d3fc7f 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -22,8 +22,8 @@
import static android.companion.AssociationRequest.DEVICE_PROFILE_WATCH;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.SCAN_RESULTS_OBSERVABLE;
-import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.TIMEOUT_OBSERVABLE;
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState;
+import static com.android.companiondevicemanager.CompanionDeviceDiscoveryService.DiscoveryState.FINISHED_TIMEOUT;
import static com.android.companiondevicemanager.Utils.getApplicationLabel;
import static com.android.companiondevicemanager.Utils.getHtmlFromResources;
import static com.android.companiondevicemanager.Utils.prepareResultReceiverForIpc;
@@ -32,7 +32,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.Activity;
import android.companion.AssociationInfo;
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
@@ -50,7 +49,13 @@
import android.widget.ListView;
import android.widget.TextView;
-public class CompanionDeviceActivity extends Activity {
+import androidx.appcompat.app.AppCompatActivity;
+
+/**
+ * A CompanionDevice activity response for showing the available
+ * nearby devices to be associated with.
+ */
+public class CompanionDeviceActivity extends AppCompatActivity {
private static final boolean DEBUG = false;
private static final String TAG = CompanionDeviceActivity.class.getSimpleName();
@@ -126,7 +131,9 @@
// Start discovery services if needed.
if (!mRequest.isSelfManaged()) {
CompanionDeviceDiscoveryService.startForRequest(this, mRequest);
- TIMEOUT_OBSERVABLE.addObserver((o, arg) -> cancel(true));
+ // TODO(b/217749191): Create the ViewModel for the LiveData
+ CompanionDeviceDiscoveryService.getDiscoveryState().observe(
+ /* LifeCycleOwner */ this, this::onDiscoveryStateChanged);
}
// Init UI.
initUI();
@@ -158,10 +165,6 @@
if (!isDone()) {
cancel(false); // will finish()
}
-
- TIMEOUT_OBSERVABLE.deleteObservers();
- // mAdapter may also be observing - need to remove it.
- SCAN_RESULTS_OBSERVABLE.deleteObservers();
}
@Override
@@ -210,6 +213,13 @@
}
}
+ private void onDiscoveryStateChanged(DiscoveryState newState) {
+ if (newState == FINISHED_TIMEOUT
+ && CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) {
+ cancel(true);
+ }
+ }
+
private void onUserSelectedDevice(@NonNull DeviceFilterPair<?> selectedDevice) {
if (mSelectedDevice != null) {
if (DEBUG) Log.w(TAG, "Already selected.");
@@ -380,9 +390,12 @@
mSummary.setText(summary);
mAdapter = new DeviceListAdapter(this);
- SCAN_RESULTS_OBSERVABLE.addObserver(mAdapter);
+
// TODO: hide the list and show a spinner until a first device matching device is found.
mListView.setAdapter(mAdapter);
+ CompanionDeviceDiscoveryService.getScanResult().observe(
+ /* lifecycleOwner */ this,
+ /* observer */ mAdapter);
// "Remove" consent button: users would need to click on the list item.
mButtonAllow.setVisibility(View.GONE);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index f859130..5d48708 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -56,13 +56,18 @@
import android.text.TextUtils;
import android.util.Log;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.Observable;
+/**
+ * A CompanionDevice service response for scanning nearby devices
+ */
public class CompanionDeviceDiscoveryService extends Service {
private static final boolean DEBUG = false;
private static final String TAG = CompanionDeviceDiscoveryService.class.getSimpleName();
@@ -78,12 +83,10 @@
"com.android.companiondevicemanager.action.ACTION_STOP_DISCOVERY";
private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
-
- // TODO: replace with LiveData-s?
- static final Observable TIMEOUT_OBSERVABLE = new MyObservable();
- static final Observable SCAN_RESULTS_OBSERVABLE = new MyObservable();
-
- private static CompanionDeviceDiscoveryService sInstance;
+ private static MutableLiveData<List<DeviceFilterPair<?>>> sScanResultsLiveData =
+ new MutableLiveData<>(Collections.emptyList());
+ private static MutableLiveData<DiscoveryState> sStateLiveData =
+ new MutableLiveData<>(DiscoveryState.NOT_STARTED);
private BluetoothManager mBtManager;
private BluetoothAdapter mBtAdapter;
@@ -100,12 +103,25 @@
private final Runnable mTimeoutRunnable = this::timeout;
+ /**
+ * A state enum for devices' discovery.
+ */
+ enum DiscoveryState {
+ NOT_STARTED,
+ STARTING,
+ DISCOVERY_IN_PROGRESS,
+ FINISHED_STOPPED,
+ FINISHED_TIMEOUT
+ }
+
static void startForRequest(
@NonNull Context context, @NonNull AssociationRequest associationRequest) {
requireNonNull(associationRequest);
final Intent intent = new Intent(context, CompanionDeviceDiscoveryService.class);
intent.setAction(ACTION_START_DISCOVERY);
intent.putExtra(EXTRA_ASSOCIATION_REQUEST, associationRequest);
+ sStateLiveData.setValue(DiscoveryState.STARTING);
+
context.startService(intent);
}
@@ -115,10 +131,12 @@
context.startService(intent);
}
- @MainThread
- static @NonNull List<DeviceFilterPair<?>> getScanResults() {
- return sInstance != null ? new ArrayList<>(sInstance.mDevicesFound)
- : Collections.emptyList();
+ static LiveData<List<DeviceFilterPair<?>>> getScanResult() {
+ return sScanResultsLiveData;
+ }
+
+ static LiveData<DiscoveryState> getDiscoveryState() {
+ return sStateLiveData;
}
@Override
@@ -126,8 +144,6 @@
super.onCreate();
if (DEBUG) Log.d(TAG, "onCreate()");
- sInstance = this;
-
mBtManager = getSystemService(BluetoothManager.class);
mBtAdapter = mBtManager.getAdapter();
mBleScanner = mBtAdapter.getBluetoothLeScanner();
@@ -148,6 +164,7 @@
case ACTION_STOP_DISCOVERY:
stopDiscoveryAndFinish();
+ sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
break;
}
return START_NOT_STICKY;
@@ -157,8 +174,6 @@
public void onDestroy() {
super.onDestroy();
if (DEBUG) Log.d(TAG, "onDestroy()");
-
- sInstance = null;
}
@MainThread
@@ -168,6 +183,8 @@
if (mDiscoveryStarted) throw new RuntimeException("Discovery in progress.");
mDiscoveryStarted = true;
+ sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
+ sScanResultsLiveData.setValue(Collections.emptyList());
final List<DeviceFilter<?>> allFilters = request.getDeviceFilters();
final List<BluetoothDeviceFilter> btFilters =
@@ -329,7 +346,7 @@
// First: make change.
mDevicesFound.add(device);
// Then: notify observers.
- SCAN_RESULTS_OBSERVABLE.notifyObservers();
+ sScanResultsLiveData.setValue(mDevicesFound);
});
}
@@ -340,7 +357,7 @@
// First: make change.
mDevicesFound.remove(device);
// Then: notify observers.
- SCAN_RESULTS_OBSERVABLE.notifyObservers();
+ sScanResultsLiveData.setValue(mDevicesFound);
});
}
@@ -362,7 +379,7 @@
private void timeout() {
if (DEBUG) Log.i(TAG, "timeout()");
stopDiscoveryAndFinish();
- TIMEOUT_OBSERVABLE.notifyObservers();
+ sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
}
@Override
@@ -470,12 +487,4 @@
}
return result;
}
-
- private static class MyObservable extends Observable {
- @Override
- public void notifyObservers() {
- setChanged();
- super.notifyObservers();
- }
- }
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index 2499cf0..198b778 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -26,14 +26,14 @@
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.lifecycle.Observer;
+
import java.util.List;
-import java.util.Observable;
-import java.util.Observer;
/**
* Adapter for the list of "found" devices.
*/
-class DeviceListAdapter extends BaseAdapter implements Observer {
+class DeviceListAdapter extends BaseAdapter implements Observer<List<DeviceFilterPair<?>>> {
private final Context mContext;
// List if pairs (display name, address)
@@ -59,12 +59,6 @@
}
@Override
- public void update(Observable o, Object arg) {
- mDevices = CompanionDeviceDiscoveryService.getScanResults();
- notifyDataSetChanged();
- }
-
- @Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
final View view = convertView != null
? convertView
@@ -89,4 +83,10 @@
// final Drawable icon = getTintedIcon(mResources, iconRes);
// iconView.setImageDrawable(icon);
}
+
+ @Override
+ public void onChanged(List<DeviceFilterPair<?>> deviceFilterPairs) {
+ mDevices = deviceFilterPairs;
+ notifyDataSetChanged();
+ }
}