Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1224)

Unified Diff: remoting/android/java/src/org/chromium/chromoting/Desktop.java

Issue 1427453004: Fixing image canvas resize problems when showing/hiding system UI. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing some comment formatting. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/android/java/src/org/chromium/chromoting/Desktop.java
diff --git a/remoting/android/java/src/org/chromium/chromoting/Desktop.java b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
index ef9c582a3be8d6c67d1b947877b05e72e3c84784..b906a87b80b6bacaec05f5ee65192dbb2b6ae7b2 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Desktop.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Desktop.java
@@ -11,6 +11,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
@@ -20,6 +21,7 @@ import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.View.OnLayoutChangeListener;
import android.view.inputmethod.InputMethodManager;
import org.chromium.chromoting.cardboard.DesktopActivity;
@@ -40,8 +42,10 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
* Preference used for displaying an interestitial dialog only when the user first accesses the
* Cardboard function.
*/
- private static final String PREFERENCE_CARDBOARD_DIALOG_SEEN =
- "cardboard_dialog_seen";
+ private static final String PREFERENCE_CARDBOARD_DIALOG_SEEN = "cardboard_dialog_seen";
+
+ /** The amount of time to wait to hide the Actionbar after user input is seen. */
+ private static final int ACTIONBAR_AUTO_HIDE_DELAY_MS = 5000;
/** The surface that displays the remote host's desktop feed. */
private DesktopView mRemoteHostDesktop;
@@ -51,10 +55,15 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
private ActivityLifecycleListener mActivityLifecycleListener;
- // Flag to indicate whether the current activity is going to switch to Cardboard
- // desktop activity.
+ /** Flag to indicate whether the current activity is switching to Cardboard desktop activity. */
private boolean mSwitchToCardboardDesktopActivity;
+ /** Indicates whether a Soft Input UI (such as a keyboard) is visible. */
+ private boolean mSoftInputVisible = false;
+
+ /** Holds the scheduled task object which will be called to hide the ActionBar. */
+ private Runnable mActionBarAutoHideTask;
+
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -78,9 +87,19 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener(this);
- mActivityLifecycleListener = CapabilityManager.getInstance()
- .onActivityAcceptingListener(this, Capabilities.CAST_CAPABILITY);
+ mActivityLifecycleListener = CapabilityManager.getInstance().onActivityAcceptingListener(
+ this, Capabilities.CAST_CAPABILITY);
mActivityLifecycleListener.onActivityCreated(this, savedInstanceState);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ // The action bar is already shown when the activity is started however calling the
+ // function below will set our preferred system UI flags which will adjust the layout
+ // size of the canvas and we can avoid an initial resize event.
+ showActionBar();
+ attachKeyboardVisibilityListener();
+ } else {
+ mRemoteHostDesktop.setFitsSystemWindows(true);
+ }
}
@Override
@@ -98,6 +117,7 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
if (!mSwitchToCardboardDesktopActivity) {
JniInterface.enableVideoChannel(false);
}
+ stopActionBarAutoHideTimer();
}
@Override
@@ -105,6 +125,7 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
super.onResume();
mActivityLifecycleListener.onActivityResumed(this);
JniInterface.enableVideoChannel(true);
+ startActionBarAutoHideTimer();
}
@Override
@@ -127,8 +148,8 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
boolean enableCardboard = false;
try {
- ApplicationInfo ai = getPackageManager()
- .getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
+ ApplicationInfo ai = getPackageManager().getApplicationInfo(
+ getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
enableCardboard = bundle.getInt("enable_cardboard") == 1;
} catch (NameNotFoundException e) {
@@ -143,6 +164,41 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
return super.onCreateOptionsMenu(menu);
}
+ // Posts a deplayed task to hide the ActionBar. If an existing task has already been scheduled,
+ // then the previous task is removed and the new one scheduled, effectively resetting the timer.
+ private void startActionBarAutoHideTimer() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ // The required flags for immersive full screen are not supported on pre-KitKat builds
+ // so don't enable the auto-hide timer for them as every transition on older versions
+ // causes resizing of the canvas and we want to minimize the number of layout changes.
+ return;
+ }
+
+ if (mActionBarAutoHideTask != null) {
+ stopActionBarAutoHideTimer();
+ }
+
+ mActionBarAutoHideTask = new Runnable() {
Lambros 2015/10/29 23:39:16 optional: Don't really need to keep setting mActio
joedow 2015/10/30 17:41:22 Done.
+ public void run() {
+ hideActionBar();
+ }
+ };
+
+ View decorView = getWindow().getDecorView();
+ decorView.postDelayed(mActionBarAutoHideTask, ACTIONBAR_AUTO_HIDE_DELAY_MS);
+ }
+
+ // Clear an existing delayed task to prevent the ActionBar from being hidden.
+ private void stopActionBarAutoHideTimer() {
+ if (mActionBarAutoHideTask == null) {
+ return;
+ }
+
+ View decorView = getWindow().getDecorView();
+ decorView.removeCallbacks(mActionBarAutoHideTask);
+ mActionBarAutoHideTask = null;
+ }
+
/** Called whenever the visibility of the system status bar or navigation bar changes. */
@Override
public void onSystemUiVisibilityChange(int visibility) {
@@ -176,12 +232,26 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
// to the SystemUiVisibility notification. The visibility of the action-bar should be tied
// to the fullscreen state of the system, so there's no need to explicitly show it here.
View decorView = getWindow().getDecorView();
- decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+ int flags = View.SYSTEM_UI_FLAG_VISIBLE;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ flags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
Lambros 2015/10/29 23:39:16 Since these are duplicated below, maybe have a get
joedow 2015/10/30 17:41:23 Done.
+ flags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ flags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+ }
+ decorView.setSystemUiVisibility(flags);
+
+ // The OS will not call onSystemUiVisibilityChange() if the keyboard is visible which means
+ // our ActionBar will not be visible until then. This check allows us to work around this
+ // issue and still allow the system to show the ActionBar normally with the soft keyboard.
+ if (mSoftInputVisible) {
+ showActionBarWithoutSystemUi();
+ }
}
/** Shows the action bar without changing SystemUiVisibility. */
private void showActionBarWithoutSystemUi() {
getSupportActionBar().show();
+ startActionBarAutoHideTimer();
}
@SuppressLint("InlinedApi")
@@ -204,15 +274,28 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
// keeping the navigation controls hidden. This flag was introduced in 4.4, later than
// HIDE_NAVIGATION, and so a runtime check is needed before setting either of these flags.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- flags |= (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE);
+ flags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ flags |= View.SYSTEM_UI_FLAG_IMMERSIVE;
+ flags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ flags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ flags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
}
decorView.setSystemUiVisibility(flags);
+
+ // The OS will not call onSystemUiVisibilityChange() until the keyboard has been dismissed
+ // which means our ActionBar will still be visible. This check allows us to work around
+ // this issue when the keyboard is visible and the user wants additional space on the screen
+ // and still allow the system to hide the ActionBar normally when no keyboard is present.
+ if (mSoftInputVisible) {
+ hideActionBarWithoutSystemUi();
+ }
}
/** Hides the action bar without changing SystemUiVisibility. */
private void hideActionBarWithoutSystemUi() {
getSupportActionBar().hide();
+ stopActionBarAutoHideTimer();
}
/** Called whenever an action bar button is pressed. */
@@ -222,6 +305,9 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
mActivityLifecycleListener.onActivityOptionsItemSelected(this, item);
+ // Whenever a user selects an option from the ActionBar, reset the auto-hide timer.
+ startActionBarAutoHideTimer();
+
if (id == R.id.actionbar_cardboard) {
onCardboardItemSelected();
return true;
@@ -240,9 +326,8 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
}
if (id == R.id.actionbar_send_ctrl_alt_del) {
int[] keys = {
- KeyEvent.KEYCODE_CTRL_LEFT,
- KeyEvent.KEYCODE_ALT_LEFT,
- KeyEvent.KEYCODE_FORWARD_DEL,
+ KeyEvent.KEYCODE_CTRL_LEFT, KeyEvent.KEYCODE_ALT_LEFT,
+ KeyEvent.KEYCODE_FORWARD_DEL,
};
for (int key : keys) {
JniInterface.sendKeyEvent(0, key, true);
@@ -259,6 +344,35 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
return super.onOptionsItemSelected(item);
}
+ private void attachKeyboardVisibilityListener() {
+ View keyboardVisibilityDetector = findViewById(R.id.resize_detector);
+ keyboardVisibilityDetector.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ // Represents the initial size of the viewable area sans the soft keyboard.
+ private Rect mInitialRect;
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ if (mInitialRect == null || bottom > mInitialRect.bottom) {
Lambros 2015/10/29 23:39:16 Maybe initialize mInitialRect and mutate it instea
joedow 2015/10/30 17:41:22 Done.
+ // When the activity is started fresh we will see a single layout change event,
+ // however if we are transitioning between orientations and the keyboard was
+ // previously visible, we might receive several layout changes sequentially.
+ mInitialRect = new Rect(left, top, right, bottom);
+ return;
+ }
+
+ // If the delta between lowest bound we have seen (should be a systemUI such as
+ // the navigation bar) and the current bound does not match, then we have a form
+ // of soft input displayed. Note that the size of a soft input device can change
+ // when the input method is changed so we want to send updates to the image canvas
+ // whenever they occur.
+ mSoftInputVisible = ((mInitialRect.bottom - bottom) > 0);
Lambros 2015/10/29 23:39:16 Maybe replace Rect with int, since you only use |b
joedow 2015/10/30 17:41:22 Done.
+ mRemoteHostDesktop.onSoftInputMethodVisibilityChanged(
+ mSoftInputVisible, new Rect(left, top, right, bottom));
+ }
+ });
+ }
+
private void onCardboardItemSelected() {
if (getPreferences(MODE_PRIVATE).getBoolean(PREFERENCE_CARDBOARD_DIALOG_SEEN, false)) {
switchToCardboardMode();
@@ -269,21 +383,22 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
.setTitle(getTitle())
.setMessage(R.string.cardboard_warning_message)
.setIcon(R.drawable.ic_cardboard)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- getPreferences(MODE_PRIVATE)
- .edit()
- .putBoolean(PREFERENCE_CARDBOARD_DIALOG_SEEN, true)
- .apply();
- switchToCardboardMode();
- }
- })
- .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- }
- })
+ .setPositiveButton(android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ getPreferences(MODE_PRIVATE)
+ .edit()
+ .putBoolean(PREFERENCE_CARDBOARD_DIALOG_SEEN, true)
+ .apply();
+ switchToCardboardMode();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {}
+ })
.create()
.show();
}
@@ -336,12 +451,12 @@ public class Desktop extends AppCompatActivity implements View.OnSystemUiVisibil
// want to send it as KeyEvent.
int unicode = keyCode != KeyEvent.KEYCODE_ENTER ? event.getUnicodeChar() : 0;
- boolean no_modifiers = !event.isAltPressed()
- && !event.isCtrlPressed() && !event.isMetaPressed();
+ boolean no_modifiers =
+ !event.isAltPressed() && !event.isCtrlPressed() && !event.isMetaPressed();
if (pressed && unicode != 0 && no_modifiers) {
mPressedTextKeys.add(keyCode);
- int[] codePoints = { unicode };
+ int[] codePoints = {unicode};
JniInterface.sendTextEvent(new String(codePoints, 0, 1));
return true;
}

Powered by Google App Engine
This is Rietveld 408576698