• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.systemui.statusbar;
18 
19 import android.content.Context;
20 import android.content.res.ColorStateList;
21 import android.graphics.drawable.Drawable;
22 import android.graphics.drawable.GradientDrawable;
23 import android.graphics.drawable.RippleDrawable;
24 import android.service.notification.StatusBarNotification;
25 import android.util.FeatureFlagUtils;
26 import android.util.Log;
27 import android.view.View;
28 import android.view.ViewGroup;
29 import android.view.ViewParent;
30 import android.widget.ImageView;
31 import android.widget.LinearLayout;
32 import android.widget.TextView;
33 
34 import com.android.settingslib.bluetooth.LocalBluetoothManager;
35 import com.android.settingslib.media.InfoMediaManager;
36 import com.android.settingslib.media.LocalMediaManager;
37 import com.android.settingslib.media.MediaDevice;
38 import com.android.settingslib.widget.AdaptiveIcon;
39 import com.android.systemui.Dependency;
40 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
41 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
42 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
43 
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 /**
48  * Class for handling MediaTransfer state over a set of notifications.
49  */
50 public class MediaTransferManager {
51     private final Context mContext;
52     private final MediaOutputDialogFactory mMediaOutputDialogFactory;
53     private MediaDevice mDevice;
54     private List<View> mViews = new ArrayList<>();
55     private LocalMediaManager mLocalMediaManager;
56 
57     private static final String TAG = "MediaTransferManager";
58 
59     private final View.OnClickListener mOnClickHandler = new View.OnClickListener() {
60         @Override
61         public void onClick(View view) {
62             if (handleMediaTransfer(view)) {
63                 return;
64             }
65         }
66 
67         private boolean handleMediaTransfer(View view) {
68             if (view.findViewById(com.android.internal.R.id.media_seamless) == null) {
69                 return false;
70             }
71 
72             ViewParent parent = view.getParent();
73             StatusBarNotification statusBarNotification =
74                     getRowForParent(parent).getEntry().getSbn();
75             mMediaOutputDialogFactory.create(statusBarNotification.getPackageName(), true);
76             return true;
77         }
78     };
79 
80     private final LocalMediaManager.DeviceCallback mMediaDeviceCallback =
81             new LocalMediaManager.DeviceCallback() {
82         @Override
83         public void onDeviceListUpdate(List<MediaDevice> devices) {
84             MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
85             // Check because this can be called several times while changing devices
86             if (mDevice == null || !mDevice.equals(currentDevice)) {
87                 mDevice = currentDevice;
88                 updateAllChips();
89             }
90         }
91 
92         @Override
93         public void onSelectedDeviceStateChanged(MediaDevice device, int state) {
94             if (mDevice == null || !mDevice.equals(device)) {
95                 mDevice = device;
96                 updateAllChips();
97             }
98         }
99     };
100 
MediaTransferManager(Context context)101     public MediaTransferManager(Context context) {
102         mContext = context;
103         mMediaOutputDialogFactory = Dependency.get(MediaOutputDialogFactory.class);
104         LocalBluetoothManager lbm = Dependency.get(LocalBluetoothManager.class);
105         InfoMediaManager imm = new InfoMediaManager(mContext, null, null, lbm);
106         mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, null);
107     }
108 
109     /**
110      * Mark a view as removed. If no views remain the media device listener will be unregistered.
111      * @param root
112      */
setRemoved(View root)113     public void setRemoved(View root) {
114         if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)
115                 || mLocalMediaManager == null || root == null) {
116             return;
117         }
118         View view = root.findViewById(com.android.internal.R.id.media_seamless);
119         if (mViews.remove(view)) {
120             if (mViews.size() == 0) {
121                 mLocalMediaManager.unregisterCallback(mMediaDeviceCallback);
122             }
123         } else {
124             Log.e(TAG, "Tried to remove unknown view " + view);
125         }
126     }
127 
getRowForParent(ViewParent parent)128     private ExpandableNotificationRow getRowForParent(ViewParent parent) {
129         while (parent != null) {
130             if (parent instanceof ExpandableNotificationRow) {
131                 return ((ExpandableNotificationRow) parent);
132             }
133             parent = parent.getParent();
134         }
135         return null;
136     }
137 
138     /**
139      * apply the action button for MediaTransfer
140      *
141      * @param root  The parent container of the view.
142      * @param entry The entry of MediaTransfer action button.
143      */
applyMediaTransferView(ViewGroup root, NotificationEntry entry)144     public void applyMediaTransferView(ViewGroup root, NotificationEntry entry) {
145         if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SEAMLESS_TRANSFER)
146                 || mLocalMediaManager == null || root == null) {
147             return;
148         }
149 
150         View view = root.findViewById(com.android.internal.R.id.media_seamless);
151         if (view == null) {
152             return;
153         }
154 
155         view.setVisibility(View.VISIBLE);
156         view.setOnClickListener(mOnClickHandler);
157         if (!mViews.contains(view)) {
158             mViews.add(view);
159             if (mViews.size() == 1) {
160                 mLocalMediaManager.registerCallback(mMediaDeviceCallback);
161             }
162         }
163 
164         // Initial update
165         mLocalMediaManager.startScan();
166         mDevice = mLocalMediaManager.getCurrentConnectedDevice();
167         updateChip(view);
168     }
169 
updateAllChips()170     private void updateAllChips() {
171         for (View view : mViews) {
172             updateChip(view);
173         }
174     }
175 
updateChip(View view)176     private void updateChip(View view) {
177         ExpandableNotificationRow enr = getRowForParent(view.getParent());
178         int fgColor = enr.getNotificationHeader().getOriginalIconColor();
179         ColorStateList fgTintList = ColorStateList.valueOf(fgColor);
180         int bgColor = enr.getCurrentBackgroundTint();
181 
182         // Update outline color
183         LinearLayout viewLayout = (LinearLayout) view;
184         RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground();
185         GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
186         rect.setStroke(2, fgColor);
187         rect.setColor(bgColor);
188 
189         ImageView iconView = view.findViewById(com.android.internal.R.id.media_seamless_image);
190         TextView deviceName = view.findViewById(com.android.internal.R.id.media_seamless_text);
191         deviceName.setTextColor(fgTintList);
192 
193         if (mDevice != null) {
194             Drawable icon = mDevice.getIcon();
195             iconView.setVisibility(View.VISIBLE);
196             iconView.setImageTintList(fgTintList);
197 
198             if (icon instanceof AdaptiveIcon) {
199                 AdaptiveIcon aIcon = (AdaptiveIcon) icon;
200                 aIcon.setBackgroundColor(bgColor);
201                 iconView.setImageDrawable(aIcon);
202             } else {
203                 iconView.setImageDrawable(icon);
204             }
205             deviceName.setText(mDevice.getName());
206         } else {
207             // Reset to default
208             iconView.setVisibility(View.GONE);
209             deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
210         }
211     }
212 }
213