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