1bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang/*
2bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * Copyright (C) 2012 The Android Open Source Project
3bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang *
4bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License");
5bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * you may not use this file except in compliance with the License.
6bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * You may obtain a copy of the License at
7bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang *
8bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang *      http://www.apache.org/licenses/LICENSE-2.0
9bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang *
10bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * Unless required by applicable law or agreed to in writing, software
11bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS,
12bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * See the License for the specific language governing permissions and
14bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang * limitations under the License.
15bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang */
16bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
17bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changpackage com.android.gallery3d.app;
18bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
19bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.app.Activity;
20d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Changimport android.content.ContentResolver;
21bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.content.Context;
22bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.content.pm.ActivityInfo;
23bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.content.res.Configuration;
24d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Changimport android.provider.Settings;
25bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.view.OrientationEventListener;
26bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.view.Surface;
27bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
282ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Changimport com.android.gallery3d.ui.OrientationSource;
292ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang
30bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport java.util.ArrayList;
31bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
322ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Changpublic class OrientationManager implements OrientationSource {
33bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private static final String TAG = "OrientationManager";
34bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
35bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public interface Listener {
362ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        public void onOrientationCompensationChanged();
37bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
38bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
39bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // Orientation hysteresis amount used in rounding, in degrees
40bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private static final int ORIENTATION_HYSTERESIS = 5;
41bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
42bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private Activity mActivity;
43bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private ArrayList<Listener> mListeners;
44bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private MyOrientationEventListener mOrientationListener;
45bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // The degrees of the device rotated clockwise from its natural orientation.
46bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
47bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // If the framework orientation is locked.
48bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private boolean mOrientationLocked = false;
49bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // The orientation compensation: if the framwork orientation is locked, the
50bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // device orientation and the framework orientation may be different, so we
51bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // need to rotate the UI. For example, if this value is 90, the UI
52bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // components should be rotated 90 degrees counter-clockwise.
53bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private int mOrientationCompensation = 0;
54bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
55d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang    // This is true if "Settings -> Display -> Rotation Lock" is checked. We
56d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang    // don't allow the orientation to be unlocked if the value is true.
57d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang    private boolean mRotationLockedSetting = false;
58d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang
59bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public OrientationManager(Activity activity) {
60bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mActivity = activity;
61bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mListeners = new ArrayList<Listener>();
62bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mOrientationListener = new MyOrientationEventListener(activity);
63bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
64bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
65bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public void resume() {
66d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang        ContentResolver resolver = mActivity.getContentResolver();
67d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang        mRotationLockedSetting = Settings.System.getInt(
68d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang                resolver, Settings.System.ACCELEROMETER_ROTATION, 0) != 1;
69bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mOrientationListener.enable();
70bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
71bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
72bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public void pause() {
73bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mOrientationListener.disable();
74bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
75bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
76bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public void addListener(Listener listener) {
77bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        synchronized (mListeners) {
78bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mListeners.add(listener);
79bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
80bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
81bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
82bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public void removeListener(Listener listener) {
83bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        synchronized (mListeners) {
84bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mListeners.remove(listener);
85bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
86bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
87bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
88bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    ////////////////////////////////////////////////////////////////////////////
89bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    //  Orientation handling
90bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    //
91bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    //  We can choose to lock the framework orientation or not. If we lock the
92bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    //  framework orientation, we calculate a a compensation value according to
93bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    //  current device orientation and send it to listeners. If we don't lock
94bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    //  the framework orientation, we always set the compensation value to 0.
95bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    ////////////////////////////////////////////////////////////////////////////
96bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
97bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // Lock the framework orientation to the current device orientation
98bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public void lockOrientation() {
99bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mOrientationLocked) return;
100bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mOrientationLocked = true;
1015cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck        int displayRotation = getDisplayRotation();
102eece6da4d344f7e1e937130c0d36cef8ef9dbe0cJohn Reck        // Display rotation >= 180 means we need to use the REVERSE landscape/portrait
1035cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck        boolean standard = displayRotation < 180;
104bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mActivity.getResources().getConfiguration().orientation
105bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                == Configuration.ORIENTATION_LANDSCAPE) {
106bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            Log.d(TAG, "lock orientation to landscape");
107eece6da4d344f7e1e937130c0d36cef8ef9dbe0cJohn Reck            mActivity.setRequestedOrientation(standard
108eece6da4d344f7e1e937130c0d36cef8ef9dbe0cJohn Reck                    ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
109eece6da4d344f7e1e937130c0d36cef8ef9dbe0cJohn Reck                    : ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
110bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        } else {
1115cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck            if (displayRotation == 90 || displayRotation == 270) {
1125cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck                // If displayRotation = 90 or 270 then we are on a landscape
1135cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck                // device. On landscape devices, portrait is a 90 degree
1145cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck                // clockwise rotation from landscape, so we need
1155cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck                // to flip which portrait we pick as display rotation is counter clockwise
1165cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck                standard = !standard;
1175cca8b99bebe6a9fbb191a8e1364b81e309a1390John Reck            }
118bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            Log.d(TAG, "lock orientation to portrait");
119eece6da4d344f7e1e937130c0d36cef8ef9dbe0cJohn Reck            mActivity.setRequestedOrientation(standard
120eece6da4d344f7e1e937130c0d36cef8ef9dbe0cJohn Reck                    ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
121eece6da4d344f7e1e937130c0d36cef8ef9dbe0cJohn Reck                    : ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
122bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
123bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        updateCompensation();
124bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
125bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
126bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // Unlock the framework orientation, so it can change when the device
127bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // rotates.
128bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public void unlockOrientation() {
129bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (!mOrientationLocked) return;
130d0781ecea9a9ad299c6466a81ef66ab78af9dee3Chih-Chung Chang        if (mRotationLockedSetting) return;
131bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mOrientationLocked = false;
132bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        Log.d(TAG, "unlock orientation");
133bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
134bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        disableCompensation();
135bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
136bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
137bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // Calculate the compensation value and send it to listeners.
138bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private void updateCompensation() {
139bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mOrientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
140bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            return;
141bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
142bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
143bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int orientationCompensation =
144bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            (mOrientation + getDisplayRotation(mActivity)) % 360;
145bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
146bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mOrientationCompensation != orientationCompensation) {
147bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mOrientationCompensation = orientationCompensation;
148bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            notifyListeners();
149bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
150bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
151bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
152bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // Make the compensation value 0 and send it to listeners.
153bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private void disableCompensation() {
154bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mOrientationCompensation != 0) {
155bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mOrientationCompensation = 0;
156bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            notifyListeners();
157bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
158bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
159bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
160bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private void notifyListeners() {
161bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        synchronized (mListeners) {
162bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            for (int i = 0, n = mListeners.size(); i < n; i++) {
1632ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang                mListeners.get(i).onOrientationCompensationChanged();
164bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            }
165bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
166bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
167bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
168bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // This listens to the device orientation, so we can update the compensation.
169bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private class MyOrientationEventListener extends OrientationEventListener {
170bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        public MyOrientationEventListener(Context context) {
171bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            super(context);
172bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
173bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
174bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        @Override
175bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        public void onOrientationChanged(int orientation) {
176bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // We keep the last known orientation. So if the user first orient
177bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // the camera then point the camera to floor or sky, we still have
178bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // the correct orientation.
179bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            if (orientation == ORIENTATION_UNKNOWN) return;
180bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mOrientation = roundOrientation(orientation, mOrientation);
181bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // If the framework orientation is locked, we update the
182bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // compensation value and notify the listeners.
183bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            if (mOrientationLocked) updateCompensation();
184bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
185bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
186bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
1872ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    @Override
188bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public int getDisplayRotation() {
189bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        return getDisplayRotation(mActivity);
190bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
191bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
1922ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    @Override
1932ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    public int getCompensation() {
1942ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        return mOrientationCompensation;
1952ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    }
1962ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang
197bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private static int roundOrientation(int orientation, int orientationHistory) {
198bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        boolean changeOrientation = false;
199bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
200bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            changeOrientation = true;
201bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        } else {
202bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            int dist = Math.abs(orientation - orientationHistory);
203bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            dist = Math.min(dist, 360 - dist);
204bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            changeOrientation = (dist >= 45 + ORIENTATION_HYSTERESIS);
205bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
206bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (changeOrientation) {
207bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            return ((orientation + 45) / 90 * 90) % 360;
208bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
209bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        return orientationHistory;
210bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
211bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
212bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private static int getDisplayRotation(Activity activity) {
213bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int rotation = activity.getWindowManager().getDefaultDisplay()
214bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                .getRotation();
215bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        switch (rotation) {
216bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            case Surface.ROTATION_0: return 0;
217bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            case Surface.ROTATION_90: return 90;
218bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            case Surface.ROTATION_180: return 180;
219bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            case Surface.ROTATION_270: return 270;
220bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
221bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        return 0;
222bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
223bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang}
224