1 /* 2 * Copyright (C) 2022 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.complication; 18 19 import static com.android.systemui.complication.dagger.DreamMediaEntryComplicationComponent.DreamMediaEntryModule.DREAM_MEDIA_ENTRY_VIEW; 20 import static com.android.systemui.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_ENTRY_LAYOUT_PARAMS; 21 import static com.android.systemui.flags.Flags.DREAM_MEDIA_TAP_TO_OPEN; 22 23 import android.app.PendingIntent; 24 import android.util.Log; 25 import android.view.View; 26 27 import com.android.systemui.ActivityIntentHelper; 28 import com.android.systemui.complication.dagger.DreamMediaEntryComplicationComponent; 29 import com.android.systemui.dreams.DreamOverlayStateController; 30 import com.android.systemui.flags.FeatureFlags; 31 import com.android.systemui.media.controls.ui.MediaCarouselController; 32 import com.android.systemui.media.dream.MediaDreamComplication; 33 import com.android.systemui.plugins.ActivityStarter; 34 import com.android.systemui.statusbar.NotificationLockscreenUserManager; 35 import com.android.systemui.statusbar.policy.KeyguardStateController; 36 import com.android.systemui.util.ViewController; 37 38 import javax.inject.Inject; 39 import javax.inject.Named; 40 41 /** 42 * A dream complication that shows a media entry chip to launch media control view. 43 */ 44 public class DreamMediaEntryComplication implements Complication { 45 private final DreamMediaEntryComplicationComponent.Factory mComponentFactory; 46 47 @Inject DreamMediaEntryComplication( DreamMediaEntryComplicationComponent.Factory componentFactory)48 public DreamMediaEntryComplication( 49 DreamMediaEntryComplicationComponent.Factory componentFactory) { 50 mComponentFactory = componentFactory; 51 } 52 53 @Override createView(ComplicationViewModel model)54 public ViewHolder createView(ComplicationViewModel model) { 55 return mComponentFactory.create().getViewHolder(); 56 } 57 58 @Override getRequiredTypeAvailability()59 public int getRequiredTypeAvailability() { 60 return COMPLICATION_TYPE_MEDIA_ENTRY; 61 } 62 63 /** 64 * Contains values/logic associated with the dream complication view. 65 */ 66 public static class DreamMediaEntryViewHolder implements ViewHolder { 67 private final View mView; 68 private final ComplicationLayoutParams mLayoutParams; 69 private final DreamMediaEntryViewController mViewController; 70 71 @Inject DreamMediaEntryViewHolder( DreamMediaEntryViewController dreamMediaEntryViewController, @Named(DREAM_MEDIA_ENTRY_VIEW) View view, @Named(DREAM_MEDIA_ENTRY_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams )72 DreamMediaEntryViewHolder( 73 DreamMediaEntryViewController dreamMediaEntryViewController, 74 @Named(DREAM_MEDIA_ENTRY_VIEW) View view, 75 @Named(DREAM_MEDIA_ENTRY_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams 76 ) { 77 mView = view; 78 mLayoutParams = layoutParams; 79 mViewController = dreamMediaEntryViewController; 80 mViewController.init(); 81 } 82 83 @Override getView()84 public View getView() { 85 return mView; 86 } 87 88 @Override getLayoutParams()89 public ComplicationLayoutParams getLayoutParams() { 90 return mLayoutParams; 91 } 92 } 93 94 /** 95 * Controls behavior of the dream complication. 96 */ 97 static class DreamMediaEntryViewController extends ViewController<View> { 98 private static final String TAG = "DreamMediaEntryVwCtrl"; 99 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 100 101 private final DreamOverlayStateController mDreamOverlayStateController; 102 private final MediaDreamComplication mMediaComplication; 103 private final MediaCarouselController mMediaCarouselController; 104 105 private final ActivityStarter mActivityStarter; 106 private final ActivityIntentHelper mActivityIntentHelper; 107 private final KeyguardStateController mKeyguardStateController; 108 private final NotificationLockscreenUserManager mLockscreenUserManager; 109 110 private final FeatureFlags mFeatureFlags; 111 private boolean mIsTapToOpenEnabled; 112 113 private boolean mMediaComplicationAdded; 114 115 @Inject DreamMediaEntryViewController( @amedDREAM_MEDIA_ENTRY_VIEW) View view, DreamOverlayStateController dreamOverlayStateController, MediaDreamComplication mediaComplication, MediaCarouselController mediaCarouselController, ActivityStarter activityStarter, ActivityIntentHelper activityIntentHelper, KeyguardStateController keyguardStateController, NotificationLockscreenUserManager lockscreenUserManager, FeatureFlags featureFlags)116 DreamMediaEntryViewController( 117 @Named(DREAM_MEDIA_ENTRY_VIEW) View view, 118 DreamOverlayStateController dreamOverlayStateController, 119 MediaDreamComplication mediaComplication, 120 MediaCarouselController mediaCarouselController, 121 ActivityStarter activityStarter, 122 ActivityIntentHelper activityIntentHelper, 123 KeyguardStateController keyguardStateController, 124 NotificationLockscreenUserManager lockscreenUserManager, 125 FeatureFlags featureFlags) { 126 super(view); 127 mDreamOverlayStateController = dreamOverlayStateController; 128 mMediaComplication = mediaComplication; 129 mMediaCarouselController = mediaCarouselController; 130 mActivityStarter = activityStarter; 131 mActivityIntentHelper = activityIntentHelper; 132 mKeyguardStateController = keyguardStateController; 133 mLockscreenUserManager = lockscreenUserManager; 134 mFeatureFlags = featureFlags; 135 mView.setOnClickListener(this::onClickMediaEntry); 136 } 137 138 @Override onViewAttached()139 protected void onViewAttached() { 140 mIsTapToOpenEnabled = mFeatureFlags.isEnabled(DREAM_MEDIA_TAP_TO_OPEN); 141 } 142 143 @Override onViewDetached()144 protected void onViewDetached() { 145 removeMediaComplication(); 146 } 147 onClickMediaEntry(View v)148 private void onClickMediaEntry(View v) { 149 if (DEBUG) Log.d(TAG, "media entry complication tapped"); 150 151 if (mIsTapToOpenEnabled) { 152 final PendingIntent clickIntent = 153 mMediaCarouselController.getCurrentVisibleMediaContentIntent(); 154 155 if (clickIntent == null) { 156 return; 157 } 158 159 // See StatusBarNotificationActivityStarter#onNotificationClicked 160 final boolean showOverLockscreen = mKeyguardStateController.isShowing() 161 && mActivityIntentHelper.wouldShowOverLockscreen(clickIntent.getIntent(), 162 mLockscreenUserManager.getCurrentUserId()); 163 164 if (showOverLockscreen) { 165 mActivityStarter.startActivity(clickIntent.getIntent(), 166 /* dismissShade */ true, 167 /* animationController */ null, 168 /* showOverLockscreenWhenLocked */ true); 169 } else { 170 mActivityStarter.postStartActivityDismissingKeyguard(clickIntent, null); 171 } 172 173 return; 174 } 175 176 if (!mMediaComplicationAdded) { 177 addMediaComplication(); 178 } else { 179 removeMediaComplication(); 180 } 181 } 182 addMediaComplication()183 private void addMediaComplication() { 184 mView.setSelected(true); 185 mDreamOverlayStateController.addComplication(mMediaComplication); 186 mMediaComplicationAdded = true; 187 } 188 removeMediaComplication()189 private void removeMediaComplication() { 190 mView.setSelected(false); 191 mDreamOverlayStateController.removeComplication(mMediaComplication); 192 mMediaComplicationAdded = false; 193 } 194 } 195 } 196