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.util.PackageManagerHelper.getPackageFilter; 20 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.res.Resources; 25 import android.util.Log; 26 27 import com.android.launcher3.touch.PagedOrientationHandler; 28 import com.android.launcher3.util.MainThreadInitializedObject; 29 30 import java.io.PrintWriter; 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /** 35 * Observer for the resource config that specifies the navigation bar mode. 36 */ 37 public class SysUINavigationMode { 38 39 public enum Mode { 40 THREE_BUTTONS(false, 0), 41 TWO_BUTTONS(true, 1), 42 NO_BUTTON(true, 2); 43 44 public final boolean hasGestures; 45 public final int resValue; 46 Mode(boolean hasGestures, int resValue)47 Mode(boolean hasGestures, int resValue) { 48 this.hasGestures = hasGestures; 49 this.resValue = resValue; 50 } 51 } 52 getMode(Context context)53 public static Mode getMode(Context context) { 54 return INSTANCE.get(context).getMode(); 55 } 56 57 public static final MainThreadInitializedObject<SysUINavigationMode> INSTANCE = 58 new MainThreadInitializedObject<>(SysUINavigationMode::new); 59 60 private static final String TAG = "SysUINavigationMode"; 61 62 private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; 63 private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = 64 "config_navBarInteractionMode"; 65 66 private final Context mContext; 67 private Mode mMode; 68 69 private final List<NavigationModeChangeListener> mChangeListeners = new ArrayList<>(); 70 SysUINavigationMode(Context context)71 public SysUINavigationMode(Context context) { 72 mContext = context; 73 initializeMode(); 74 75 mContext.registerReceiver(new BroadcastReceiver() { 76 @Override 77 public void onReceive(Context context, Intent intent) { 78 updateMode(); 79 } 80 }, getPackageFilter("android", ACTION_OVERLAY_CHANGED)); 81 } 82 83 /** Updates navigation mode when needed. */ updateMode()84 public void updateMode() { 85 Mode oldMode = mMode; 86 initializeMode(); 87 if (mMode != oldMode) { 88 dispatchModeChange(); 89 } 90 } 91 initializeMode()92 private void initializeMode() { 93 int modeInt = getSystemIntegerRes(mContext, NAV_BAR_INTERACTION_MODE_RES_NAME); 94 for(Mode m : Mode.values()) { 95 if (m.resValue == modeInt) { 96 mMode = m; 97 } 98 } 99 } 100 dispatchModeChange()101 private void dispatchModeChange() { 102 for (NavigationModeChangeListener listener : mChangeListeners) { 103 listener.onNavigationModeChanged(mMode); 104 } 105 } 106 addModeChangeListener(NavigationModeChangeListener listener)107 public Mode addModeChangeListener(NavigationModeChangeListener listener) { 108 mChangeListeners.add(listener); 109 return mMode; 110 } 111 removeModeChangeListener(NavigationModeChangeListener listener)112 public void removeModeChangeListener(NavigationModeChangeListener listener) { 113 mChangeListeners.remove(listener); 114 } 115 getMode()116 public Mode getMode() { 117 return mMode; 118 } 119 getSystemIntegerRes(Context context, String resName)120 private static int getSystemIntegerRes(Context context, String resName) { 121 Resources res = context.getResources(); 122 int resId = res.getIdentifier(resName, "integer", "android"); 123 124 if (resId != 0) { 125 return res.getInteger(resId); 126 } else { 127 Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?"); 128 return -1; 129 } 130 } 131 132 /** @return Whether we can remove the shelf from overview. */ removeShelfFromOverview(Context context)133 public static boolean removeShelfFromOverview(Context context) { 134 // The shelf is core to the two-button mode model, so we need to continue supporting it. 135 return getMode(context) != Mode.TWO_BUTTONS; 136 } 137 hideShelfInTwoButtonLandscape(Context context, PagedOrientationHandler pagedOrientationHandler)138 public static boolean hideShelfInTwoButtonLandscape(Context context, 139 PagedOrientationHandler pagedOrientationHandler) { 140 return getMode(context) == Mode.TWO_BUTTONS && 141 !pagedOrientationHandler.isLayoutNaturalToLauncher(); 142 } 143 dump(PrintWriter pw)144 public void dump(PrintWriter pw) { 145 pw.println("SysUINavigationMode:"); 146 pw.println(" mode=" + mMode.name()); 147 } 148 149 public interface NavigationModeChangeListener { 150 onNavigationModeChanged(Mode newMode)151 void onNavigationModeChanged(Mode newMode); 152 } 153 }