1 /*
2  * Copyright (C) 2022 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 android.app;
18 
19 import static android.app.Activity.FULLSCREEN_MODE_REQUEST_ENTER;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
22 
23 import android.annotation.IntDef;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.content.res.Configuration;
27 import android.os.Bundle;
28 import android.os.IBinder;
29 import android.os.IRemoteCallback;
30 import android.os.OutcomeReceiver;
31 
32 /**
33  * @hide
34  */
35 public class FullscreenRequestHandler {
36     @IntDef(prefix = { "RESULT_" }, value = {
37             RESULT_APPROVED,
38             RESULT_FAILED_NOT_IN_FREEFORM,
39             RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY,
40             RESULT_FAILED_NOT_DEFAULT_FREEFORM,
41             RESULT_FAILED_NOT_TOP_FOCUSED
42     })
43     public @interface RequestResult {}
44 
45     public static final int RESULT_APPROVED = 0;
46     public static final int RESULT_FAILED_NOT_IN_FREEFORM = 1;
47     public static final int RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY = 2;
48     public static final int RESULT_FAILED_NOT_DEFAULT_FREEFORM = 3;
49     public static final int RESULT_FAILED_NOT_TOP_FOCUSED = 4;
50 
51     public static final String REMOTE_CALLBACK_RESULT_KEY = "result";
52 
requestFullscreenMode(@onNull @ctivity.FullscreenModeRequest int request, @Nullable OutcomeReceiver<Void, Throwable> approvalCallback, Configuration config, IBinder token)53     static void requestFullscreenMode(@NonNull @Activity.FullscreenModeRequest int request,
54             @Nullable OutcomeReceiver<Void, Throwable> approvalCallback, Configuration config,
55             IBinder token) {
56         int earlyCheck = earlyCheckRequestMatchesWindowingMode(
57                 request, config.windowConfiguration.getWindowingMode());
58         if (earlyCheck != RESULT_APPROVED) {
59             if (approvalCallback != null) {
60                 notifyFullscreenRequestResult(approvalCallback, earlyCheck);
61             }
62             return;
63         }
64         try {
65             if (approvalCallback != null) {
66                 ActivityClient.getInstance().requestMultiwindowFullscreen(token, request,
67                         new IRemoteCallback.Stub() {
68                             @Override
69                             public void sendResult(Bundle res) {
70                                 notifyFullscreenRequestResult(
71                                         approvalCallback, res.getInt(REMOTE_CALLBACK_RESULT_KEY));
72                             }
73                         });
74             } else {
75                 ActivityClient.getInstance().requestMultiwindowFullscreen(token, request, null);
76             }
77         } catch (Throwable e) {
78             if (approvalCallback != null) {
79                 approvalCallback.onError(e);
80             }
81         }
82     }
83 
notifyFullscreenRequestResult( OutcomeReceiver<Void, Throwable> callback, int result)84     private static void notifyFullscreenRequestResult(
85             OutcomeReceiver<Void, Throwable> callback, int result) {
86         Throwable e = null;
87         switch (result) {
88             case RESULT_FAILED_NOT_IN_FREEFORM:
89                 e = new IllegalStateException("The window is not a freeform window, the request "
90                         + "to get into fullscreen cannot be approved.");
91                 break;
92             case RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY:
93                 e = new IllegalStateException("The window is not in fullscreen by calling the "
94                         + "requestFullscreenMode API before, such that cannot be restored.");
95                 break;
96             case RESULT_FAILED_NOT_DEFAULT_FREEFORM:
97                 e = new IllegalStateException("The window is not launched in freeform by default.");
98                 break;
99             case RESULT_FAILED_NOT_TOP_FOCUSED:
100                 e = new IllegalStateException("The window is not the top focused window.");
101                 break;
102             default:
103                 callback.onResult(null);
104                 break;
105         }
106         if (e != null) {
107             callback.onError(e);
108         }
109     }
110 
earlyCheckRequestMatchesWindowingMode(int request, int windowingMode)111     private static int earlyCheckRequestMatchesWindowingMode(int request, int windowingMode) {
112         if (request == FULLSCREEN_MODE_REQUEST_ENTER) {
113             if (windowingMode != WINDOWING_MODE_FREEFORM) {
114                 return RESULT_FAILED_NOT_IN_FREEFORM;
115             }
116         } else {
117             if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
118                 return RESULT_FAILED_NOT_IN_FULLSCREEN_WITH_HISTORY;
119             }
120         }
121         return RESULT_APPROVED;
122     }
123 }
124