Skip to content

Commit 367a18a

Browse files
author
Peter Li
committed
Add Automotive and Android Auto tests, update UI
Fix: 137138749 Test: Manual Change-Id: I189d52718fc813a40713153379bffa851cfb0465
1 parent c1320b3 commit 367a18a

File tree

14 files changed

+1006
-129
lines changed

14 files changed

+1006
-129
lines changed

mediacontroller/src/main/java/com/example/android/mediacontroller/LaunchActivity.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.example.android.mediacontroller.tasks.MediaAppControllerUtils;
3636
import com.google.android.material.snackbar.Snackbar;
3737

38+
import java.util.ArrayList;
3839
import java.util.List;
3940

4041
import androidx.annotation.NonNull;
@@ -54,6 +55,7 @@ public class LaunchActivity extends AppCompatActivity {
5455

5556
private Snackbar mSnackbar;
5657

58+
private MediaAppListAdapter mediaAppsAdapter;
5759
private MediaAppListAdapter.Section mMediaBrowserApps;
5860

5961
private final FindMediaAppsTask.AppListUpdatedCallback mBrowserAppsUpdated =
@@ -64,12 +66,50 @@ public void onAppListUpdated(
6466

6567
if (mediaAppDetails.isEmpty()) {
6668
// Show an error if no apps were found.
69+
mMediaBrowserApps = mediaAppsAdapter
70+
.addSection(R.string.media_app_header_browse);
6771
mMediaBrowserApps.setError(
6872
R.string.no_apps_found,
6973
R.string.no_apps_reason_no_media_browser_service);
7074
return;
7175
}
72-
mMediaBrowserApps.setAppsList(mediaAppDetails);
76+
77+
ArrayList<MediaAppDetails> apps = new ArrayList<>();
78+
ArrayList<MediaAppDetails> autoApps = new ArrayList<>();
79+
ArrayList<MediaAppDetails> automotiveApps = new ArrayList<>();
80+
ArrayList<MediaAppDetails> bothApps = new ArrayList<>();
81+
82+
for (MediaAppDetails app : mediaAppDetails) {
83+
if (app.supportsAuto && app.supportsAutomotive) {
84+
bothApps.add(app);
85+
} else if (app.supportsAuto) {
86+
autoApps.add(app);
87+
} else if (app.supportsAutomotive) {
88+
automotiveApps.add(app);
89+
} else {
90+
apps.add(app);
91+
}
92+
}
93+
94+
mediaAppsAdapter.clearImplSections();
95+
96+
if (!apps.isEmpty()) {
97+
mMediaBrowserApps = mediaAppsAdapter.addSection(
98+
R.string.media_app_header_browse);
99+
mMediaBrowserApps.setAppsList(apps);
100+
}
101+
if (!bothApps.isEmpty()) {
102+
mediaAppsAdapter.addSection(R.string.media_app_both_header_browse)
103+
.setAppsList(bothApps);
104+
}
105+
if (!autoApps.isEmpty()) {
106+
mediaAppsAdapter.addSection(R.string.media_app_auto_header_browse)
107+
.setAppsList(autoApps);
108+
}
109+
if (!automotiveApps.isEmpty()) {
110+
mediaAppsAdapter.addSection(R.string.media_app_automotive_header_browse)
111+
.setAppsList(automotiveApps);
112+
}
73113
}
74114
};
75115

