Allow to show device name as toolbar title.
Fixes: 143956787
Test: manually
Change-Id: I43f1f4e7bcc8228a351df5fc3be399d65a078295
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e409c95..a7801ab 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -42,7 +42,7 @@
<activity android:name=".ui.TelecomActivity"
android:launchMode="singleTask"
- android:theme="@style/Theme.Dialer"
+ android:theme="@style/Theme.Dialer.Telecom"
android:label="@string/phone_app_name"
android:exported="true"
android:resizeableActivity="true">
@@ -83,7 +83,7 @@
<activity android:name=".ui.activecall.InCallActivity"
android:launchMode="singleInstance"
- android:theme="@style/Theme.Dialer"
+ android:theme="@style/Theme.Dialer.InCall"
android:label="@string/phone_app_name">
<meta-data android:name="distractionOptimized" android:value="true"/>
</activity>
diff --git a/res/values-port/strings.xml b/res/values-port/configs.xml
similarity index 77%
rename from res/values-port/strings.xml
rename to res/values-port/configs.xml
index 572bb37..b0af8bd 100644
--- a/res/values-port/strings.xml
+++ b/res/values-port/configs.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version='1.0' encoding='UTF-8'?>
<!--
Copyright (C) 2019 The Android Open Source Project
@@ -14,9 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<resources>
- <!-- Titles -->
- <!-- Toolbar title for tabbed pages -->
- <string name="default_toolbar_title">@string/phone_app_name</string>
-</resources>
\ No newline at end of file
+ <!-- Use app name as toolbar title. Supported value see @attr/toolbarTitleMode -->
+ <integer name="config_toolbar_title_mode">0</integer>
+</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 7b966de..f085c19 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -29,6 +29,13 @@
<declare-styleable name="Theme">
<!-- Tab bar height that only applies to portrait layout where tabs are under action bar.-->
<attr name="tabBarSize" format="dimension"/>
+
+ <!-- Toolbar title mode -->
+ <attr name="toolbarTitleMode" format="enum">
+ <enum name="app_name" value="0"/>
+ <enum name="none" value="1"/>
+ <enum name="device_name" value="2"/>
+ </attr>
</declare-styleable>
<declare-styleable name="LoadingFrameLayout">
diff --git a/res/values/configs.xml b/res/values/configs.xml
index 531b0fd..42ba9ab 100644
--- a/res/values/configs.xml
+++ b/res/values/configs.xml
@@ -33,4 +33,7 @@
<!-- A config determines if to show the action bar view in the contact details page.-->
<bool name="config_show_contact_details_action_bar_view">false</bool>
+
+ <!-- No toolbar title. Supported value see @attr/toolbarTitleMode -->
+ <integer name="config_toolbar_title_mode">1</integer>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 862794a..579c363 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -70,8 +70,6 @@
<string name="contacts_title">Contacts</string>
<!-- Title for the dialpad [CHAR LIMIT=30] -->
<string name="dialpad_title">Dialpad</string>
- <!-- Toolbar title for tabbed pages -->
- <string name="default_toolbar_title" translatable="false"></string>
<!-- Headers for call history -->
<!-- Header in call log to group calls from the current day. [CHAR LIMIT=30] -->
diff --git a/res/values/themes.xml b/res/values/themes.xml
index b64b934..e3b054c 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources>
- <!-- The theme for the Dialer app. -->
+ <!-- The base theme for the Dialer app. -->
<style name="Theme.Dialer" parent="android:Theme.DeviceDefault.NoActionBar">
<item name="android:actionBarSize">@dimen/action_bar_height</item>
<item name="tabBarSize">@dimen/tab_bar_height</item>
@@ -29,6 +29,12 @@
<item name="android:searchViewStyle">@style/Widget.Dialer.SearchView</item>
</style>
+ <style name="Theme.Dialer.Telecom" parent="Theme.Dialer">
+ <item name="toolbarTitleMode">@integer/config_toolbar_title_mode</item>
+ </style>
+
+ <style name="Theme.Dialer.InCall" parent="Theme.Dialer"/>
+
<style name="Theme.Dialer.Setting" parent="Theme.Dialer">
<item name="preferenceTheme">@style/PreferenceTheme</item>
</style>
diff --git a/src/com/android/car/dialer/livedata/HfpDeviceListLiveData.java b/src/com/android/car/dialer/livedata/HfpDeviceListLiveData.java
new file mode 100644
index 0000000..54794d5
--- /dev/null
+++ b/src/com/android/car/dialer/livedata/HfpDeviceListLiveData.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 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.car.dialer.livedata;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadsetClient;
+import android.bluetooth.BluetoothProfile;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+
+import java.util.List;
+
+/** {@link LiveData} that monitors the hfp connected devices. */
+public class HfpDeviceListLiveData extends MutableLiveData<List<BluetoothDevice>> {
+ private final Context mContext;
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final IntentFilter mIntentFilter;
+
+ private BluetoothHeadsetClient mBluetoothHeadsetClient;
+
+ private BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ update();
+ }
+ };
+
+ /** Creates a new {@link HfpDeviceListLiveData}. Call on main thread. */
+ public HfpDeviceListLiveData(Context context) {
+ mContext = context;
+
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (mBluetoothAdapter != null) {
+ mBluetoothAdapter.getProfileProxy(mContext, new BluetoothProfile.ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ if (profile == BluetoothProfile.HEADSET_CLIENT) {
+ mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
+ update();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ }
+ }, BluetoothProfile.HEADSET_CLIENT);
+ }
+
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
+ }
+
+ @Override
+ protected void onActive() {
+ if (mBluetoothAdapter != null) {
+ update();
+ mContext.registerReceiver(mBluetoothStateReceiver, mIntentFilter);
+ }
+ }
+
+ @Override
+ protected void onInactive() {
+ if (mBluetoothAdapter != null) {
+ mContext.unregisterReceiver(mBluetoothStateReceiver);
+ }
+ }
+
+ private void update() {
+ if (mBluetoothHeadsetClient != null) {
+ setValue(mBluetoothHeadsetClient.getConnectedDevices());
+ }
+ }
+}
diff --git a/src/com/android/car/dialer/ui/TelecomActivity.java b/src/com/android/car/dialer/ui/TelecomActivity.java
index 26b5cf9..9a2160d 100644
--- a/src/com/android/car/dialer/ui/TelecomActivity.java
+++ b/src/com/android/car/dialer/ui/TelecomActivity.java
@@ -36,6 +36,7 @@
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModelProviders;
import androidx.preference.PreferenceManager;
@@ -73,11 +74,9 @@
public class TelecomActivity extends FragmentActivity implements
DialerBaseFragment.DialerFragmentParent, FragmentManager.OnBackStackChangedListener {
private static final String TAG = "CD.TelecomActivity";
-
private LiveData<String> mBluetoothErrorMsgLiveData;
private LiveData<Integer> mDialerAppStateLiveData;
private LiveData<List<Call>> mOngoingCallListLiveData;
-
// View objects for this activity.
private CarTabLayout<TelecomPageTab> mTabLayout;
private TelecomPageTab.Factory mTabFactory;
@@ -87,6 +86,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
L.d(TAG, "onCreate");
setContentView(R.layout.telecom_activity);
@@ -104,6 +104,8 @@
mDialerAppStateLiveData = viewModel.getDialerAppState();
mDialerAppStateLiveData.observe(this,
dialerAppState -> updateCurrentFragment(dialerAppState));
+ MutableLiveData<Integer> toolbarTitleMode = viewModel.getToolbarTitleMode();
+ toolbarTitleMode.setValue(Themes.getAttrInteger(this, R.attr.toolbarTitleMode));
InCallViewModel inCallViewModel = ViewModelProviders.of(this).get(InCallViewModel.class);
mOngoingCallListLiveData = inCallViewModel.getOngoingCallList();
diff --git a/src/com/android/car/dialer/ui/TelecomActivityViewModel.java b/src/com/android/car/dialer/ui/TelecomActivityViewModel.java
index c9125c1..e28c4ce 100644
--- a/src/com/android/car/dialer/ui/TelecomActivityViewModel.java
+++ b/src/com/android/car/dialer/ui/TelecomActivityViewModel.java
@@ -44,13 +44,18 @@
*/
public class TelecomActivityViewModel extends AndroidViewModel {
private static final String TAG = "CD.TelecomActivityViewModel";
- /** A constant which indicates that there's no Bluetooth error. */
+ /**
+ * A constant which indicates that there's no Bluetooth error.
+ */
public static final String NO_BT_ERROR = "NO_ERROR";
private final Context mApplicationContext;
private final LiveData<String> mErrorStringLiveData;
private final MutableLiveData<Integer> mDialerAppStateLiveData;
+ private final ToolbarTitleLiveData mToolbarTitleLiveData;
+ private final MutableLiveData<Integer> mToolbarTitleMode;
+
/**
* App state indicates if bluetooth is connected or it should just show the content fragments.
*/
@@ -67,6 +72,9 @@
super(application);
mApplicationContext = application.getApplicationContext();
+ mToolbarTitleMode = new MediatorLiveData<>();
+ mToolbarTitleLiveData = new ToolbarTitleLiveData(mApplicationContext, mToolbarTitleMode);
+
if (BluetoothAdapter.getDefaultAdapter() == null) {
MutableLiveData<String> bluetoothUnavailableLiveData = new MutableLiveData<>();
bluetoothUnavailableLiveData.setValue(
@@ -84,6 +92,22 @@
mDialerAppStateLiveData = new DialerAppStateLiveData(mErrorStringLiveData);
}
+ /**
+ * Returns the {@link LiveData} for the toolbar title, which provides the toolbar title
+ * depending on the {@link R.attr#toolbarTitleMode}.
+ */
+ public LiveData<String> getToolbarTitle() {
+ return mToolbarTitleLiveData;
+ }
+
+ /**
+ * Returns the {@link MutableLiveData} of the toolbar title mode. The value should be set by the
+ * {@link TelecomActivity}.
+ */
+ public MutableLiveData<Integer> getToolbarTitleMode() {
+ return mToolbarTitleMode;
+ }
+
public MutableLiveData<Integer> getDialerAppState() {
return mDialerAppStateLiveData;
}
diff --git a/src/com/android/car/dialer/ui/ToolbarTitleLiveData.java b/src/com/android/car/dialer/ui/ToolbarTitleLiveData.java
new file mode 100644
index 0000000..11863dd
--- /dev/null
+++ b/src/com/android/car/dialer/ui/ToolbarTitleLiveData.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 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.car.dialer.ui;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+
+import androidx.annotation.IntDef;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MediatorLiveData;
+
+import com.android.car.dialer.R;
+import com.android.car.dialer.livedata.HfpDeviceListLiveData;
+
+import java.util.List;
+
+/**
+ * LiveData for the toolbar title of the {@link com.android.car.dialer.ui.TelecomActivity}. The
+ * attribute {@link R.attr#toolbarTitleMode} is activity scope attribute. Supported values are:
+ * <ul>
+ * <li> app_name: 0
+ * <li> none: 1
+ * <li> device_name: 2
+ */
+class ToolbarTitleLiveData extends MediatorLiveData<String> {
+
+ @IntDef({
+ ToolbarTitleMode.APP_NAME,
+ ToolbarTitleMode.NONE,
+ ToolbarTitleMode.DEVICE_NAME
+ })
+ private @interface ToolbarTitleMode {
+ int APP_NAME = 0;
+ int NONE = 1;
+ int DEVICE_NAME = 2;
+ }
+
+ private final HfpDeviceListLiveData mHfpDeviceListLiveData;
+ private final LiveData<Integer> mToolbarTitleModeLiveData;
+ private final Context mContext;
+
+ ToolbarTitleLiveData(Context context, LiveData<Integer> toolbarTitleModeLiveData) {
+ mContext = context;
+ mToolbarTitleModeLiveData = toolbarTitleModeLiveData;
+ mHfpDeviceListLiveData = new HfpDeviceListLiveData(context);
+
+ addSource(mToolbarTitleModeLiveData, this::updateToolbarTitle);
+ }
+
+ private void updateToolbarTitle(int toolbarTitleMode) {
+ switch (toolbarTitleMode) {
+ case ToolbarTitleMode.NONE:
+ removeSource(mHfpDeviceListLiveData);
+ setValue(null);
+ return;
+ case ToolbarTitleMode.DEVICE_NAME:
+ addSource(mHfpDeviceListLiveData, this::updateDeviceName);
+ return;
+ case ToolbarTitleMode.APP_NAME:
+ default:
+ removeSource(mHfpDeviceListLiveData);
+ setValue(mContext.getString(R.string.phone_app_name));
+ return;
+ }
+ }
+
+ private void updateDeviceName(List<BluetoothDevice> hfpDeviceList) {
+ // When there is no hfp device connected, use the app name as title.
+ if (hfpDeviceList == null || hfpDeviceList.isEmpty()) {
+ setValue(mContext.getString(R.string.phone_app_name));
+ return;
+ }
+
+ // TODO: handle multi-HFP cases. Right now return the first connected device in list.
+ BluetoothDevice bluetoothDevice = hfpDeviceList.get(0);
+ setValue(bluetoothDevice.getName());
+ }
+}
diff --git a/src/com/android/car/dialer/ui/common/DialerBaseFragment.java b/src/com/android/car/dialer/ui/common/DialerBaseFragment.java
index 87b5240..9fc862b 100644
--- a/src/com/android/car/dialer/ui/common/DialerBaseFragment.java
+++ b/src/com/android/car/dialer/ui/common/DialerBaseFragment.java
@@ -24,10 +24,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.ViewModelProviders;
import com.android.car.apps.common.util.Themes;
import com.android.car.dialer.R;
import com.android.car.dialer.ui.TelecomActivity;
+import com.android.car.dialer.ui.TelecomActivityViewModel;
/** The base class for top level dialer content {@link Fragment}s. */
public abstract class DialerBaseFragment extends Fragment {
@@ -46,7 +49,11 @@
/** Customizes the action bar. Can be overridden in subclasses. */
public void setupActionBar(@NonNull ActionBar actionBar) {
- actionBar.setTitle(getActionBarTitle());
+ TelecomActivityViewModel viewModel = ViewModelProviders.of(getActivity()).get(
+ TelecomActivityViewModel.class);
+ LiveData<String> toolbarTitleLiveData = viewModel.getToolbarTitle();
+ toolbarTitleLiveData.observe(this,
+ toolbarTitle -> setActionBarTitle(actionBar, toolbarTitle));
actionBar.setCustomView(null);
setActionBarBackground(getContext().getDrawable(R.color.app_bar_background_color));
}
@@ -59,11 +66,6 @@
}
}
- /** Return the action bar title. */
- protected CharSequence getActionBarTitle() {
- return getString(R.string.default_toolbar_title);
- }
-
protected int getTopBarHeight() {
View toolbar = getActivity().findViewById(R.id.car_toolbar);
@@ -79,6 +81,11 @@
return topBarHeight;
}
+ protected final void setActionBarTitle(@NonNull ActionBar actionBar,
+ @Nullable CharSequence title) {
+ actionBar.setTitle(title);
+ }
+
protected final void setActionBarBackground(@Nullable Drawable drawable) {
Activity activity = getActivity();
if (activity instanceof TelecomActivity) {
diff --git a/src/com/android/car/dialer/ui/search/ContactResultsFragment.java b/src/com/android/car/dialer/ui/search/ContactResultsFragment.java
index 3888179..63a5d0f 100644
--- a/src/com/android/car/dialer/ui/search/ContactResultsFragment.java
+++ b/src/com/android/car/dialer/ui/search/ContactResultsFragment.java
@@ -127,7 +127,8 @@
@Override
public void setupActionBar(@NonNull ActionBar actionBar) {
- super.setupActionBar(actionBar);
+ setActionBarTitle(actionBar, null);
+ setActionBarBackground(getContext().getDrawable(R.color.app_bar_background_color));
// We have to use the setCustomView that accepts a LayoutParams to get the SearchView
// to take up the full height and width of the action bar.
@@ -192,11 +193,6 @@
}
@Override
- protected CharSequence getActionBarTitle() {
- return null;
- }
-
- @Override
public void onShowContactDetail(Contact contact) {
Fragment contactDetailsFragment = ContactDetailsFragment.newInstance(contact);
pushContentFragment(contactDetailsFragment, ContactDetailsFragment.FRAGMENT_TAG);