1bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu/* 2bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * Copyright (C) 2013 The Android Open Source Project 3bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * 4bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * Licensed under the Apache License, Version 2.0 (the "License"); 5bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * you may not use this file except in compliance with the License. 6bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * You may obtain a copy of the License at 7bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * 8bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * http://www.apache.org/licenses/LICENSE-2.0 9bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * 10bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * Unless required by applicable law or agreed to in writing, software 11bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * distributed under the License is distributed on an "AS IS" BASIS, 12bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * See the License for the specific language governing permissions and 14bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu * limitations under the License. 15bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu */ 16bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu 17bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liupackage com.android.camera.ui; 18bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu 198e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport android.annotation.SuppressLint; 20bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liuimport android.app.Activity; 21bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liuimport android.content.Context; 22bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liuimport android.content.res.Configuration; 23bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liuimport android.graphics.Rect; 246432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.hardware.display.DisplayManager; 256432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.hardware.display.DisplayManager.DisplayListener; 26bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liuimport android.util.AttributeSet; 27bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liuimport android.view.View; 28bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liuimport android.widget.FrameLayout; 29bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu 30b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport com.android.camera.util.ApiHelper; 314863db01e3629a0a29c718b94445332ef74441e9Sascha Haeberlingimport com.android.camera.util.CameraUtil; 32bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu 338e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberling@SuppressLint("NewApi") 346432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liupublic class CameraRootView extends FrameLayout { 35bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu 36cb62cff674473133bedc32d06c2c0d6c02cbec90Doris Liu private int mTopMargin = 0; 37cb62cff674473133bedc32d06c2c0d6c02cbec90Doris Liu private int mBottomMargin = 0; 38cb62cff674473133bedc32d06c2c0d6c02cbec90Doris Liu private int mLeftMargin = 0; 39cb62cff674473133bedc32d06c2c0d6c02cbec90Doris Liu private int mRightMargin = 0; 40fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu private final Rect mCurrentInsets = new Rect(0, 0, 0, 0); 416432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu private int mOffset = 0; 426432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu private Object mDisplayListener; 436432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu private MyDisplayListener mListener; 444ed20592482d2ab2f3f48ee72d5b1c06bf009034Sascha Haeberling 456432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public interface MyDisplayListener { 466432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void onDisplayChanged(); 476432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 486432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 49bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu public CameraRootView(Context context, AttributeSet attrs) { 50bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu super(context, attrs); 516432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu initDisplayListener(); 52bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu } 53bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu 54bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu @Override 55bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu protected boolean fitSystemWindows(Rect insets) { 564863db01e3629a0a29c718b94445332ef74441e9Sascha Haeberling // insets include status bar, navigation bar, etc 574863db01e3629a0a29c718b94445332ef74441e9Sascha Haeberling // In this case, we are only concerned with the size of nav bar 58fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu if (mCurrentInsets.equals(insets)) { 59fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu // Local copy of the insets is up to date. No need to do anything. 60fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu return false; 61bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu } 624863db01e3629a0a29c718b94445332ef74441e9Sascha Haeberling 63fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu if (mOffset == 0) { 64fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu if (insets.bottom > 0) { 65fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu mOffset = insets.bottom; 66fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu } else if (insets.right > 0) { 67fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu mOffset = insets.right; 68fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu } 694863db01e3629a0a29c718b94445332ef74441e9Sascha Haeberling } 70fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu mCurrentInsets.set(insets); 71fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu // Make sure onMeasure will be called to adapt to the new insets. 72fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu requestLayout(); 73fc7b834155f3a15939b0dcfaf7140a9da21b876cDoris Liu return false; 74bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu } 75bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu 766432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void initDisplayListener() { 776432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu if (ApiHelper.HAS_DISPLAY_LISTENER) { 786432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu mDisplayListener = new DisplayListener() { 796432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 806432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu @Override 816432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void onDisplayAdded(int arg0) {} 826432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 836432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu @Override 846432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void onDisplayChanged(int arg0) { 85ed15d1a140986473bbe7fffd72ec9618c41c5979Angus Kong if (mListener != null) { 86ed15d1a140986473bbe7fffd72ec9618c41c5979Angus Kong mListener.onDisplayChanged(); 87ed15d1a140986473bbe7fffd72ec9618c41c5979Angus Kong } 886432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 896432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 906432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu @Override 916432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void onDisplayRemoved(int arg0) {} 926432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu }; 936432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 946432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 956432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 9659390061e26d3d481c6e0c9b22fb3ee8ec8387b0Doris Liu public void removeDisplayChangeListener() { 9759390061e26d3d481c6e0c9b22fb3ee8ec8387b0Doris Liu mListener = null; 9859390061e26d3d481c6e0c9b22fb3ee8ec8387b0Doris Liu } 9959390061e26d3d481c6e0c9b22fb3ee8ec8387b0Doris Liu 1006432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void setDisplayChangeListener(MyDisplayListener listener) { 1016432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu mListener = listener; 1026432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 1036432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 1046432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu @Override 1056432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void onAttachedToWindow() { 1066432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu super.onAttachedToWindow(); 1076432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu if (ApiHelper.HAS_DISPLAY_LISTENER) { 1086432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE)) 1096432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu .registerDisplayListener((DisplayListener) mDisplayListener, null); 1106432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 1116432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 1126432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 1136432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu @Override 1146432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu public void onDetachedFromWindow () { 1156432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu super.onDetachedFromWindow(); 1166432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu if (ApiHelper.HAS_DISPLAY_LISTENER) { 1176432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE)) 1186432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu .unregisterDisplayListener((DisplayListener) mDisplayListener); 1196432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 1206432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu } 1216432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu 122bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu @Override 123bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 124b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong int rotation = CameraUtil.getDisplayRotation((Activity) getContext()); 125acfe99e268f157bfd524c825f388e6d37261e135Doris Liu // all the layout code assumes camera device orientation to be portrait 126acfe99e268f157bfd524c825f388e6d37261e135Doris Liu // adjust rotation for landscape 127acfe99e268f157bfd524c825f388e6d37261e135Doris Liu int orientation = getResources().getConfiguration().orientation; 128acfe99e268f157bfd524c825f388e6d37261e135Doris Liu int camOrientation = (rotation % 180 == 0) ? Configuration.ORIENTATION_PORTRAIT 129acfe99e268f157bfd524c825f388e6d37261e135Doris Liu : Configuration.ORIENTATION_LANDSCAPE; 130acfe99e268f157bfd524c825f388e6d37261e135Doris Liu if (camOrientation != orientation) { 131acfe99e268f157bfd524c825f388e6d37261e135Doris Liu rotation = (rotation + 90) % 360; 132acfe99e268f157bfd524c825f388e6d37261e135Doris Liu } 133acfe99e268f157bfd524c825f388e6d37261e135Doris Liu // calculate margins 134bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mLeftMargin = 0; 135bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mRightMargin = 0; 136bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mBottomMargin = 0; 137bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mTopMargin = 0; 138acfe99e268f157bfd524c825f388e6d37261e135Doris Liu switch (rotation) { 139acfe99e268f157bfd524c825f388e6d37261e135Doris Liu case 0: 140bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mBottomMargin += mOffset; 141acfe99e268f157bfd524c825f388e6d37261e135Doris Liu break; 142acfe99e268f157bfd524c825f388e6d37261e135Doris Liu case 90: 143bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mRightMargin += mOffset; 144acfe99e268f157bfd524c825f388e6d37261e135Doris Liu break; 145acfe99e268f157bfd524c825f388e6d37261e135Doris Liu case 180: 146bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mTopMargin += mOffset; 147acfe99e268f157bfd524c825f388e6d37261e135Doris Liu break; 148acfe99e268f157bfd524c825f388e6d37261e135Doris Liu case 270: 149bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mLeftMargin += mOffset; 150acfe99e268f157bfd524c825f388e6d37261e135Doris Liu break; 151acfe99e268f157bfd524c825f388e6d37261e135Doris Liu } 152d45258375a9356475377f6bdc7a504cd9acb937aDoris Liu if (mCurrentInsets != null) { 153d45258375a9356475377f6bdc7a504cd9acb937aDoris Liu if (mCurrentInsets.right > 0) { 154d45258375a9356475377f6bdc7a504cd9acb937aDoris Liu // navigation bar on the right 155bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mRightMargin = mRightMargin > 0 ? mRightMargin : mCurrentInsets.right; 156d45258375a9356475377f6bdc7a504cd9acb937aDoris Liu } else { 157d45258375a9356475377f6bdc7a504cd9acb937aDoris Liu // navigation bar on the bottom 158bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu mBottomMargin = mBottomMargin > 0 ? mBottomMargin : mCurrentInsets.bottom; 159d45258375a9356475377f6bdc7a504cd9acb937aDoris Liu } 160acfe99e268f157bfd524c825f388e6d37261e135Doris Liu } 161bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu // make sure all the children are resized 162bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu super.onMeasure(widthMeasureSpec - mLeftMargin - mRightMargin, 163bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu heightMeasureSpec - mTopMargin - mBottomMargin); 164bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); 165bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu } 166bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu 167bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu @Override 168bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu public void onLayout(boolean changed, int l, int t, int r, int b) { 1696432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu r -= l; 1706432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu b -= t; 1716432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu l = 0; 1726432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu t = 0; 173bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu int orientation = getResources().getConfiguration().orientation; 174bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu // Lay out children 175acfe99e268f157bfd524c825f388e6d37261e135Doris Liu for (int i = 0; i < getChildCount(); i++) { 176acfe99e268f157bfd524c825f388e6d37261e135Doris Liu View v = getChildAt(i); 177acfe99e268f157bfd524c825f388e6d37261e135Doris Liu if (v instanceof CameraControls) { 178bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu // Lay out camera controls to center on the short side of the screen 179acfe99e268f157bfd524c825f388e6d37261e135Doris Liu // so that they stay in place during rotation 180bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu int width = v.getMeasuredWidth(); 181bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu int height = v.getMeasuredHeight(); 182bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu if (orientation == Configuration.ORIENTATION_PORTRAIT) { 183bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu int left = (l + r - width) / 2; 184bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu v.layout(left, t + mTopMargin, left + width, b - mBottomMargin); 185acfe99e268f157bfd524c825f388e6d37261e135Doris Liu } else { 186bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu int top = (t + b - height) / 2; 187bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu v.layout(l + mLeftMargin, top, r - mRightMargin, top + height); 188acfe99e268f157bfd524c825f388e6d37261e135Doris Liu } 189acfe99e268f157bfd524c825f388e6d37261e135Doris Liu } else { 190bcd73db9b9a5580167f1f54e78b798cbf9165940Doris Liu v.layout(l + mLeftMargin, t + mTopMargin, r - mRightMargin, b - mBottomMargin); 191acfe99e268f157bfd524c825f388e6d37261e135Doris Liu } 192bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu } 193bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu } 194bbee3bfe85ab29acda2e13c422459d3cb96b1917Doris Liu} 195