blob: 9ef6edc6cfc97f8f8445feee877477dbd2b1f83b [file] [log] [blame]
Sunny Goyal30ac97d2020-06-24 23:47:46 -07001/*
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 */
16package com.android.launcher3;
17
18import static android.content.Intent.EXTRA_COMPONENT_NAME;
19import static android.content.Intent.EXTRA_USER;
20
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070021import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
22
Sunny Goyal30ac97d2020-06-24 23:47:46 -070023import android.content.ComponentName;
24import android.content.Intent;
25import android.graphics.RectF;
Sunny Goyal30ac97d2020-06-24 23:47:46 -070026import android.os.Bundle;
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070027import android.os.Handler;
28import android.os.Looper;
Sunny Goyal30ac97d2020-06-24 23:47:46 -070029import android.os.Message;
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070030import android.os.Messenger;
Sunny Goyal30ac97d2020-06-24 23:47:46 -070031import android.os.RemoteException;
32import android.os.UserHandle;
33import android.util.Log;
34import android.view.SurfaceControl;
35
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070036import androidx.annotation.NonNull;
Sunny Goyal30ac97d2020-06-24 23:47:46 -070037import androidx.annotation.Nullable;
38
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070039import com.android.launcher3.views.ActivityContext;
40
41import java.lang.ref.WeakReference;
42
Sunny Goyal30ac97d2020-06-24 23:47:46 -070043/**
44 * Class to encapsulate the handshake protocol between Launcher and gestureNav.
45 */
46public 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";
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070054 public static final String EXTRA_ON_FINISH_CALLBACK = "gesture_nav_contract_finish_callback";
Sunny Goyal30ac97d2020-06-24 23:47:46 -070055
56 public final ComponentName componentName;
57 public final UserHandle user;
58
59 private final Message mCallback;
60
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 */
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070070 public void sendEndPosition(RectF position, ActivityContext context,
71 @Nullable SurfaceControl surfaceControl) {
Sunny Goyal30ac97d2020-06-24 23:47:46 -070072 Bundle result = new Bundle();
73 result.putParcelable(EXTRA_ICON_POSITION, position);
74 result.putParcelable(EXTRA_ICON_SURFACE, surfaceControl);
Sunny Goyal5c20fdd2022-04-05 20:58:03 -070075 if (sMessageReceiver == null) {
76 sMessageReceiver = new StaticMessageReceiver();
77 }
78 result.putParcelable(EXTRA_ON_FINISH_CALLBACK, sMessageReceiver.setCurrentContext(context));
Sunny Goyal30ac97d2020-06-24 23:47:46 -070079
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 */
94 public static GestureNavContract fromIntent(Intent intent) {
Sunny Goyal30ac97d2020-06-24 23:47:46 -070095 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 }
Sunny Goyal5c20fdd2022-04-05 20:58:03 -0700111
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
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
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 }
Sunny Goyal30ac97d2020-06-24 23:47:46 -0700149}