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); +}