Introduce LiveData for CDM Activity and Discovery

Test: atest CtsCompanionDeviceManagerCoreTestCases
      atest CtsCompanionDeviceManagerUiAutomationTestCases
      atest CtsOsTestCases:CompanionDeviceManagerTest

Bug: 211722613
Change-Id: Icb84fe42cf02b1e0db4546fefee70afdd97ee7f3
This commit is contained in:
Evan Chen
2022-01-06 18:04:57 +00:00
parent 2be2597553
commit d343f9f76a
6 changed files with 77 additions and 47 deletions

View File

@@ -36,5 +36,11 @@ android_app {
defaults: ["platform_app_defaults"],
srcs: ["src/**/*.java"],
static_libs: [
"androidx.lifecycle_lifecycle-livedata",
"androidx.lifecycle_lifecycle-extensions",
"androidx.appcompat_appcompat",
],
platform_apis: true,
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -22,8 +22,8 @@ import static android.companion.AssociationRequest.DEVICE_PROFILE_COMPUTER;
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 static java.util.Objects.requireNonNull;
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.Button;
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 @@ public class CompanionDeviceActivity extends Activity {
// 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 @@ public class CompanionDeviceActivity extends Activity {
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 @@ public class CompanionDeviceActivity extends Activity {
}
}
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 @@ public class CompanionDeviceActivity extends Activity {
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);

View File

@@ -56,13 +56,18 @@ import android.os.SystemProperties;
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 @@ public class CompanionDeviceDiscoveryService extends Service {
"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 @@ public class CompanionDeviceDiscoveryService extends Service {
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 @@ public class CompanionDeviceDiscoveryService extends Service {
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 @@ public class CompanionDeviceDiscoveryService extends Service {
super.onCreate();
if (DEBUG) Log.d(TAG, "onCreate()");
sInstance = this;
mBtManager = getSystemService(BluetoothManager.class);
mBtAdapter = mBtManager.getAdapter();
mBleScanner = mBtAdapter.getBluetoothLeScanner();
@@ -148,6 +164,7 @@ public class CompanionDeviceDiscoveryService extends Service {
case ACTION_STOP_DISCOVERY:
stopDiscoveryAndFinish();
sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
break;
}
return START_NOT_STICKY;
@@ -157,8 +174,6 @@ public class CompanionDeviceDiscoveryService extends Service {
public void onDestroy() {
super.onDestroy();
if (DEBUG) Log.d(TAG, "onDestroy()");
sInstance = null;
}
@MainThread
@@ -168,6 +183,8 @@ public class CompanionDeviceDiscoveryService extends Service {
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 @@ public class CompanionDeviceDiscoveryService extends Service {
// First: make change.
mDevicesFound.add(device);
// Then: notify observers.
SCAN_RESULTS_OBSERVABLE.notifyObservers();
sScanResultsLiveData.setValue(mDevicesFound);
});
}
@@ -340,7 +357,7 @@ public class CompanionDeviceDiscoveryService extends Service {
// First: make change.
mDevicesFound.remove(device);
// Then: notify observers.
SCAN_RESULTS_OBSERVABLE.notifyObservers();
sScanResultsLiveData.setValue(mDevicesFound);
});
}
@@ -362,7 +379,7 @@ public class CompanionDeviceDiscoveryService extends Service {
private void timeout() {
if (DEBUG) Log.i(TAG, "timeout()");
stopDiscoveryAndFinish();
TIMEOUT_OBSERVABLE.notifyObservers();
sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
}
@Override
@@ -470,12 +487,4 @@ public class CompanionDeviceDiscoveryService extends Service {
}
return result;
}
private static class MyObservable extends Observable {
@Override
public void notifyObservers() {
setChanged();
super.notifyObservers();
}
}
}

View File

@@ -26,14 +26,14 @@ import android.widget.BaseAdapter;
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)
@@ -58,12 +58,6 @@ class DeviceListAdapter extends BaseAdapter implements Observer {
return position;
}
@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
@@ -89,4 +83,10 @@ class DeviceListAdapter extends BaseAdapter implements Observer {
// final Drawable icon = getTintedIcon(mResources, iconRes);
// iconView.setImageDrawable(icon);
}
@Override
public void onChanged(List<DeviceFilterPair<?>> deviceFilterPairs) {
mDevices = deviceFilterPairs;
notifyDataSetChanged();
}
}