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