mobile/android/base/GeckoScreenOrientation.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/GeckoScreenOrientation.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,376 @@
     1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +package org.mozilla.gecko;
    1.10 +
    1.11 +import android.content.Context;
    1.12 +import android.content.pm.ActivityInfo;
    1.13 +import android.content.res.Configuration;
    1.14 +import android.util.Log;
    1.15 +import android.view.Surface;
    1.16 +import android.app.Activity;
    1.17 +
    1.18 +import java.util.Arrays;
    1.19 +import java.util.List;
    1.20 +
    1.21 +/*
    1.22 + * Updates, locks and unlocks the screen orientation.
    1.23 + *
    1.24 + * Note: Replaces the OnOrientationChangeListener to avoid redundant rotation
    1.25 + * event handling.
    1.26 + */
    1.27 +public class GeckoScreenOrientation {
    1.28 +    private static final String LOGTAG = "GeckoScreenOrientation";
    1.29 +
    1.30 +    // Make sure that any change in dom/base/ScreenOrientation.h happens here too.
    1.31 +    public enum ScreenOrientation {
    1.32 +        NONE(0),
    1.33 +        PORTRAIT_PRIMARY(1 << 0),
    1.34 +        PORTRAIT_SECONDARY(1 << 1),
    1.35 +        LANDSCAPE_PRIMARY(1 << 2),
    1.36 +        LANDSCAPE_SECONDARY(1 << 3),
    1.37 +        DEFAULT(1 << 4);
    1.38 +
    1.39 +        public final short value;
    1.40 +
    1.41 +        private ScreenOrientation(int value) {
    1.42 +            this.value = (short)value;
    1.43 +        }
    1.44 +
    1.45 +        public static ScreenOrientation get(short value) {
    1.46 +            switch (value) {
    1.47 +                case (1 << 0): return PORTRAIT_PRIMARY;
    1.48 +                case (1 << 1): return PORTRAIT_SECONDARY;
    1.49 +                case (1 << 2): return LANDSCAPE_PRIMARY;
    1.50 +                case (1 << 3): return LANDSCAPE_SECONDARY;
    1.51 +                case (1 << 4): return DEFAULT;
    1.52 +                default: return NONE;
    1.53 +            }
    1.54 +        }
    1.55 +    }
    1.56 +
    1.57 +    // Singleton instance.
    1.58 +    private static GeckoScreenOrientation sInstance = null;
    1.59 +    // Default screen orientation, used for initialization and unlocking.
    1.60 +    private static final ScreenOrientation DEFAULT_SCREEN_ORIENTATION = ScreenOrientation.DEFAULT;
    1.61 +    // Default rotation, used when device rotation is unknown.
    1.62 +    private static final int DEFAULT_ROTATION = Surface.ROTATION_0;
    1.63 +    // Default orientation, used if screen orientation is unspecified.
    1.64 +    private ScreenOrientation mDefaultScreenOrientation;
    1.65 +    // Last updated screen orientation.
    1.66 +    private ScreenOrientation mScreenOrientation;
    1.67 +    // Whether the update should notify Gecko about screen orientation changes.
    1.68 +    private boolean mShouldNotify = true;
    1.69 +    // Configuration screen orientation preference path.
    1.70 +    private static final String DEFAULT_SCREEN_ORIENTATION_PREF = "app.orientation.default";
    1.71 +
    1.72 +    public GeckoScreenOrientation() {
    1.73 +        PrefsHelper.getPref(DEFAULT_SCREEN_ORIENTATION_PREF, new PrefsHelper.PrefHandlerBase() {
    1.74 +            @Override public void prefValue(String pref, String value) {
    1.75 +                // Read and update the configuration default preference.
    1.76 +                mDefaultScreenOrientation = screenOrientationFromArrayString(value);
    1.77 +                setRequestedOrientation(mDefaultScreenOrientation);
    1.78 +            }
    1.79 +        });
    1.80 +
    1.81 +        mDefaultScreenOrientation = DEFAULT_SCREEN_ORIENTATION;
    1.82 +        update();
    1.83 +    }
    1.84 +
    1.85 +    public static GeckoScreenOrientation getInstance() {
    1.86 +        if (sInstance == null) {
    1.87 +            sInstance = new GeckoScreenOrientation();
    1.88 +        }
    1.89 +        return sInstance;
    1.90 +    }
    1.91 +
    1.92 +    /*
    1.93 +     * Enable Gecko screen orientation events on update.
    1.94 +     */
    1.95 +    public void enableNotifications() {
    1.96 +        update();
    1.97 +        mShouldNotify = true;
    1.98 +    }
    1.99 +
   1.100 +    /*
   1.101 +     * Disable Gecko screen orientation events on update.
   1.102 +     */
   1.103 +    public void disableNotifications() {
   1.104 +        mShouldNotify = false;
   1.105 +    }
   1.106 +
   1.107 +    /*
   1.108 +     * Update screen orientation.
   1.109 +     * Retrieve orientation and rotation via GeckoAppShell.
   1.110 +     *
   1.111 +     * @return Whether the screen orientation has changed.
   1.112 +     */
   1.113 +    public boolean update() {
   1.114 +        Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
   1.115 +        if (activity == null) {
   1.116 +            return false;
   1.117 +        }
   1.118 +        Configuration config = activity.getResources().getConfiguration();
   1.119 +        return update(config.orientation);
   1.120 +    }
   1.121 +
   1.122 +    /*
   1.123 +     * Update screen orientation given the android orientation.
   1.124 +     * Retrieve rotation via GeckoAppShell.
   1.125 +     *
   1.126 +     * @param aAndroidOrientation
   1.127 +     *        Android screen orientation from Configuration.orientation.
   1.128 +     *
   1.129 +     * @return Whether the screen orientation has changed.
   1.130 +     */
   1.131 +    public boolean update(int aAndroidOrientation) {
   1.132 +        return update(getScreenOrientation(aAndroidOrientation, getRotation()));
   1.133 +    }
   1.134 +
   1.135 +    /*
   1.136 +     * Update screen orientation given the screen orientation.
   1.137 +     *
   1.138 +     * @param aScreenOrientation
   1.139 +     *        Gecko screen orientation based on android orientation and rotation.
   1.140 +     *
   1.141 +     * @return Whether the screen orientation has changed.
   1.142 +     */
   1.143 +    public boolean update(ScreenOrientation aScreenOrientation) {
   1.144 +        if (mScreenOrientation == aScreenOrientation) {
   1.145 +            return false;
   1.146 +        }
   1.147 +        mScreenOrientation = aScreenOrientation;
   1.148 +        Log.d(LOGTAG, "updating to new orientation " + mScreenOrientation);
   1.149 +        if (mShouldNotify) {
   1.150 +            GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenOrientationEvent(mScreenOrientation.value));
   1.151 +        }
   1.152 +        return true;
   1.153 +    }
   1.154 +
   1.155 +    /*
   1.156 +     * @return The Android orientation (Configuration.orientation).
   1.157 +     */
   1.158 +    public int getAndroidOrientation() {
   1.159 +        return screenOrientationToAndroidOrientation(getScreenOrientation());
   1.160 +    }
   1.161 +
   1.162 +    /*
   1.163 +     * @return The Gecko screen orientation derived from Android orientation and
   1.164 +     *         rotation.
   1.165 +     */
   1.166 +    public ScreenOrientation getScreenOrientation() {
   1.167 +        return mScreenOrientation;
   1.168 +    }
   1.169 +
   1.170 +    /*
   1.171 +     * Lock screen orientation given the Android orientation.
   1.172 +     * Retrieve rotation via GeckoAppShell.
   1.173 +     *
   1.174 +     * @param aAndroidOrientation
   1.175 +     *        The Android orientation provided by Configuration.orientation.
   1.176 +     */
   1.177 +    public void lock(int aAndroidOrientation) {
   1.178 +        lock(getScreenOrientation(aAndroidOrientation, getRotation()));
   1.179 +    }
   1.180 +
   1.181 +    /*
   1.182 +     * Lock screen orientation given the Gecko screen orientation.
   1.183 +     * Retrieve rotation via GeckoAppShell.
   1.184 +     *
   1.185 +     * @param aScreenOrientation
   1.186 +     *        Gecko screen orientation derived from Android orientation and
   1.187 +     *        rotation.
   1.188 +     *
   1.189 +     * @return Whether the locking was successful.
   1.190 +     */
   1.191 +    public boolean lock(ScreenOrientation aScreenOrientation) {
   1.192 +        Log.d(LOGTAG, "locking to " + aScreenOrientation);
   1.193 +        update(aScreenOrientation);
   1.194 +        return setRequestedOrientation(aScreenOrientation);
   1.195 +    }
   1.196 +
   1.197 +    /*
   1.198 +     * Unlock and update screen orientation.
   1.199 +     *
   1.200 +     * @return Whether the unlocking was successful.
   1.201 +     */
   1.202 +    public boolean unlock() {
   1.203 +        Log.d(LOGTAG, "unlocking");
   1.204 +        setRequestedOrientation(mDefaultScreenOrientation);
   1.205 +        return update();
   1.206 +    }
   1.207 +
   1.208 +    /*
   1.209 +     * Set the given requested orientation for the current activity.
   1.210 +     * This is essentially an unlock without an update.
   1.211 +     *
   1.212 +     * @param aScreenOrientation
   1.213 +     *        Gecko screen orientation.
   1.214 +     *
   1.215 +     * @return Whether the requested orientation was set. This can only fail if
   1.216 +     *         the current activity cannot be retrieved vie GeckoAppShell.
   1.217 +     *
   1.218 +     */
   1.219 +    private boolean setRequestedOrientation(ScreenOrientation aScreenOrientation) {
   1.220 +        int activityOrientation = screenOrientationToActivityInfoOrientation(aScreenOrientation);
   1.221 +        Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
   1.222 +        if (activity == null) {
   1.223 +            Log.w(LOGTAG, "setRequestOrientation: failed to get activity");
   1.224 +        }
   1.225 +        if (activity.getRequestedOrientation() == activityOrientation) {
   1.226 +            return false;
   1.227 +        }
   1.228 +        activity.setRequestedOrientation(activityOrientation);
   1.229 +        return true;
   1.230 +    }
   1.231 +
   1.232 +    /*
   1.233 +     * Combine the Android orientation and rotation to the Gecko orientation.
   1.234 +     *
   1.235 +     * @param aAndroidOrientation
   1.236 +     *        Android orientation from Configuration.orientation.
   1.237 +     * @param aRotation
   1.238 +     *        Device rotation from Display.getRotation().
   1.239 +     *
   1.240 +     * @return Gecko screen orientation.
   1.241 +     */
   1.242 +    private ScreenOrientation getScreenOrientation(int aAndroidOrientation, int aRotation) {
   1.243 +        boolean isPrimary = aRotation == Surface.ROTATION_0 || aRotation == Surface.ROTATION_90;
   1.244 +        if (aAndroidOrientation == Configuration.ORIENTATION_PORTRAIT) {
   1.245 +            if (isPrimary) {
   1.246 +                // Non-rotated portrait device or landscape device rotated
   1.247 +                // to primary portrait mode counter-clockwise.
   1.248 +                return ScreenOrientation.PORTRAIT_PRIMARY;
   1.249 +            }
   1.250 +            return ScreenOrientation.PORTRAIT_SECONDARY;
   1.251 +        }
   1.252 +        if (aAndroidOrientation == Configuration.ORIENTATION_LANDSCAPE) {
   1.253 +            if (isPrimary) {
   1.254 +                // Non-rotated landscape device or portrait device rotated
   1.255 +                // to primary landscape mode counter-clockwise.
   1.256 +                return ScreenOrientation.LANDSCAPE_PRIMARY;
   1.257 +            }
   1.258 +            return ScreenOrientation.LANDSCAPE_SECONDARY;
   1.259 +        }
   1.260 +        return ScreenOrientation.NONE;
   1.261 +    }
   1.262 +
   1.263 +    /*
   1.264 +     * @return Device rotation from Display.getRotation().
   1.265 +     */
   1.266 +    private int getRotation() {
   1.267 +        Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
   1.268 +        if (activity == null) {
   1.269 +            Log.w(LOGTAG, "getRotation: failed to get activity");
   1.270 +            return DEFAULT_ROTATION;
   1.271 +        }
   1.272 +        return activity.getWindowManager().getDefaultDisplay().getRotation();
   1.273 +    }
   1.274 +
   1.275 +    /*
   1.276 +     * Retrieve the screen orientation from an array string.
   1.277 +     *
   1.278 +     * @param aArray
   1.279 +     *        String containing comma-delimited strings.
   1.280 +     *
   1.281 +     * @return First parsed Gecko screen orientation.
   1.282 +     */
   1.283 +    public static ScreenOrientation screenOrientationFromArrayString(String aArray) {
   1.284 +        List<String> orientations = Arrays.asList(aArray.split(","));
   1.285 +        if (orientations.size() == 0) {
   1.286 +            // If nothing is listed, return default.
   1.287 +            Log.w(LOGTAG, "screenOrientationFromArrayString: no orientation in string");
   1.288 +            return DEFAULT_SCREEN_ORIENTATION;
   1.289 +        }
   1.290 +
   1.291 +        // We don't support multiple orientations yet. To avoid developer
   1.292 +        // confusion, just take the first one listed.
   1.293 +        return screenOrientationFromString(orientations.get(0));
   1.294 +    }
   1.295 +
   1.296 +    /*
   1.297 +     * Retrieve the scren orientation from a string.
   1.298 +     *
   1.299 +     * @param aStr
   1.300 +     *        String hopefully containing a screen orientation name.
   1.301 +     * @return Gecko screen orientation if matched, DEFAULT_SCREEN_ORIENTATION
   1.302 +     *         otherwise.
   1.303 +     */
   1.304 +    public static ScreenOrientation screenOrientationFromString(String aStr) {
   1.305 +        if ("portrait".equals(aStr)) {
   1.306 +            return ScreenOrientation.PORTRAIT_PRIMARY;
   1.307 +        }
   1.308 +        else if ("landscape".equals(aStr)) {
   1.309 +            return ScreenOrientation.LANDSCAPE_PRIMARY;
   1.310 +        }
   1.311 +        else if ("portrait-primary".equals(aStr)) {
   1.312 +            return ScreenOrientation.PORTRAIT_PRIMARY;
   1.313 +        }
   1.314 +        else if ("portrait-secondary".equals(aStr)) {
   1.315 +            return ScreenOrientation.PORTRAIT_SECONDARY;
   1.316 +        }
   1.317 +        else if ("landscape-primary".equals(aStr)) {
   1.318 +            return ScreenOrientation.LANDSCAPE_PRIMARY;
   1.319 +        }
   1.320 +        else if ("landscape-secondary".equals(aStr)) {
   1.321 +            return ScreenOrientation.LANDSCAPE_SECONDARY;
   1.322 +        }
   1.323 +        Log.w(LOGTAG, "screenOrientationFromString: unknown orientation string");
   1.324 +        return DEFAULT_SCREEN_ORIENTATION;
   1.325 +    }
   1.326 +
   1.327 +    /*
   1.328 +     * Convert Gecko screen orientation to Android orientation.
   1.329 +     *
   1.330 +     * @param aScreenOrientation
   1.331 +     *        Gecko screen orientation.
   1.332 +     * @return Android orientation. This conversion is lossy, the Android
   1.333 +     *         orientation does not differentiate between primary and secondary
   1.334 +     *         orientations.
   1.335 +     */
   1.336 +    public static int screenOrientationToAndroidOrientation(ScreenOrientation aScreenOrientation) {
   1.337 +        switch (aScreenOrientation) {
   1.338 +            case PORTRAIT_PRIMARY:
   1.339 +            case PORTRAIT_SECONDARY:
   1.340 +                return Configuration.ORIENTATION_PORTRAIT;
   1.341 +            case LANDSCAPE_PRIMARY:
   1.342 +            case LANDSCAPE_SECONDARY:
   1.343 +                return Configuration.ORIENTATION_LANDSCAPE;
   1.344 +            case NONE:
   1.345 +            case DEFAULT:
   1.346 +            default:
   1.347 +                return Configuration.ORIENTATION_UNDEFINED;
   1.348 +        }
   1.349 +    }
   1.350 +
   1.351 +
   1.352 +    /*
   1.353 +     * Convert Gecko screen orientation to Android ActivityInfo orientation.
   1.354 +     * This is yet another orientation used by Android, but it's more detailed
   1.355 +     * than the Android orientation.
   1.356 +     * It is required for screen orientation locking and unlocking.
   1.357 +     *
   1.358 +     * @param aScreenOrientation
   1.359 +     *        Gecko screen orientation.
   1.360 +     * @return Android ActivityInfo orientation.
   1.361 +     */
   1.362 +    public static int screenOrientationToActivityInfoOrientation(ScreenOrientation aScreenOrientation) {
   1.363 +        switch (aScreenOrientation) {
   1.364 +            case PORTRAIT_PRIMARY:
   1.365 +                return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
   1.366 +            case PORTRAIT_SECONDARY:
   1.367 +                return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
   1.368 +            case LANDSCAPE_PRIMARY:
   1.369 +                return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
   1.370 +            case LANDSCAPE_SECONDARY:
   1.371 +                return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
   1.372 +            case DEFAULT:
   1.373 +            case NONE:
   1.374 +                return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
   1.375 +            default:
   1.376 +                return ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
   1.377 +        }
   1.378 +    }
   1.379 +}

mercurial