diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml index e902c925c2a9c..b5d48b4636a89 100644 --- a/packages/SystemUI/res/layout/remote_input.xml +++ b/packages/SystemUI/res/layout/remote_input.xml @@ -42,7 +42,7 @@ android:singleLine="true" android:ellipsize="start" android:inputType="textShortMessage|textAutoCorrect|textCapSentences" - android:imeOptions="actionSend" /> + android:imeOptions="actionSend|flagNoExtractUi|flagNoFullscreen" /> new NotificationEntryManager(context)); providers.put(KeyguardDismissUtil.class, KeyguardDismissUtil::new); providers.put(SmartReplyController.class, () -> new SmartReplyController()); + providers.put(RemoteInputQuickSettingsDisabler.class, + () -> new RemoteInputQuickSettingsDisabler(context)); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index cbd1ca1b771da..b146cfccf180b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -35,6 +35,7 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.FrameLayout.LayoutParams; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.R.id; @@ -43,6 +44,7 @@ import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.stack.StackStateAnimator; public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks { @@ -72,6 +74,9 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks { private float mLastQSExpansion = -1; private boolean mQsDisabled; + private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler = + Dependency.get(RemoteInputQuickSettingsDisabler.class); + @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { @@ -191,6 +196,8 @@ public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks { @Override public void disable(int state1, int state2, boolean animate) { + state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2); + final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0; if (disabled == mQsDisabled) return; mQsDisabled = disabled; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 9eeb4d250d995..fe4db446b54b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -233,6 +233,7 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.PreviewInflater; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -398,6 +399,9 @@ public class StatusBar extends SystemUI implements DemoMode, private View mPendingRemoteInputView; private View mPendingWorkRemoteInputView; + private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler = + Dependency.get(RemoteInputQuickSettingsDisabler.class); + private View mReportRejectedTouch; private int mMaxAllowedKeyguardNotifications; @@ -1750,6 +1754,8 @@ public class StatusBar extends SystemUI implements DemoMode, */ @Override public void disable(int state1, int state2, boolean animate) { + state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2); + animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN; final int old1 = mDisabled1; final int diff1 = state1 ^ old1; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java new file mode 100644 index 0000000000000..c2933e1516be6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import android.app.StatusBarManager; +import android.content.Context; +import android.content.res.Configuration; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.Dependency; +import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.qs.QSFragment; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.StatusBar; + +/** + * Let {@link RemoteInputView} to control the visibility of QuickSetting. + */ +public class RemoteInputQuickSettingsDisabler + implements ConfigurationController.ConfigurationListener { + + private Context mContext; + @VisibleForTesting boolean mRemoteInputActive; + @VisibleForTesting boolean misLandscape; + private int mLastOrientation; + @VisibleForTesting CommandQueue mCommandQueue; + + public RemoteInputQuickSettingsDisabler(Context context) { + mContext = context; + mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class); + mLastOrientation = mContext.getResources().getConfiguration().orientation; + Dependency.get(ConfigurationController.class).addCallback(this); + } + + public int adjustDisableFlags(int state) { + if (mRemoteInputActive && misLandscape) { + state |= StatusBarManager.DISABLE2_QUICK_SETTINGS; + } + + return state; + } + + public void setRemoteInputActive(boolean active){ + if(mRemoteInputActive != active){ + mRemoteInputActive = active; + recomputeDisableFlags(); + } + } + + @Override + public void onConfigChanged(Configuration newConfig) { + if (newConfig.orientation != mLastOrientation) { + misLandscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE; + mLastOrientation = newConfig.orientation; + recomputeDisableFlags(); + } + } + + /** + * Reapplies the disable flags. Then the method adjustDisableFlags in this class will be invoked + * in {@link QSFragment#disable(int, int, boolean)} and + * {@link StatusBar#disable(int, int, boolean)} + * to modify the disable flags according to the status of mRemoteInputActive and misLandscape. + */ + private void recomputeDisableFlags() { + mCommandQueue.recomputeDisableFlags(true); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index 310f14c2fca70..afa35bd1caf2c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -53,6 +53,7 @@ import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.NotificationData; @@ -81,6 +82,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene private RemoteInput[] mRemoteInputs; private RemoteInput mRemoteInput; private RemoteInputController mController; + private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private NotificationData.Entry mEntry; @@ -96,6 +98,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene public RemoteInputView(Context context, AttributeSet attrs) { super(context, attrs); + mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class); } @Override @@ -232,6 +235,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene } } } + + mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false); + MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE, mEntry.notification.getPackageName()); } @@ -291,6 +297,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mEditText.setSelection(mEditText.getText().length()); mEditText.requestFocus(); mController.addRemoteInput(mEntry, mToken); + + mRemoteInputQuickSettingsDisabler.setRemoteInputActive(true); + updateSendButton(); } @@ -553,6 +562,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene return super.onKeyUp(keyCode, event); } + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { + mRemoteInputView.mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false); + } + return super.dispatchKeyEvent(event); + } + @Override public boolean onCheckIsTextEditor() { // Stop being editable while we're being removed. During removal, we get reattached, @@ -565,11 +582,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { final InputConnection inputConnection = super.onCreateInputConnection(outAttrs); - //if pinned, set imeOption to keep the behavior like in portrait. - if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isPinned()) { - outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI - | EditorInfo.IME_FLAG_NO_FULLSCREEN; - } if (mShowImeOnInputConnection && inputConnection != null) { final InputMethodManager imm = InputMethodManager.getInstance(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java new file mode 100644 index 0000000000000..3b47eae03fa02 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import static com.google.common.truth.Truth.assertThat; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.content.res.Configuration; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.CommandQueue; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase { + + private CommandQueue mCommandQueue; + private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mCommandQueue = mock(CommandQueue.class); + mContext.putComponent(CommandQueue.class, mCommandQueue); + + mRemoteInputQuickSettingsDisabler = new RemoteInputQuickSettingsDisabler(mContext); + } + + @Test + public void shouldEnableQuickSetting_afterDeactiviate() { + mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE); + mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE); + assertFalse(mRemoteInputQuickSettingsDisabler.mRemoteInputActive); + verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean()); + } + + @Test + public void shouldDisableQuickSetting_afteActiviate() { + mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE); + mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE); + assertTrue(mRemoteInputQuickSettingsDisabler.mRemoteInputActive); + verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean()); + } + + @Test + public void testChangeToLandscape() { + Configuration c = new Configuration(mContext.getResources().getConfiguration()); + c.orientation = Configuration.ORIENTATION_PORTRAIT; + mRemoteInputQuickSettingsDisabler.onConfigChanged(c); + c.orientation = Configuration.ORIENTATION_LANDSCAPE; + mRemoteInputQuickSettingsDisabler.onConfigChanged(c); + assertTrue(mRemoteInputQuickSettingsDisabler.misLandscape); + verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean()); + } + + @Test + public void testChangeToPortrait() { + Configuration c = new Configuration(mContext.getResources().getConfiguration()); + c.orientation = Configuration.ORIENTATION_LANDSCAPE; + mRemoteInputQuickSettingsDisabler.onConfigChanged(c); + c.orientation = Configuration.ORIENTATION_PORTRAIT; + mRemoteInputQuickSettingsDisabler.onConfigChanged(c); + assertFalse(mRemoteInputQuickSettingsDisabler.misLandscape); + verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean()); + } + +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java index 7e1aba57f87bf..d902793f89359 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java @@ -52,6 +52,7 @@ public class RemoteInputViewTest extends SysuiTestCase { @Mock private RemoteInputController mController; @Mock private ShortcutManager mShortcutManager; + @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private BlockingQueueIntentReceiver mReceiver; private RemoteInputView mView; @@ -59,6 +60,9 @@ public class RemoteInputViewTest extends SysuiTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mDependency.injectTestDependency(RemoteInputQuickSettingsDisabler.class, + mRemoteInputQuickSettingsDisabler); + mReceiver = new BlockingQueueIntentReceiver(); mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));