@@ -88,7 +128,7 @@ protected void onCreate(Bundle savedInstanceState) {
88128
Toolbar toolbar = findViewById(R.id.toolbar);
89129
setSupportActionBar(toolbar);
90130

91-
MediaAppListAdapter mediaAppsAdapter = new MediaAppListAdapter((app, isTest) -> {
131+
mediaAppsAdapter = new MediaAppListAdapter((app, isTest) -> {
92132
if (mSnackbar != null) {
93133
mSnackbar.dismiss();
94134
mSnackbar = null;
@@ -103,7 +143,6 @@ protected void onCreate(Bundle savedInstanceState) {
103143
if (mMediaSessionListener != null) {
104144
mMediaSessionListener.onCreate(mediaAppsAdapter);
105145
}
106-
mMediaBrowserApps = mediaAppsAdapter.addSection(R.string.media_app_header_browse);
107146

108147
RecyclerView mediaAppsList = findViewById(R.id.app_list);
109148
mediaAppsList.setLayoutManager(new LinearLayoutManager(this));

mediacontroller/src/main/java/com/example/android/mediacontroller/MediaAppControllerActivity.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public class MediaAppControllerActivity extends AppCompatActivity {
150150
* @return An Intent that can be used to start the Activity.
151151
*/
152152
public static Intent buildIntent(final Activity activity,
153-
final MediaAppDetails appDetails) {
153+
final MediaAppDetails appDetails) {
154154
final Intent intent = new Intent(activity, MediaAppControllerActivity.class);
155155
intent.putExtra(APP_DETAILS_EXTRA, appDetails);
156156
return intent;
@@ -162,6 +162,8 @@ protected void onCreate(Bundle savedInstanceState) {
162162
setContentView(R.layout.activity_media_app_controller);
163163
final Toolbar toolbar = findViewById(R.id.toolbar);
164164
setSupportActionBar(toolbar);
165+
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
166+
toolbar.setNavigationOnClickListener(v -> finish());
165167

166168
mViewPager = findViewById(R.id.view_pager);
167169
mInputTypeView = findViewById(R.id.input_type);
@@ -751,7 +753,7 @@ private void showActions(@PlaybackStateCompat.Actions long actions) {
751753
}
752754

753755
private boolean actionSupported(@PlaybackStateCompat.Actions long actions,
754-
@PlaybackStateCompat.Actions long checkAction) {
756+
@PlaybackStateCompat.Actions long checkAction) {
755757
return ((actions & checkAction) != 0);
756758
}
757759

@@ -778,8 +780,8 @@ private static class AudioFocusHelper
778780
private final Spinner mFocusTypeSpinner;
779781

780782
private AudioFocusHelper(@NonNull Context context,
781-
@NonNull ToggleButton focusToggleButton,
782-
@NonNull Spinner focusTypeSpinner) {
783+
@NonNull ToggleButton focusToggleButton,
784+
@NonNull Spinner focusTypeSpinner) {
783785

784786
mAudioManager = (AudioManager) context.getSystemService(AUDIO_SERVICE);
785787
mToggleButton = focusToggleButton;
@@ -897,7 +899,7 @@ public int getItemCount() {
897899
}
898900

899901
void setActions(MediaControllerCompat controller,
900-
List<PlaybackStateCompat.CustomAction> actions) {
902+
List<PlaybackStateCompat.CustomAction> actions) {
901903
mControls = controller.getTransportControls();
902904
try {
903905
mMediaAppResources = getPackageManager()
@@ -921,7 +923,7 @@ public int getNewListSize() {
921923
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
922924
return actions.size() == mActions.size() &&
923925
actions.get(oldItemPosition).getAction()
924-
.equals(mActions.get(newItemPosition).getAction());
926+
.equals(mActions.get(newItemPosition).getAction());
925927
}
926928

927929
@Override
@@ -959,9 +961,9 @@ private static abstract class ModeHelper implements AdapterView.OnItemSelectedLi
959961
private final List<Integer> modes;
960962

961963
ModeHelper(ViewGroup container,
962-
@IdRes int stateSpinnerView,
963-
@IdRes int iconImageView,
964-
List<Integer> modes) {
964+
@IdRes int stateSpinnerView,
965+
@IdRes int iconImageView,
966+
List<Integer> modes) {
965967
this.context = container.getContext();
966968
this.spinner = container.findViewById(stateSpinnerView);
967969
this.icon = container.findViewById(iconImageView);
@@ -1073,7 +1075,7 @@ private class BrowseMediaItemsAdapter extends
10731075
new MediaBrowserCompat.SubscriptionCallback() {
10741076
@Override
10751077
public void onChildrenLoaded(@NonNull String parentId,
1076-
@NonNull List<MediaItem> children) {
1078+
@NonNull List<MediaItem> children) {
10771079
updateItemsEmptyIfNull(children);
10781080
}
10791081
};
@@ -1252,7 +1254,7 @@ protected void subscribe() {
12521254
mBrowser.search(getCurrentNode(), null, new MediaBrowserCompat.SearchCallback() {
12531255
@Override
12541256
public void onSearchResult(@NonNull String query, Bundle extras,
1255-
@NonNull List<MediaBrowserCompat.MediaItem> items) {
1257+
@NonNull List<MediaBrowserCompat.MediaItem> items) {
12561258
if (query.equals(getCurrentNode())) {
12571259
updateItemsEmptyIfNull(items);
12581260
}

mediacontroller/src/main/java/com/example/android/mediacontroller/MediaAppDetails.java

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import android.content.ComponentName;
1919
import android.content.Intent;
20+
import android.content.pm.FeatureInfo;
2021
import android.content.pm.PackageItemInfo;
2122
import android.content.pm.PackageManager;
2223
import android.content.pm.ResolveInfo;
@@ -26,13 +27,18 @@
2627
import android.graphics.drawable.Drawable;
2728
import android.media.session.MediaSession;
2829
import android.os.Build;
30+
import android.os.Bundle;
2931
import android.os.Parcel;
3032
import android.os.Parcelable;
33+
3134
import androidx.annotation.Nullable;
3235
import androidx.annotation.RequiresApi;
3336
import androidx.media.MediaBrowserServiceCompat;
37+
3438
import android.support.v4.media.session.MediaSessionCompat;
39+
import android.util.Log;
3540

41+
import java.util.Arrays;
3642
import java.util.List;
3743

3844
/**
@@ -47,9 +53,11 @@ public class MediaAppDetails implements Parcelable {
4753
public Bitmap banner;
4854
public final MediaSessionCompat.Token sessionToken;
4955
public final ComponentName componentName;
56+
public boolean supportsAutomotive = false;
57+
public boolean supportsAuto = false;
5058

5159
public MediaAppDetails(String packageName, String name, Bitmap appIcon,
52-
@Nullable Bitmap appBanner, MediaSessionCompat.Token token) {
60+
@Nullable Bitmap appBanner, MediaSessionCompat.Token token) {
5361
this.packageName = packageName;
5462
appName = name;
5563
sessionToken = token;
@@ -62,12 +70,12 @@ public MediaAppDetails(String packageName, String name, Bitmap appIcon,
6270
}
6371

6472
public MediaAppDetails(String packageName, String name, Bitmap appIcon,
65-
@Nullable Bitmap appBanner, MediaSession.Token token) {
73+
@Nullable Bitmap appBanner, MediaSession.Token token) {
6674
this(packageName, name, appIcon, appBanner, MediaSessionCompat.Token.fromToken(token));
6775
}
6876

6977
public MediaAppDetails(PackageItemInfo info, PackageManager pm, Resources resources,
70-
MediaSession.Token token) {
78+
MediaSession.Token token) {
7179
packageName = info.packageName;
7280
appName = info.loadLabel(pm).toString();
7381
Drawable appIcon = info.loadIcon(pm);
@@ -90,6 +98,27 @@ public MediaAppDetails(PackageItemInfo info, PackageManager pm, Resources resour
9098
componentName = new ComponentName(info.packageName, info.name);
9199
sessionToken = null;
92100
}
101+
102+
try {
103+
FeatureInfo[] features = pm.getPackageInfo(
104+
packageName, PackageManager.GET_CONFIGURATIONS).reqFeatures;
105+
106+
supportsAutomotive = features != null && Arrays.stream(features)
107+
.filter(f -> "android.hardware.type.automotive".equals(f.name))
108+
.findAny()
109+
.orElse(null) != null;
110+
111+
Bundle metaData = pm.getApplicationInfo(packageName,
112+
PackageManager.GET_META_DATA).metaData;
113+
114+
if (metaData != null) {
115+
if (metaData.containsKey("com.google.android.gms.car.application")) {
116+
supportsAuto = true;
117+
}
118+
}
119+
} catch (PackageManager.NameNotFoundException e) {
120+
Log.w("MediaAppDetails", "package name not found" + packageName);
121+
}
93122
}
94123

95124
public MediaAppDetails(PackageItemInfo info, PackageManager pm, Resources resources) {
@@ -112,11 +141,13 @@ public static ServiceInfo findServiceInfo(String packageName, PackageManager pm)
112141
return null;
113142
}
114143

115-
public static ResolveInfo findPreferenceResolveInfo(String packageName, PackageManager pm) {
144+
public static List<ResolveInfo> findResolveInfo(
145+
String packageName, PackageManager pm, String action) {
116146
if (packageName != null) {
117-
Intent prefsIntent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES);
147+
Intent prefsIntent = new Intent(action);
118148
prefsIntent.setPackage(packageName);
119-
return pm.resolveActivity(prefsIntent, 0);
149+
150+
return pm.queryIntentActivities(prefsIntent, 0);
120151
}
121152
return null;
122153
}
@@ -127,6 +158,8 @@ private MediaAppDetails(final Parcel parcel) {
127158
icon = parcel.readParcelable(MediaAppDetails.class.getClassLoader());
128159
sessionToken = parcel.readParcelable(MediaAppDetails.class.getClassLoader());
129160
componentName = parcel.readParcelable(MediaAppDetails.class.getClassLoader());
161+
supportsAuto = parcel.readInt() == 1;
162+
supportsAutomotive = parcel.readInt() == 1;
130163
}
131164

132165
@Override
@@ -141,6 +174,8 @@ public void writeToParcel(Parcel dest, int flags) {
141174
dest.writeParcelable(icon, flags);
142175
dest.writeParcelable(sessionToken, flags);
143176
dest.writeParcelable(componentName, flags);
177+
dest.writeInt(supportsAuto ? 1 : 0);
178+
dest.writeInt(supportsAutomotive ? 1 : 0);
144179
}
145180

146181
public static final Parcelable.Creator<MediaAppDetails> CREATOR =

mediacontroller/src/main/java/com/example/android/mediacontroller/MediaAppListAdapter.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import androidx.recyclerview.widget.DiffUtil;
2323
import androidx.recyclerview.widget.RecyclerView;
2424
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
25+
2526
import android.view.LayoutInflater;
2627
import android.view.View;
2728
import android.view.ViewGroup;
@@ -105,7 +106,7 @@ static class AppEntry implements RecyclerViewItem {
105106
private final MediaAppSelectedListener appSelectedListener;
106107

107108
public AppEntry(MediaAppDetails appDetails,
108-
MediaAppSelectedListener appSelectedListener) {
109+
MediaAppSelectedListener appSelectedListener) {
109110
this.appDetails = appDetails;
110111
this.appSelectedListener = appSelectedListener;
111112
}
@@ -120,7 +121,8 @@ public void bindTo(RecyclerView.ViewHolder vh) {
120121
ViewHolder holder = (ViewHolder) vh;
121122
holder.appIconView.setImageBitmap(appDetails.icon);
122123
holder.appIconView.setContentDescription(
123-
holder.appIconView.getContext().getString(R.string.app_icon_desc, appDetails.appName));
124+
holder.appIconView.getContext().getString(R.string.app_icon_desc,
125+
appDetails.appName));
124126
holder.appNameView.setText(appDetails.appName);
125127
holder.appPackageView.setText(appDetails.packageName);
126128

@@ -227,7 +229,7 @@ static class Error implements RecyclerViewItem {
227229
private final View.OnClickListener clickListener;
228230

229231
public Error(@StringRes int message, @StringRes int detail, @StringRes int buttonText,
230-
@Nullable View.OnClickListener onClickListener) {
232+
@Nullable View.OnClickListener onClickListener) {
231233
this.errorMsgId = message;
232234
this.errorDetailId = detail;
233235
this.errorButtonId = buttonText;
@@ -316,7 +318,7 @@ public void setError(@StringRes int message, @StringRes int detail) {
316318
}
317319

318320
public void setError(@StringRes int message, @StringRes int detail,
319-
@StringRes int buttonText, View.OnClickListener onClickListener) {
321+
@StringRes int buttonText, View.OnClickListener onClickListener) {
320322
mItems.clear();
321323
mItems.add(new Error(message, detail, buttonText, onClickListener));
322324
updateData();
@@ -329,7 +331,6 @@ public void setAppsList(@NonNull final List<? extends MediaAppDetails> appEntrie
329331
}
330332
updateData();
331333
}
332-
333334
}
334335

335336
private final List<Section> mSections = new ArrayList<>();
@@ -341,6 +342,12 @@ public void setAppsList(@NonNull final List<? extends MediaAppDetails> appEntrie
341342
mMediaAppSelectedListener = itemClickListener;
342343
}
343344

345+
void clearImplSections() {
346+
Section active = mSections.get(0);
347+
mSections.clear();
348+
mSections.add(active);
349+
}
350+
344351
Section addSection(@StringRes int label) {
345352
Section section = new Section(label);
346353
mSections.add(section);

0 commit comments

Comments
 (0)