• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.util;
17 
18 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
19 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
20 
21 import android.annotation.SuppressLint;
22 import android.app.Activity;
23 import android.content.Context;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Message;
28 import android.view.View;
29 import android.view.inputmethod.InputMethodManager;
30 
31 import com.android.launcher3.Launcher;
32 import com.android.launcher3.views.ActivityContext;
33 
34 /**
35  * Utility class for offloading some class from UI thread
36  */
37 public class UiThreadHelper {
38 
39     private static final MainThreadInitializedObject<Handler> HANDLER =
40             new MainThreadInitializedObject<>(
41                     c -> new Handler(UI_HELPER_EXECUTOR.getLooper(), new UiCallbacks(c)));
42 
43     private static final int MSG_HIDE_KEYBOARD = 1;
44     private static final int MSG_SET_ORIENTATION = 2;
45     private static final int MSG_RUN_COMMAND = 3;
46     private static final String STATS_LOGGER_KEY = "STATS_LOGGER_KEY";
47 
48     @SuppressLint("NewApi")
hideKeyboardAsync(ActivityContext activityContext, IBinder token)49     public static void hideKeyboardAsync(ActivityContext activityContext, IBinder token) {
50         View root = activityContext.getDragLayer();
51 
52         // Since the launcher context cannot be accessed directly from callback, adding secondary
53         // message to log keyboard close event asynchronously.
54         Bundle mHideKeyboardLoggerMsg = new Bundle();
55         mHideKeyboardLoggerMsg.putParcelable(
56                 STATS_LOGGER_KEY,
57                 Message.obtain(
58                         HANDLER.get(root.getContext()),
59                         () -> Launcher.cast(activityContext)
60                                 .getStatsLogManager()
61                                 .logger()
62                                 .log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED)
63                 )
64         );
65 
66         Message mHideKeyboardMsg = Message.obtain(HANDLER.get(root.getContext()), MSG_HIDE_KEYBOARD,
67                 token);
68         mHideKeyboardMsg.setData(mHideKeyboardLoggerMsg);
69         mHideKeyboardMsg.sendToTarget();
70     }
71 
setOrientationAsync(Activity activity, int orientation)72     public static void setOrientationAsync(Activity activity, int orientation) {
73         Message.obtain(HANDLER.get(activity), MSG_SET_ORIENTATION, orientation, 0, activity)
74                 .sendToTarget();
75     }
76 
setBackButtonAlphaAsync(Context context, AsyncCommand command, float alpha, boolean animate)77     public static void setBackButtonAlphaAsync(Context context, AsyncCommand command, float alpha,
78             boolean animate) {
79         runAsyncCommand(context, command, Float.floatToIntBits(alpha), animate ? 1 : 0);
80     }
81 
runAsyncCommand(Context context, AsyncCommand command, int arg1, int arg2)82     public static void runAsyncCommand(Context context, AsyncCommand command, int arg1, int arg2) {
83         Message.obtain(HANDLER.get(context), MSG_RUN_COMMAND, arg1, arg2, command).sendToTarget();
84     }
85 
86     private static class UiCallbacks implements Handler.Callback {
87 
88         private final Context mContext;
89         private final InputMethodManager mIMM;
90 
UiCallbacks(Context context)91         UiCallbacks(Context context) {
92             mContext = context;
93             mIMM = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
94         }
95 
96         @Override
handleMessage(Message message)97         public boolean handleMessage(Message message) {
98             switch (message.what) {
99                 case MSG_HIDE_KEYBOARD:
100                     if (mIMM.hideSoftInputFromWindow((IBinder) message.obj, 0)) {
101                         // log keyboard close event only when keyboard is actually closed
102                         ((Message) message.getData().getParcelable(STATS_LOGGER_KEY))
103                                 .sendToTarget();
104                     }
105                     return true;
106                 case MSG_SET_ORIENTATION:
107                     ((Activity) message.obj).setRequestedOrientation(message.arg1);
108                     return true;
109                 case MSG_RUN_COMMAND:
110                     ((AsyncCommand) message.obj).execute(mContext, message.arg1, message.arg2);
111                     return true;
112             }
113             return false;
114         }
115     }
116 
117     public interface AsyncCommand {
execute(Context proxy, int arg1, int arg2)118         void execute(Context proxy, int arg1, int arg2);
119     }
120 }
121