1 /* 2 * Copyright (C) 2019 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 com.android.quickstep; 18 19 import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE; 20 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_2_BUTTON; 21 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_3_BUTTON; 22 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON; 23 import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter; 24 25 import android.content.BroadcastReceiver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.util.Log; 29 30 import com.android.launcher3.ResourceUtils; 31 import com.android.launcher3.logging.StatsLogManager.LauncherEvent; 32 import com.android.launcher3.util.MainThreadInitializedObject; 33 34 import java.io.PrintWriter; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.concurrent.CopyOnWriteArrayList; 38 39 /** 40 * Observer for the resource config that specifies the navigation bar mode. 41 */ 42 public class SysUINavigationMode { 43 44 public enum Mode { 45 THREE_BUTTONS(false, 0, LAUNCHER_NAVIGATION_MODE_3_BUTTON), 46 TWO_BUTTONS(true, 1, LAUNCHER_NAVIGATION_MODE_2_BUTTON), 47 NO_BUTTON(true, 2, LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON); 48 49 public final boolean hasGestures; 50 public final int resValue; 51 public final LauncherEvent launcherEvent; 52 Mode(boolean hasGestures, int resValue, LauncherEvent launcherEvent)53 Mode(boolean hasGestures, int resValue, LauncherEvent launcherEvent) { 54 this.hasGestures = hasGestures; 55 this.resValue = resValue; 56 this.launcherEvent = launcherEvent; 57 } 58 } 59 getMode(Context context)60 public static Mode getMode(Context context) { 61 return INSTANCE.get(context).getMode(); 62 } 63 64 public static final MainThreadInitializedObject<SysUINavigationMode> INSTANCE = 65 new MainThreadInitializedObject<>(SysUINavigationMode::new); 66 67 private static final String TAG = "SysUINavigationMode"; 68 private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; 69 private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = 70 "config_navBarInteractionMode"; 71 private static final String TARGET_OVERLAY_PACKAGE = "android"; 72 73 private final Context mContext; 74 private Mode mMode; 75 76 private int mNavBarGesturalHeight; 77 private int mNavBarLargerGesturalHeight; 78 79 private final List<NavigationModeChangeListener> mChangeListeners = 80 new CopyOnWriteArrayList<>(); 81 private final List<OneHandedModeChangeListener> mOneHandedOverlayChangeListeners = 82 new ArrayList<>(); 83 SysUINavigationMode(Context context)84 public SysUINavigationMode(Context context) { 85 mContext = context; 86 initializeMode(); 87 88 mContext.registerReceiver(new BroadcastReceiver() { 89 @Override 90 public void onReceive(Context context, Intent intent) { 91 updateMode(); 92 updateGesturalHeight(); 93 } 94 }, getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED)); 95 } 96 97 /** Updates navigation mode when needed. */ updateMode()98 public void updateMode() { 99 Mode oldMode = mMode; 100 initializeMode(); 101 if (mMode != oldMode) { 102 dispatchModeChange(); 103 } 104 } 105 updateGesturalHeight()106 private void updateGesturalHeight() { 107 int newGesturalHeight = ResourceUtils.getDimenByName( 108 ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mContext.getResources(), 109 INVALID_RESOURCE_HANDLE); 110 111 if (newGesturalHeight == INVALID_RESOURCE_HANDLE) { 112 Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?"); 113 return; 114 } 115 116 if (mNavBarGesturalHeight != newGesturalHeight) { 117 mNavBarGesturalHeight = newGesturalHeight; 118 } 119 120 int newLargerGesturalHeight = ResourceUtils.getDimenByName( 121 ResourceUtils.NAVBAR_BOTTOM_GESTURE_LARGER_SIZE, mContext.getResources(), 122 INVALID_RESOURCE_HANDLE); 123 if (newLargerGesturalHeight == INVALID_RESOURCE_HANDLE) { 124 Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?"); 125 return; 126 } 127 if (mNavBarLargerGesturalHeight != newLargerGesturalHeight) { 128 mNavBarLargerGesturalHeight = newLargerGesturalHeight; 129 dispatchOneHandedOverlayChange(); 130 } 131 } 132 initializeMode()133 private void initializeMode() { 134 int modeInt = ResourceUtils.getIntegerByName(NAV_BAR_INTERACTION_MODE_RES_NAME, 135 mContext.getResources(), INVALID_RESOURCE_HANDLE); 136 mNavBarGesturalHeight = ResourceUtils.getDimenByName( 137 ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mContext.getResources(), 138 INVALID_RESOURCE_HANDLE); 139 mNavBarLargerGesturalHeight = ResourceUtils.getDimenByName( 140 ResourceUtils.NAVBAR_BOTTOM_GESTURE_LARGER_SIZE, mContext.getResources(), 141 mNavBarGesturalHeight); 142 143 if (modeInt == INVALID_RESOURCE_HANDLE) { 144 Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?"); 145 return; 146 } 147 148 for (Mode m : Mode.values()) { 149 if (m.resValue == modeInt) { 150 mMode = m; 151 } 152 } 153 } 154 dispatchModeChange()155 private void dispatchModeChange() { 156 for (NavigationModeChangeListener listener : mChangeListeners) { 157 listener.onNavigationModeChanged(mMode); 158 } 159 } 160 dispatchOneHandedOverlayChange()161 private void dispatchOneHandedOverlayChange() { 162 for (OneHandedModeChangeListener listener : mOneHandedOverlayChangeListeners) { 163 listener.onOneHandedModeChanged(mNavBarLargerGesturalHeight); 164 } 165 } 166 addModeChangeListener(NavigationModeChangeListener listener)167 public Mode addModeChangeListener(NavigationModeChangeListener listener) { 168 mChangeListeners.add(listener); 169 return mMode; 170 } 171 removeModeChangeListener(NavigationModeChangeListener listener)172 public void removeModeChangeListener(NavigationModeChangeListener listener) { 173 mChangeListeners.remove(listener); 174 } 175 addOneHandedOverlayChangeListener(OneHandedModeChangeListener listener)176 public int addOneHandedOverlayChangeListener(OneHandedModeChangeListener listener) { 177 mOneHandedOverlayChangeListeners.add(listener); 178 return mNavBarLargerGesturalHeight; 179 } 180 removeOneHandedOverlayChangeListener(OneHandedModeChangeListener listener)181 public void removeOneHandedOverlayChangeListener(OneHandedModeChangeListener listener) { 182 mOneHandedOverlayChangeListeners.remove(listener); 183 } 184 getMode()185 public Mode getMode() { 186 return mMode; 187 } 188 dump(PrintWriter pw)189 public void dump(PrintWriter pw) { 190 pw.println("SysUINavigationMode:"); 191 pw.println(" mode=" + mMode.name()); 192 pw.println(" mNavBarGesturalHeight=:" + mNavBarGesturalHeight); 193 } 194 195 public interface NavigationModeChangeListener { onNavigationModeChanged(Mode newMode)196 void onNavigationModeChanged(Mode newMode); 197 } 198 199 public interface OneHandedModeChangeListener { onOneHandedModeChanged(int newGesturalHeight)200 void onOneHandedModeChanged(int newGesturalHeight); 201 } 202 } 203