From 37fd65f106cbf77d52f36c9a05cab5c5237b62bb Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Thu, 18 May 2017 17:40:32 -0400 Subject: [PATCH] Bug 1365120 - Add WakeLockDelegate; r=rbarker Add and use WakeLockDelegate within GeckoView code to replace the notifyWakeLockChanged method in GeckoInterface. Fennec will use the default implementation in GeckoView, while GeckoView users are free to override the default implementation through GeckoAppShell.setWakeLockDelegate. MozReview-Commit-ID: I8S8q2RZRMu --- .../base/java/org/mozilla/gecko/GeckoApp.java | 35 --------- mobile/android/base/moz.build | 1 + .../org/mozilla/gecko/BaseGeckoInterface.java | 4 - .../java/org/mozilla/gecko/GeckoAppShell.java | 74 +++++++++++++++++-- .../org/mozilla/gecko/WakeLockDelegate.java | 43 +++++++++++ 5 files changed, 110 insertions(+), 47 deletions(-) create mode 100644 mobile/android/geckoview/src/main/java/org/mozilla/gecko/WakeLockDelegate.java diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java index cfcfa840d0a6..9df6bc032909 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -52,7 +52,6 @@ import org.mozilla.gecko.widget.AnchoredPopup; import android.animation.Animator; import android.animation.ObjectAnimator; -import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; @@ -74,7 +73,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; -import android.os.PowerManager; import android.os.StrictMode; import android.provider.ContactsContract; import android.provider.MediaStore.Images.Media; @@ -216,8 +214,6 @@ public abstract class GeckoApp extends GeckoActivity private FullScreenHolder mFullScreenPluginContainer; private View mFullScreenPluginView; - private final HashMap mWakeLocks = new HashMap(); - protected boolean mLastSessionCrashed; protected boolean mShouldRestore; private boolean mSessionRestoreParsingFinished = false; @@ -2878,37 +2874,6 @@ public abstract class GeckoApp extends GeckoActivity Permissions.onRequestPermissionsResult(this, permissions, grantResults); } - private static final String CPU = "cpu"; - private static final String SCREEN = "screen"; - - // Called when a Gecko Hal WakeLock is changed - @Override - // We keep the wake lock independent from the function scope, so we need to - // suppress the linter warning. - @SuppressLint("Wakelock") - public void notifyWakeLockChanged(String topic, String state) { - PowerManager.WakeLock wl = mWakeLocks.get(topic); - if (state.equals("locked-foreground") && wl == null) { - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - - if (CPU.equals(topic)) { - wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, topic); - } else if (SCREEN.equals(topic)) { - // ON_AFTER_RELEASE is set, the user activity timer will be reset when the - // WakeLock is released, causing the illumination to remain on a bit longer. - wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, topic); - } - - if (wl != null) { - wl.acquire(); - mWakeLocks.put(topic, wl); - } - } else if (!state.equals("locked-foreground") && wl != null) { - wl.release(); - mWakeLocks.remove(topic); - } - } - private void geckoConnected() { mLayerView.setOverScrollMode(View.OVER_SCROLL_NEVER); } diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index b2acb121f720..b20576b38b88 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -435,6 +435,7 @@ gvjar.sources += [geckoview_source_dir + 'java/org/mozilla/gecko/' + x 'sqlite/SQLiteBridge.java', 'sqlite/SQLiteBridgeException.java', 'TouchEventInterceptor.java', + 'WakeLockDelegate.java', ]] gvjar.sources += [geckoview_thirdparty_source_dir + f for f in [ diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/BaseGeckoInterface.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/BaseGeckoInterface.java index 28c7cd14354e..16013d85ad42 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/BaseGeckoInterface.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/BaseGeckoInterface.java @@ -34,10 +34,6 @@ public class BaseGeckoInterface implements GeckoAppShell.GeckoInterface { @Override public void removeAppStateListener(GeckoAppShell.AppStateListener listener) {} - // Bug 908789: Implement this - @Override - public void notifyWakeLockChanged(String topic, String state) {} - @Override public boolean areTabsShown() { return false; diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index ef34b1662122..9223f6d41fc2 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -24,7 +24,6 @@ import java.util.Map; import java.util.StringTokenizer; import java.util.TreeMap; -import android.annotation.SuppressLint; import org.mozilla.gecko.annotation.JNITarget; import org.mozilla.gecko.annotation.RobocopTarget; import org.mozilla.gecko.annotation.WrapForJNI; @@ -39,6 +38,7 @@ import org.mozilla.gecko.util.ProxySelector; import org.mozilla.gecko.util.ThreadUtils; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; @@ -78,10 +78,12 @@ import android.os.Bundle; import android.os.Environment; import android.os.Looper; import android.os.ParcelFileDescriptor; +import android.os.PowerManager; import android.os.SystemClock; import android.os.Vibrator; import android.provider.Settings; import android.support.annotation.NonNull; +import android.support.v4.util.SimpleArrayMap; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.DisplayMetrics; @@ -401,8 +403,11 @@ public class GeckoAppShell double altitude, float accuracy, float bearing, float speed, long time); - private static class DefaultListeners - implements SensorEventListener, LocationListener, NotificationListener, ScreenOrientationDelegate { + private static class DefaultListeners implements SensorEventListener, + LocationListener, + NotificationListener, + ScreenOrientationDelegate, + WakeLockDelegate { @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @@ -533,17 +538,54 @@ public class GeckoAppShell // Do nothing. } - @Override + @Override // ScreenOrientationDelegate public boolean setRequestedOrientationForCurrentActivity(int requestedActivityInfoOrientation) { // Do nothing, and report that the orientation was not set. return false; } + + private SimpleArrayMap mWakeLocks; + + @Override // WakeLockDelegate + @SuppressLint("Wakelock") // We keep the wake lock independent from the function + // scope, so we need to suppress the linter warning. + public void setWakeLockState(final String lock, final int state) { + if (mWakeLocks == null) { + mWakeLocks = new SimpleArrayMap<>(WakeLockDelegate.LOCKS_COUNT); + } + + PowerManager.WakeLock wl = mWakeLocks.get(lock); + + if (state == WakeLockDelegate.STATE_LOCKED_FOREGROUND && wl == null) { + final PowerManager pm = (PowerManager) + getApplicationContext().getSystemService(Context.POWER_SERVICE); + + if (WakeLockDelegate.LOCK_CPU.equals(lock)) { + wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, lock); + } else if (WakeLockDelegate.LOCK_SCREEN.equals(lock)) { + // ON_AFTER_RELEASE is set, the user activity timer will be reset when the + // WakeLock is released, causing the illumination to remain on a bit longer. + wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | + PowerManager.ON_AFTER_RELEASE, lock); + } else { + Log.w(LOGTAG, "Unsupported wake-lock: " + lock); + return; + } + + wl.acquire(); + mWakeLocks.put(lock, wl); + } else if (state != WakeLockDelegate.STATE_LOCKED_FOREGROUND && wl != null) { + wl.release(); + mWakeLocks.remove(lock); + } + } } private static final DefaultListeners DEFAULT_LISTENERS = new DefaultListeners(); private static SensorEventListener sSensorListener = DEFAULT_LISTENERS; private static LocationListener sLocationListener = DEFAULT_LISTENERS; private static NotificationListener sNotificationListener = DEFAULT_LISTENERS; + private static WakeLockDelegate sWakeLockDelegate = DEFAULT_LISTENERS; /** * A delegate for supporting the Screen Orientation API. @@ -582,6 +624,14 @@ public class GeckoAppShell sScreenOrientationDelegate = (screenOrientationDelegate != null) ? screenOrientationDelegate : DEFAULT_LISTENERS; } + public static WakeLockDelegate getWakeLockDelegate() { + return sWakeLockDelegate; + } + + public void setWakeLockDelegate(final WakeLockDelegate delegate) { + sWakeLockDelegate = (delegate != null) ? delegate : DEFAULT_LISTENERS; + } + @WrapForJNI(calledFrom = "gecko") private static void enableSensor(int aSensortype) { GeckoInterface gi = getGeckoInterface(); @@ -1649,7 +1699,6 @@ public class GeckoAppShell public void disableOrientationListener(); public void addAppStateListener(AppStateListener listener); public void removeAppStateListener(AppStateListener listener); - public void notifyWakeLockChanged(String topic, String state); public boolean areTabsShown(); public void invalidateOptionsMenu(); public boolean isForegrounded(); @@ -1973,9 +2022,18 @@ public class GeckoAppShell } @WrapForJNI(calledFrom = "gecko") - private static void notifyWakeLockChanged(String topic, String state) { - if (getGeckoInterface() != null) - getGeckoInterface().notifyWakeLockChanged(topic, state); + private static void notifyWakeLockChanged(final String topic, final String state) { + final int intState; + if ("unlocked".equals(state)) { + intState = WakeLockDelegate.STATE_UNLOCKED; + } else if ("locked-foreground".equals(state)) { + intState = WakeLockDelegate.STATE_LOCKED_FOREGROUND; + } else if ("locked-background".equals(state)) { + intState = WakeLockDelegate.STATE_LOCKED_BACKGROUND; + } else { + throw new IllegalArgumentException(); + } + getWakeLockDelegate().setWakeLockState(topic, intState); } @WrapForJNI(calledFrom = "gecko") diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/WakeLockDelegate.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/WakeLockDelegate.java new file mode 100644 index 000000000000..c1e1518e4dcb --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/WakeLockDelegate.java @@ -0,0 +1,43 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * 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; + +/** + * A WakeLockDelegate is responsible for acquiring and release wake-locks. + */ +public interface WakeLockDelegate { + /** + * Wake-lock for the CPU. + */ + final String LOCK_CPU = "cpu"; + /** + * Wake-lock for the screen. + */ + final String LOCK_SCREEN = "screen"; + + final int LOCKS_COUNT = 2; + + /** + * No one holds the wake-lock. + */ + final int STATE_UNLOCKED = 0; + /** + * The wake-lock is held by a foreground window. + */ + final int STATE_LOCKED_FOREGROUND = 1; + /** + * The wake-lock is held by a background window. + */ + final int STATE_LOCKED_BACKGROUND = 2; + + /** + * Set a wake-lock to a specified state. Called from the Gecko thread. + * + * @param lock Wake-lock to set from one of the LOCK_* constants. + * @param state New wake-lock state from one of the STATE_* constants. + */ + void setWakeLockState(String lock, int state); +}