1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.media;
18 
19 
20 import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_BROWSE;
21 
22 import android.car.content.pm.CarPackageManager;
23 import android.content.ActivityNotFoundException;
24 import android.content.Intent;
25 import android.content.pm.ResolveInfo;
26 import android.content.res.Resources;
27 import android.graphics.drawable.BitmapDrawable;
28 import android.graphics.drawable.Drawable;
29 import android.media.audiofx.AudioEffect;
30 import android.util.Log;
31 import android.view.LayoutInflater;
32 import android.view.View;
33 import android.view.ViewGroup;
34 
35 import androidx.annotation.CallSuper;
36 import androidx.annotation.LayoutRes;
37 import androidx.annotation.NonNull;
38 import androidx.annotation.Nullable;
39 import androidx.fragment.app.FragmentActivity;
40 
41 import com.android.car.apps.common.util.CarPackageManagerUtils;
42 import com.android.car.media.common.source.MediaSource;
43 import com.android.car.media.common.source.MediaSourceViewModel;
44 import com.android.car.media.widgets.AppBarController;
45 
46 import com.android.car.ui.baselayout.Insets;
47 import com.android.car.ui.baselayout.InsetsChangedListener;
48 import com.android.car.ui.core.CarUi;
49 import com.android.car.ui.toolbar.ToolbarController;
50 
51 /**
52  * Functionality common to content view controllers. It mainly handles the AppBar view,
53  * which is common to all of them.
54  */
55 abstract class ViewControllerBase implements InsetsChangedListener {
56     private static final String TAG = "ViewControllerBase";
57 
58     private final boolean mShouldShowSoundSettings;
59     private final CarPackageManager mCarPackageManager;
60 
61     final FragmentActivity mActivity;
62     final int mFadeDuration;
63     final View mContent;
64     final AppBarController mAppBarController;
65     final MediaSourceViewModel mMediaSourceVM;
66 
67     private Intent mCurrentSourcePreferences;
68 
ViewControllerBase(FragmentActivity activity, CarPackageManager carPackageManager, ViewGroup container, @LayoutRes int resource)69     ViewControllerBase(FragmentActivity activity, CarPackageManager carPackageManager,
70             ViewGroup container, @LayoutRes int resource) {
71         mActivity = activity;
72         Resources res = mActivity.getResources();
73         mFadeDuration = res.getInteger(R.integer.new_album_art_fade_in_duration);
74         mShouldShowSoundSettings = res.getBoolean(R.bool.show_sound_settings);
75 
76         LayoutInflater inflater = LayoutInflater.from(container.getContext());
77         mContent = inflater.inflate(resource, container, false);
78         container.addView(mContent);
79 
80         GuidelinesUpdater updater = new GuidelinesUpdater(mContent);
81         updater.addListener(this);
82         ToolbarController toolbar = CarUi.installBaseLayoutAround(mContent, updater, true);
83 
84         mAppBarController = new AppBarController(activity, toolbar);
85         mAppBarController.setSearchSupported(false);
86         mAppBarController.setHasEqualizer(false);
87 
88         mCarPackageManager = carPackageManager;
89 
90         mMediaSourceVM = MediaSourceViewModel.get(activity.getApplication(),
91                 MEDIA_SOURCE_MODE_BROWSE);
92 
93     }
94 
95     @Override
onCarUiInsetsChanged(@onNull Insets insets)96     public void onCarUiInsetsChanged(@NonNull Insets insets) {
97         // Overridden in subclasses
98     }
99 
getAppBarDefaultTitle(@ullable MediaSource mediaSource)100     CharSequence getAppBarDefaultTitle(@Nullable MediaSource mediaSource) {
101         return (mediaSource != null) ? mediaSource.getDisplayName()
102                 : mActivity.getResources().getString(R.string.media_app_title);
103     }
104 
105     class BasicAppBarListener extends AppBarController.AppBarListener {
106         @Override
onSettingsSelection()107         protected void onSettingsSelection() {
108             if (Log.isLoggable(TAG, Log.DEBUG)) {
109                 Log.d(TAG, "onSettingsSelection");
110             }
111             try {
112                 if (mCurrentSourcePreferences != null) {
113                     mActivity.startActivity(mCurrentSourcePreferences);
114                 }
115             } catch (ActivityNotFoundException e) {
116                 if (Log.isLoggable(TAG, Log.ERROR)) {
117                     Log.e(TAG, "onSettingsSelection " + e);
118                 }
119             }
120         }
121 
122         @Override
onEqualizerSelection()123         protected void onEqualizerSelection() {
124             Intent i = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
125             // Using startActivityForResult so that the control panel app can track changes for
126             // the launching package name.
127             mActivity.startActivityForResult(i, 0);
128         }
129     }
130 
131     @CallSuper
onMediaSourceChanged(@ullable MediaSource mediaSource)132     void onMediaSourceChanged(@Nullable MediaSource mediaSource) {
133         Resources res = mActivity.getResources();
134         Drawable icon = null;
135         Drawable searchIcon = null;
136         String packageName = null;
137         if (mediaSource != null) {
138             // Drawables can't be shared due to the fact that the layout manager effects the
139             // underlying Drawable causing artifacts when then are both "on screen"
140             icon = new BitmapDrawable(res, mediaSource.getCroppedPackageIcon());
141             searchIcon = new BitmapDrawable(res, mediaSource.getCroppedPackageIcon());
142             packageName = mediaSource.getPackageName();
143         }
144 
145         mAppBarController.setLogo(icon);
146         mAppBarController.setSearchIcon(searchIcon);
147         updateSourcePreferences(packageName);
148     }
149 
150     // TODO(b/136274938): display the preference screen for each media service.
updateSourcePreferences(@ullable String packageName)151     private void updateSourcePreferences(@Nullable String packageName) {
152         mCurrentSourcePreferences = null;
153         if (packageName != null) {
154             Intent prefsIntent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES);
155             prefsIntent.setPackage(packageName);
156             ResolveInfo info = mActivity.getPackageManager().resolveActivity(prefsIntent, 0);
157             if (info != null && info.activityInfo != null && info.activityInfo.exported) {
158                 mCurrentSourcePreferences = new Intent(prefsIntent.getAction())
159                         .setClassName(info.activityInfo.packageName, info.activityInfo.name);
160                 mAppBarController.setSettingsDistractionOptimized(
161                         CarPackageManagerUtils.isDistractionOptimized(
162                                 mCarPackageManager, info.activityInfo));
163             }
164         }
165         mAppBarController.setHasSettings(mCurrentSourcePreferences != null);
166         mAppBarController.setHasEqualizer(mShouldShowSoundSettings);
167     }
168 
169 
170 }
171