1 /* 2 * Copyright (C) 2024 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.communal.util 18 19 import android.app.ActivityOptions 20 import android.app.PendingIntent 21 import android.content.Intent 22 import android.view.View 23 import android.widget.RemoteViews 24 import androidx.core.util.component1 25 import androidx.core.util.component2 26 import com.android.systemui.animation.ActivityTransitionAnimator 27 28 29 /** A delegate that can be used to launch activities from [RemoteViews] */ 30 class InteractionHandlerDelegate( 31 private val findViewToAnimate: (View) -> Boolean, 32 private val intentStarter: IntentStarter, 33 ) : RemoteViews.InteractionHandler { 34 35 /** 36 * Responsible for starting the pending intent for launching activities. 37 */ interfacenull38 fun interface IntentStarter { 39 fun startPendingIntent( 40 intent: PendingIntent, 41 fillInIntent: Intent, 42 activityOptions: ActivityOptions, 43 controller: ActivityTransitionAnimator.Controller?, 44 ): Boolean 45 } 46 onInteractionnull47 override fun onInteraction( 48 view: View, 49 pendingIntent: PendingIntent, 50 response: RemoteViews.RemoteResponse 51 ): Boolean { 52 val launchOptions = response.getLaunchOptions(view) 53 return when { 54 pendingIntent.isActivity -> { 55 // Forward the fill-in intent and activity options retrieved from the response 56 // to populate the pending intent, so that list items can launch respective 57 // activities. 58 val hostView = getNearestParent(view) 59 val animationController = 60 hostView?.let(ActivityTransitionAnimator.Controller::fromView) 61 val (fillInIntent, activityOptions) = launchOptions 62 intentStarter.startPendingIntent( 63 pendingIntent, 64 fillInIntent, 65 activityOptions, 66 animationController 67 ) 68 } 69 70 else -> RemoteViews.startPendingIntent(view, pendingIntent, launchOptions) 71 } 72 } 73 getNearestParentnull74 private fun getNearestParent(child: View): View? { 75 var view: Any? = child 76 while (view is View) { 77 if (findViewToAnimate(view)) return view 78 view = view.parent 79 } 80 return null 81 } 82 } 83