Bug 1415994 - 6. Implement GeckoDisplay in GeckoView; r?snorp draft
authorJim Chen <nchen@mozilla.com>
Thu, 09 Nov 2017 16:55:11 -0500
changeset 695813 522f73b8bb8dba3cd572777cb95cec50dc2a9ff3
parent 695812 95efd7cd82944df21781850f18064464eb978d0e
child 695814 3562e6baa5d35e1cae82ee238bb7c18b0b6e83dd
push id88550
push userbmo:nchen@mozilla.com
push dateThu, 09 Nov 2017 21:56:18 +0000
reviewerssnorp
bugs1415994
milestone58.0a1
Bug 1415994 - 6. Implement GeckoDisplay in GeckoView; r?snorp Make GeckoView implement GeckoDisplay for its own SurfaceView, and use that with GeckoSession. MozReview-Commit-ID: LXllQGlCxaB
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
@@ -1,36 +1,44 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * vim: ts=4 sw=4 expandtab:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
+import org.mozilla.gecko.gfx.GeckoDisplay;
 import org.mozilla.gecko.gfx.LayerView;
 
 import android.content.Context;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 
 public class GeckoView extends LayerView {
     private static final String LOGTAG = "GeckoView";
     private static final boolean DEBUG = false;
 
+    private final Display mDisplay = new Display();
     protected GeckoSession mSession;
     private boolean mStateSaved;
 
+    protected SurfaceView mSurfaceView;
+
     private InputConnectionListener mInputConnectionListener;
     private boolean mIsResettingFocus;
 
     private static class SavedState extends BaseSavedState {
         public final GeckoSession session;
 
         public SavedState(final Parcelable superState, final GeckoSession session) {
             super(superState);
@@ -56,59 +64,157 @@ public class GeckoView extends LayerView
 
             @Override
             public SavedState[] newArray(final int size) {
                 return new SavedState[size];
             }
         };
     }
 
-    public GeckoView(Context context) {
-        super(context);
-        initializeView();
+    private class Display implements GeckoDisplay,
+                                     SurfaceHolder.Callback {
+        private Listener mListener;
+        private boolean mValid;
+
+        @Override // GeckoDisplay
+        public Listener getListener() {
+            return mListener;
+        }
+
+        @Override // GeckoDisplay
+        public void setListener(final Listener listener) {
+            if (mValid && mListener != null) {
+                // Tell old listener the surface is gone.
+                mListener.surfaceDestroyed();
+            }
+
+            mListener = listener;
+
+            if (!mValid || listener == null) {
+                return;
+            }
+
+            // Tell new listener there is already a surface.
+            if (GeckoView.this.mSurfaceView != null) {
+                final SurfaceHolder holder = GeckoView.this.mSurfaceView.getHolder();
+                final Rect frame = holder.getSurfaceFrame();
+                listener.surfaceChanged(holder.getSurface(), frame.right, frame.bottom);
+            }
+        }
+
+        @Override // GeckoDisplay
+        public boolean getOriginOnScreen(final int[] origin) {
+            if (GeckoView.this.mSurfaceView != null) {
+                GeckoView.this.mSurfaceView.getLocationOnScreen(origin);
+                return true;
+            }
+            return false;
+        }
+
+        @Override // SurfaceHolder.Callback
+        public void surfaceCreated(final SurfaceHolder holder) {
+            mValid = true;
+        }
+
+        @Override // SurfaceHolder.Callback
+        public void surfaceChanged(final SurfaceHolder holder, final int format,
+                                   final int width, final int height) {
+            if (mListener != null) {
+                mListener.surfaceChanged(holder.getSurface(), width, height);
+            }
+        }
+
+        @Override // SurfaceHolder.Callback
+        public void surfaceDestroyed(final SurfaceHolder holder) {
+            if (mListener != null) {
+                mListener.surfaceDestroyed();
+            }
+            mValid = false;
+        }
     }
 
-    public GeckoView(Context context, AttributeSet attrs) {
+    public GeckoView(final Context context) {
+        super(context);
+        init();
+    }
+
+    public GeckoView(final Context context, final AttributeSet attrs) {
         super(context, attrs);
+        init();
+    }
+
+    private void init() {
         initializeView();
+
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+
+        // We are adding descendants to this LayerView, but we don't want the
+        // descendants to affect the way LayerView retains its focus.
+        setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
+
+        // This will stop PropertyAnimator from creating a drawing cache (i.e. a
+        // bitmap) from a SurfaceView, which is just not possible (the bitmap will be
+        // transparent).
+        setWillNotCacheDrawing(false);
+
+        mSurfaceView = new SurfaceView(getContext());
+        mSurfaceView.setBackgroundColor(Color.WHITE);
+        addView(mSurfaceView,
+                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                           ViewGroup.LayoutParams.MATCH_PARENT));
+
+        mSurfaceView.getHolder().addCallback(mDisplay);
+    }
+
+    @Override
+    public void setSurfaceBackgroundColor(final int newColor) {
+        if (mSurfaceView != null) {
+            mSurfaceView.setBackgroundColor(newColor);
+        }
     }
 
     public void setSession(final GeckoSession session) {
         if (mSession != null && mSession.isOpen()) {
             throw new IllegalStateException("Current session is open");
         }
+
+        if (mSession != null) {
+            mSession.removeDisplay(mDisplay);
+        }
+        if (session != null) {
+            session.addDisplay(mDisplay);
+        }
+
         mSession = session;
     }
 
     public GeckoSession getSession() {
         return mSession;
     }
 
     public EventDispatcher getEventDispatcher() {
         return mSession.getEventDispatcher();
     }
 
     public GeckoSessionSettings getSettings() {
         return mSession.getSettings();
     }
 
-    protected Object getCompositor() {
-        return super.getCompositor();
-    }
-
     @Override
     public void onAttachedToWindow() {
         if (mSession == null) {
-            mSession = new GeckoSession();
+            setSession(new GeckoSession());
         }
 
         if (!mSession.isOpen()) {
             mSession.openWindow(getContext().getApplicationContext());
         }
         mSession.attachView(this);
+        attachCompositor(mSession);
 
         super.onAttachedToWindow();
     }
 
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         super.destroy();
@@ -137,17 +243,17 @@ public class GeckoView extends LayerView
             super.onRestoreInstanceState(state);
             return;
         }
 
         final SavedState ss = (SavedState) state;
         super.onRestoreInstanceState(ss.getSuperState());
 
         if (mSession == null) {
-            mSession = ss.session;
+            setSession(ss.session);
         } else if (ss.session != null) {
             mSession.transferFrom(ss.session);
         }
     }
 
     /* package */ void setInputConnectionListener(final InputConnectionListener icl) {
         mInputConnectionListener = icl;
     }