1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.content.browser;
6
7import android.app.Activity;
8import android.content.pm.ActivityInfo;
9import android.content.pm.PackageManager;
10import android.util.Log;
11
12import org.chromium.base.ApplicationStatus;
13import org.chromium.base.CalledByNative;
14import org.chromium.base.JNINamespace;
15import org.chromium.base.ThreadUtils;
16import org.chromium.content_public.common.ScreenOrientationConstants;
17import org.chromium.content_public.common.ScreenOrientationValues;
18import org.chromium.ui.gfx.DeviceDisplayInfo;
19
20/**
21 * This is the implementation of the C++ counterpart ScreenOrientationProvider.
22 */
23@JNINamespace("content")
24public class ScreenOrientationProvider {
25    private static final String TAG = "ScreenOrientationProvider";
26
27    private static int getOrientationFromWebScreenOrientations(byte orientation,
28            Activity activity) {
29        switch (orientation) {
30            case ScreenOrientationValues.DEFAULT:
31                return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
32            case ScreenOrientationValues.PORTRAIT_PRIMARY:
33                return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
34            case ScreenOrientationValues.PORTRAIT_SECONDARY:
35                return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
36            case ScreenOrientationValues.LANDSCAPE_PRIMARY:
37                return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
38            case ScreenOrientationValues.LANDSCAPE_SECONDARY:
39                return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
40            case ScreenOrientationValues.PORTRAIT:
41                return ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
42            case ScreenOrientationValues.LANDSCAPE:
43                return ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
44            case ScreenOrientationValues.ANY:
45                return ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
46            case ScreenOrientationValues.NATURAL:
47                DeviceDisplayInfo displayInfo = DeviceDisplayInfo.create(activity);
48                int rotation = displayInfo.getRotationDegrees();
49                if (rotation == 0 || rotation == 180) {
50                    if (displayInfo.getDisplayHeight() >= displayInfo.getDisplayWidth()) {
51                        return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
52                    }
53                    return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
54                } else {
55                    if (displayInfo.getDisplayHeight() < displayInfo.getDisplayWidth()) {
56                        return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
57                    }
58                    return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
59                }
60            default:
61                Log.w(TAG, "Trying to lock to unsupported orientation!");
62                return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
63        }
64    }
65
66    @CalledByNative
67    static void lockOrientation(byte orientation) {
68        lockOrientation(orientation, ApplicationStatus.getLastTrackedFocusedActivity());
69    }
70
71    public static void lockOrientation(byte webScreenOrientation, Activity activity) {
72        if (activity == null) return;
73
74        int orientation = getOrientationFromWebScreenOrientations(webScreenOrientation, activity);
75        if (orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
76            return;
77        }
78
79        activity.setRequestedOrientation(orientation);
80    }
81
82    @CalledByNative
83    static void unlockOrientation() {
84        Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
85        if (activity == null) {
86            return;
87        }
88
89        int defaultOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
90
91        // Activities opened from a shortcut may have EXTRA_ORIENTATION set. In
92        // which case, we want to use that as the default orientation.
93        int orientation = activity.getIntent().getIntExtra(
94                ScreenOrientationConstants.EXTRA_ORIENTATION,
95                ScreenOrientationValues.DEFAULT);
96        defaultOrientation = getOrientationFromWebScreenOrientations(
97                (byte) orientation, activity);
98
99        try {
100            if (defaultOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
101                ActivityInfo info = activity.getPackageManager().getActivityInfo(
102                        activity.getComponentName(), PackageManager.GET_META_DATA);
103                defaultOrientation = info.screenOrientation;
104            }
105        } catch (PackageManager.NameNotFoundException e) {
106            // Do nothing, defaultOrientation should be SCREEN_ORIENTATION_UNSPECIFIED.
107        } finally {
108            activity.setRequestedOrientation(defaultOrientation);
109        }
110    }
111
112    @CalledByNative
113    static void startAccurateListening() {
114        ThreadUtils.runOnUiThread(new Runnable() {
115            @Override
116            public void run() {
117                ScreenOrientationListener.getInstance().startAccurateListening();
118            }
119        });
120    }
121
122    @CalledByNative
123    static void stopAccurateListening() {
124        ThreadUtils.runOnUiThread(new Runnable() {
125            @Override
126            public void run() {
127                ScreenOrientationListener.getInstance().stopAccurateListening();
128            }
129        });
130    }
131
132    private ScreenOrientationProvider() {
133    }
134}
135