1 /*
2  * Copyright (C) 2020 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 package com.android.launcher3;
17 
18 import static android.content.Intent.EXTRA_COMPONENT_NAME;
19 import static android.content.Intent.EXTRA_USER;
20 
21 import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
22 
23 import android.content.ComponentName;
24 import android.content.Intent;
25 import android.graphics.RectF;
26 import android.os.Bundle;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.os.Messenger;
31 import android.os.RemoteException;
32 import android.os.UserHandle;
33 import android.util.Log;
34 import android.view.SurfaceControl;
35 
36 import androidx.annotation.NonNull;
37 import androidx.annotation.Nullable;
38 
39 import com.android.launcher3.views.ActivityContext;
40 
41 import java.lang.ref.WeakReference;
42 
43 /**
44  * Class to encapsulate the handshake protocol between Launcher and gestureNav.
45  */
46 public class GestureNavContract {
47 
48     private static final String TAG = "GestureNavContract";
49 
50     public static final String EXTRA_GESTURE_CONTRACT = "gesture_nav_contract_v1";
51     public static final String EXTRA_ICON_POSITION = "gesture_nav_contract_icon_position";
52     public static final String EXTRA_ICON_SURFACE = "gesture_nav_contract_surface_control";
53     public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
54     public static final String EXTRA_ON_FINISH_CALLBACK = "gesture_nav_contract_finish_callback";
55 
56     public final ComponentName componentName;
57     public final UserHandle user;
58 
59     private final Message mCallback;
60 
GestureNavContract(ComponentName componentName, UserHandle user, Message callback)61     public GestureNavContract(ComponentName componentName, UserHandle user, Message callback) {
62         this.componentName = componentName;
63         this.user = user;
64         this.mCallback = callback;
65     }
66 
67     /**
68      * Sends the position information to the receiver
69      */
sendEndPosition(RectF position, ActivityContext context, @Nullable SurfaceControl surfaceControl)70     public void sendEndPosition(RectF position, ActivityContext context,
71             @Nullable SurfaceControl surfaceControl) {
72         Bundle result = new Bundle();
73         result.putParcelable(EXTRA_ICON_POSITION, position);
74         result.putParcelable(EXTRA_ICON_SURFACE, surfaceControl);
75         if (sMessageReceiver == null) {
76             sMessageReceiver = new StaticMessageReceiver();
77         }
78         result.putParcelable(EXTRA_ON_FINISH_CALLBACK, sMessageReceiver.setCurrentContext(context));
79 
80         Message callback = Message.obtain();
81         callback.copyFrom(mCallback);
82         callback.setData(result);
83 
84         try {
85             callback.replyTo.send(callback);
86         } catch (RemoteException e) {
87             Log.e(TAG, "Error sending icon position", e);
88         }
89     }
90 
91     /**
92      * Clears and returns the GestureNavContract if it was present in the intent.
93      */
fromIntent(Intent intent)94     public static GestureNavContract fromIntent(Intent intent) {
95         Bundle extras = intent.getBundleExtra(EXTRA_GESTURE_CONTRACT);
96         if (extras == null) {
97             return null;
98         }
99         intent.removeExtra(EXTRA_GESTURE_CONTRACT);
100 
101         ComponentName componentName = extras.getParcelable(EXTRA_COMPONENT_NAME);
102         UserHandle userHandle = extras.getParcelable(EXTRA_USER);
103         Message callback = extras.getParcelable(EXTRA_REMOTE_CALLBACK);
104 
105         if (componentName != null && userHandle != null && callback != null
106                 && callback.replyTo != null) {
107             return new GestureNavContract(componentName, userHandle, callback);
108         }
109         return null;
110     }
111 
112     /**
113      * Message used for receiving gesture nav contract information. We use a static messenger to
114      * avoid leaking too make binders in case the receiving launcher does not handle the contract
115      * properly.
116      */
117     private static StaticMessageReceiver sMessageReceiver = null;
118 
119     private static class StaticMessageReceiver implements Handler.Callback {
120 
121         private static final int MSG_CLOSE_LAST_TARGET = 0;
122 
123         private final Messenger mMessenger =
124                 new Messenger(new Handler(Looper.getMainLooper(), this));
125 
126         private WeakReference<ActivityContext> mLastTarget = new WeakReference<>(null);
127 
setCurrentContext(ActivityContext context)128         public Message setCurrentContext(ActivityContext context) {
129             mLastTarget = new WeakReference<>(context);
130 
131             Message msg = Message.obtain();
132             msg.replyTo = mMessenger;
133             msg.what = MSG_CLOSE_LAST_TARGET;
134             return msg;
135         }
136 
137         @Override
handleMessage(@onNull Message message)138         public boolean handleMessage(@NonNull Message message) {
139             if (message.what == MSG_CLOSE_LAST_TARGET) {
140                 ActivityContext lastContext = mLastTarget.get();
141                 if (lastContext != null) {
142                     AbstractFloatingView.closeOpenViews(lastContext, false, TYPE_ICON_SURFACE);
143                 }
144                 return true;
145             }
146             return false;
147         }
148     }
149 }
150