Bug 1126479 - Support fullscreen display mode for webapps on Android r=droeh draft
authorJames Willcox <snorp@snorp.net>
Tue, 08 Aug 2017 13:23:51 -0500
changeset 644384 8d219313478adfb392dac41b923945fb5d94af6a
parent 644383 e429047c6ab75f30a9ba049aa440d6243f9dd4db
child 725598 095af4dc81444f5b8142ad3b88af1fe9e3c6da29
push id73426
push userbmo:snorp@snorp.net
push dateThu, 10 Aug 2017 22:25:15 +0000
reviewersdroeh
bugs1126479
milestone57.0a1
Bug 1126479 - Support fullscreen display mode for webapps on Android r=droeh MozReview-Commit-ID: 8GfeYqLQqGC
mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ActivityUtils.java
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -35,28 +35,31 @@ import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoScreenOrientation;
 import org.mozilla.gecko.GeckoView;
 import org.mozilla.gecko.GeckoViewSettings;
 import org.mozilla.gecko.icons.decoders.FaviconDecoder;
 import org.mozilla.gecko.icons.decoders.LoadFaviconResult;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.util.ActivityUtils;
 import org.mozilla.gecko.util.ColorUtil;
 import org.mozilla.gecko.util.FileUtils;
 
 public class WebAppActivity extends AppCompatActivity {
     private static final String LOGTAG = "WebAppActivity";
 
     public static final String MANIFEST_PATH = "MANIFEST_PATH";
     private static final String SAVED_INTENT = "savedIntent";
 
     private GeckoView mGeckoView;
     private PromptService mPromptService;
 
+    private boolean mIsFullScreenMode;
+    private boolean mIsFullScreenContent;
     private Uri mScope;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 &&
             savedInstanceState != null) {
             // Even though we're a single task activity, Android's task switcher has the
             // annoying habit of never updating its stored intent after our initial creation,
@@ -67,16 +70,25 @@ public class WebAppActivity extends AppC
 
             Intent lastLaunchIntent = savedInstanceState.getParcelable(SAVED_INTENT);
             setIntent(lastLaunchIntent);
         }
 
         super.onCreate(savedInstanceState);
 
         mGeckoView = new GeckoView(this);
