Add "Use physical keyboard" option to system bar IME button.

Bug: 3391067
Change-Id: I136087ca4f726d0068d5983d7d3686787ba60c55
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 1a2f867..5ada77b 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -53,11 +53,13 @@
  * if they are local, that they just enqueue messages to not deadlock.
  */
 public class StatusBarManagerService extends IStatusBarService.Stub
+    implements WindowManagerService.OnHardKeyboardStatusChangeListener
 {
     static final String TAG = "StatusBarManagerService";
     static final boolean SPEW = false;
 
     final Context mContext;
+    final WindowManagerService mWindowManager;
     Handler mHandler = new Handler();
     NotificationCallbacks mNotificationCallbacks;
     volatile IStatusBar mBar;
@@ -103,8 +105,10 @@
     /**
      * Construct the service, add the status bar view to the window manager
      */
-    public StatusBarManagerService(Context context) {
+    public StatusBarManagerService(Context context, WindowManagerService windowManager) {
         mContext = context;
+        mWindowManager = windowManager;
+        mWindowManager.setOnHardKeyboardStatusChangeListener(this);
 
         final Resources res = context.getResources();
         mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
@@ -320,6 +324,28 @@
         }
     }
 
+    public void setHardKeyboardEnabled(final boolean enabled) {
+        mHandler.post(new Runnable() {
+            public void run() {
+                mWindowManager.setHardKeyboardEnabled(enabled);
+            }
+        });
+    }
+
+    @Override
+    public void onHardKeyboardStatusChange(final boolean available, final boolean enabled) {
+        mHandler.post(new Runnable() {
+            public void run() {
+                if (mBar != null) {
+                    try {
+                        mBar.setHardKeyboardStatus(available, enabled);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        });
+    }
+
     private void enforceStatusBar() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
                 "StatusBarManagerService");
@@ -335,7 +361,6 @@
                 "StatusBarManagerService");
     }
 
-
     // ================================================================================
     // Callbacks from the status bar service.
     // ================================================================================
@@ -363,6 +388,8 @@
             switches[4] = mImeBackDisposition;
             binders.add(mImeToken);
         }
+        switches[5] = mWindowManager.isHardKeyboardAvailable() ? 1 : 0;
+        switches[6] = mWindowManager.isHardKeyboardEnabled() ? 1 : 0;
     }
 
     /**
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 978946f..92ec1da 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -248,7 +248,7 @@
 
             try {
                 Slog.i(TAG, "Status Bar");
-                statusBar = new StatusBarManagerService(context);
+                statusBar = new StatusBarManagerService(context, wm);
                 ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
             } catch (Throwable e) {
                 Slog.e(TAG, "Failure starting StatusBarManagerService", e);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index faaa28d7..b850804 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -454,6 +454,10 @@
     WindowState mInputMethodWindow = null;
     final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
 
+    boolean mHardKeyboardAvailable;
+    boolean mHardKeyboardEnabled;
+    OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
+
     final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
 
     // If non-null, this is the currently visible window that is associated
@@ -5776,9 +5780,64 @@
         config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
         config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
         mPolicy.adjustConfigurationLw(config);
+
+        // Adjust the hard keyboard configuration based on whether the hard keyboard is enabled.
+        boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
+        if (hardKeyboardAvailable != mHardKeyboardAvailable) {
+            mHardKeyboardAvailable = hardKeyboardAvailable;
+            mHardKeyboardEnabled = hardKeyboardAvailable;
+
+            mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+            mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+        }
+        if (!mHardKeyboardEnabled) {
+            config.keyboard = Configuration.KEYBOARD_NOKEYS;
+            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
+        }
         return true;
     }
 
+    public boolean isHardKeyboardAvailable() {
+        synchronized (mWindowMap) {
+            return mHardKeyboardAvailable;
+        }
+    }
+
+    public boolean isHardKeyboardEnabled() {
+        synchronized (mWindowMap) {
+            return mHardKeyboardEnabled;
+        }
+    }
+
+    public void setHardKeyboardEnabled(boolean enabled) {
+        synchronized (mWindowMap) {
+            if (mHardKeyboardEnabled != enabled) {
+                mHardKeyboardEnabled = enabled;
+                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+            }
+        }
+    }
+
+    public void setOnHardKeyboardStatusChangeListener(
+            OnHardKeyboardStatusChangeListener listener) {
+        synchronized (mWindowMap) {
+            mHardKeyboardStatusChangeListener = listener;
+        }
+    }
+
+    void notifyHardKeyboardStatusChange() {
+        final boolean available, enabled;
+        final OnHardKeyboardStatusChangeListener listener;
+        synchronized (mWindowMap) {
+            listener = mHardKeyboardStatusChangeListener;
+            available = mHardKeyboardAvailable;
+            enabled = mHardKeyboardEnabled;
+        }
+        if (listener != null) {
+            listener.onHardKeyboardStatusChange(available, enabled);
+        }
+    }
+
     // -------------------------------------------------------------
     // Drag and drop
     // -------------------------------------------------------------
@@ -8869,6 +8928,7 @@
         public static final int REPORT_WINDOWS_CHANGE = 19;
         public static final int DRAG_START_TIMEOUT = 20;
         public static final int DRAG_END_TIMEOUT = 21;
+        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
 
         private Session mLastReportedHold;
 
@@ -9242,6 +9302,11 @@
                     }
                     break;
                 }
+
+                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
+                    notifyHardKeyboardStatusChange();
+                    break;
+                }
             }
         }
     }
@@ -11988,4 +12053,8 @@
             return Animation.ZORDER_TOP;
         }
     }
+
+    public interface OnHardKeyboardStatusChangeListener {
+        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
+    }
 }