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.quickstep.util; 17 18 import static android.view.Surface.ROTATION_0; 19 import static android.view.Surface.ROTATION_180; 20 21 import android.annotation.TargetApi; 22 import android.content.Context; 23 import android.os.Build; 24 import android.view.WindowManager; 25 import android.view.WindowMetrics; 26 27 import androidx.annotation.NonNull; 28 import androidx.annotation.Nullable; 29 import androidx.annotation.UiThread; 30 31 import com.android.launcher3.R; 32 import com.android.launcher3.util.DisplayController; 33 import com.android.launcher3.util.WindowBounds; 34 35 import java.util.ArrayList; 36 37 /** 38 * Utility class to hold the information abound a window bounds for split screen 39 */ 40 @TargetApi(Build.VERSION_CODES.R) 41 public class SplitScreenBounds { 42 43 public static final SplitScreenBounds INSTANCE = new SplitScreenBounds(); 44 private final ArrayList<OnChangeListener> mListeners = new ArrayList<>(); 45 46 @Nullable 47 private WindowBounds mBounds; 48 SplitScreenBounds()49 private SplitScreenBounds() { } 50 51 @UiThread setSecondaryWindowBounds(@onNull WindowBounds bounds)52 public void setSecondaryWindowBounds(@NonNull WindowBounds bounds) { 53 if (!bounds.equals(mBounds)) { 54 mBounds = bounds; 55 for (OnChangeListener listener : mListeners) { 56 listener.onSecondaryWindowBoundsChanged(); 57 } 58 } 59 } 60 getSecondaryWindowBounds(Context context)61 public @NonNull WindowBounds getSecondaryWindowBounds(Context context) { 62 if (mBounds == null) { 63 mBounds = createDefaultWindowBounds(context); 64 } 65 return mBounds; 66 } 67 68 /** 69 * Creates window bounds as 50% of device size 70 */ createDefaultWindowBounds(Context context)71 private static WindowBounds createDefaultWindowBounds(Context context) { 72 WindowMetrics wm = context.getSystemService(WindowManager.class).getMaximumWindowMetrics(); 73 WindowBounds bounds = WindowBounds.fromWindowMetrics(wm); 74 75 int rotation = DisplayController.INSTANCE.get(context).getInfo().rotation; 76 int halfDividerSize = context.getResources() 77 .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2; 78 79 if (rotation == ROTATION_0 || rotation == ROTATION_180) { 80 bounds.bounds.top = bounds.insets.top + bounds.availableSize.y / 2 + halfDividerSize; 81 bounds.insets.top = 0; 82 } else { 83 bounds.bounds.left = bounds.insets.left + bounds.availableSize.x / 2 + halfDividerSize; 84 bounds.insets.left = 0; 85 } 86 return new WindowBounds(bounds.bounds, bounds.insets); 87 } 88 addOnChangeListener(OnChangeListener listener)89 public void addOnChangeListener(OnChangeListener listener) { 90 mListeners.add(listener); 91 } 92 removeOnChangeListener(OnChangeListener listener)93 public void removeOnChangeListener(OnChangeListener listener) { 94 mListeners.remove(listener); 95 } 96 97 /** 98 * Interface to receive window bounds changes 99 */ 100 public interface OnChangeListener { 101 102 /** 103 * Called when window bounds for secondary window changes 104 */ onSecondaryWindowBoundsChanged()105 void onSecondaryWindowBoundsChanged(); 106 } 107 } 108