+        mGeckoView.setContentListener(new GeckoView.ContentListener() {
+            public void onTitleChange(GeckoView view, String title) {}
+            public void onContextMenu(GeckoView view, int screenX, int screenY,
+                               String uri, String elementSrc) {}
+            public void onFullScreen(GeckoView view, boolean fullScreen) {
+                updateFullScreenContent(fullScreen);
+            }
+        });
+
         mPromptService = new PromptService(this, mGeckoView.getEventDispatcher());
 
         final GeckoViewSettings settings = mGeckoView.getSettings();
         settings.setBoolean(GeckoViewSettings.USE_MULTIPROCESS, false);
 
         final Uri u = getIntent().getData();
         if (u != null) {
             mGeckoView.loadUri(u.toString());
@@ -102,32 +114,49 @@ public class WebAppActivity extends AppC
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
         outState.putParcelable(SAVED_INTENT, getIntent());
     }
 
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        if (hasFocus) {
+            updateFullScreen();
+        }
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (mIsFullScreenContent) {
+            mGeckoView.exitFullScreen();
+        } else {
+            super.onBackPressed();
+        }
+    }
+
     private void loadManifest(String manifestPath) {
         if (TextUtils.isEmpty(manifestPath)) {
             Log.e(LOGTAG, "Missing manifest");
             return;
         }
 
         try {
             final File manifestFile = new File(manifestPath);
             final JSONObject manifest = FileUtils.readJSONObjectFromFile(manifestFile);
             final JSONObject manifestField = manifest.getJSONObject("manifest");
 
             if (AppConstants.Versions.feature21Plus) {
                 loadManifestV21(manifest, manifestField);
             }
 
             updateScreenOrientation(manifestField);
+            updateDisplayMode(manifestField);
         } catch (IOException | JSONException e) {
             Log.e(LOGTAG, "Failed to read manifest", e);
         }
     }
 
     // The customisations defined in the manifest only work on Android API 21+
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private void loadManifestV21(JSONObject manifest, JSONObject manifestField) {
@@ -163,16 +192,18 @@ public class WebAppActivity extends AppC
         int activityOrientation = GeckoScreenOrientation.screenOrientationToAndroidOrientation(orientation);
 
         setRequestedOrientation(activityOrientation);
     }
 
     private void updateDisplayMode(JSONObject manifest) {
         String displayMode = manifest.optString("display");
 
+        updateFullScreenMode(displayMode.equals("fullscreen"));
+
         GeckoViewSettings.DisplayMode mode;
         switch (displayMode) {
             case "standalone":
                 mode = GeckoViewSettings.DisplayMode.STANDALONE;
                 break;
             case "fullscreen":
                 mode = GeckoViewSettings.DisplayMode.FULLSCREEN;
                 break;
@@ -260,9 +291,28 @@ public class WebAppActivity extends AppC
         for (int i = 0; i < scopeSegments.size(); i++) {
             if (!scopeSegments.get(i).equals(urlSegments.get(i))) {
                 return false;
             }
         }
 
         return true;
     }
+
+    private void updateFullScreen() {
+        boolean fullScreen = mIsFullScreenContent || mIsFullScreenMode;
+        if (ActivityUtils.isFullScreen(this) == fullScreen) {
+            return;
+        }
+
+        ActivityUtils.setFullScreen(this, fullScreen);
+    }
+
+    private void updateFullScreenContent(boolean fullScreen) {
+        mIsFullScreenContent = fullScreen;
+        updateFullScreen();
+    }
+
+    private void updateFullScreenMode(boolean fullScreen) {
+        mIsFullScreenMode = fullScreen;
+        updateFullScreen();
+    }
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ActivityUtils.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ActivityUtils.java
@@ -17,51 +17,40 @@ import android.view.WindowManager;
 public class ActivityUtils {
     private ActivityUtils() {
     }
 
     public static void setFullScreen(Activity activity, boolean fullscreen) {
         // Hide/show the system notification bar
         Window window = activity.getWindow();
 
-        if (Build.VERSION.SDK_INT >= 16) {
-            int newVis;
-            if (fullscreen) {
-                newVis = View.SYSTEM_UI_FLAG_FULLSCREEN;
-                if (Build.VERSION.SDK_INT >= 19) {
-                    newVis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
-                            View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
-                            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
-                            View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
-                            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-                } else {
-                    newVis |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
-                }
+        int newVis;
+        if (fullscreen) {
+            newVis = View.SYSTEM_UI_FLAG_FULLSCREEN;
+            if (Build.VERSION.SDK_INT >= 19) {
+                newVis |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+                        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+                        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
             } else {
-                newVis = View.SYSTEM_UI_FLAG_VISIBLE;
+                newVis |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
             }
-
-            window.getDecorView().setSystemUiVisibility(newVis);
         } else {
-            window.setFlags(fullscreen ?
-                            WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
-                            WindowManager.LayoutParams.FLAG_FULLSCREEN);
+            newVis = View.SYSTEM_UI_FLAG_VISIBLE;
         }
+
+        window.getDecorView().setSystemUiVisibility(newVis);
     }
 
     public static boolean isFullScreen(final Activity activity) {
         final Window window = activity.getWindow();
 
-        if (Build.VERSION.SDK_INT >= 16) {
-            final int vis = window.getDecorView().getSystemUiVisibility();
-            return (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
-        }
-
-        final int flags = window.getAttributes().flags;
-        return ((flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0);
+        final int vis = window.getDecorView().getSystemUiVisibility();
+        return (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
     }
 
     /**
      * Finish this activity and launch the default home screen activity.
      */
     public static void goToHomeScreen(Context context) {
         Intent intent = new Intent(Intent.ACTION_MAIN);