BottomBar.java revision 3b92e2f8e6d91af1b83c8bee95bd93e7153b96da
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.camera.ui; 18 19import android.content.Context; 20import android.content.res.Configuration; 21import android.util.AttributeSet; 22import android.view.Gravity; 23import android.view.MotionEvent; 24import android.view.View; 25import android.view.ViewGroup; 26import android.widget.FrameLayout; 27 28import com.android.camera2.R; 29import com.android.camera.ToggleImageButton; 30 31/** 32 * BottomBar swaps its width and height on rotation. In addition, it also changes 33 * gravity and layout orientation based on the new orientation. Specifically, in 34 * landscape it aligns to the right side of its parent and lays out its children 35 * vertically, whereas in portrait, it stays at the bottom of the parent and has 36 * a horizontal layout orientation. 37 */ 38public class BottomBar extends FrameLayout 39 implements PreviewStatusListener.PreviewAreaSizeChangedListener { 40 41 private static final String TAG = "BottomBar"; 42 private int mWidth; 43 private int mHeight; 44 private float mOffsetShorterEdge; 45 private float mOffsetLongerEdge; 46 47 private final int mOptimalHeight; 48 private boolean mOverLayBottomBar; 49 50 private TopRightMostOverlay mSettingsOverlay; 51 private TopRightWeightedLayout mSettingsLayout; 52 private FrameLayout mCaptureLayout; 53 private TopRightWeightedLayout mIntentLayout; 54 55 public BottomBar(Context context, AttributeSet attrs) { 56 super(context, attrs); 57 mOptimalHeight = getResources().getDimensionPixelSize(R.dimen.bottom_bar_height_optimal); 58 } 59 60 @Override 61 public void onFinishInflate() { 62 mSettingsOverlay 63 = (TopRightMostOverlay) findViewById(R.id.bottombar_settings_overlay); 64 mSettingsLayout 65 = (TopRightWeightedLayout) findViewById(R.id.bottombar_settings); 66 mCaptureLayout 67 = (FrameLayout) findViewById(R.id.bottombar_capture); 68 mIntentLayout 69 = (TopRightWeightedLayout) findViewById(R.id.bottombar_intent); 70 } 71 72 /** 73 * Initializes the bottom bar toggle for switching between 74 * capture and the bottom bar settings toggles. 75 */ 76 public void setupToggle(final boolean isCaptureIntent) { 77 // Of type ToggleImageButton because ToggleButton 78 // has a non-removable spacing for text on the right-hand side. 79 ToggleImageButton toggle = (ToggleImageButton) findViewById(R.id.bottombar_settings_toggle); 80 toggle.setState(0, false); 81 toggle.setOnStateChangeListener(new ToggleImageButton.OnStateChangeListener() { 82 @Override 83 public void stateChanged(View view, boolean toSettings) { 84 if (toSettings) { 85 if (isCaptureIntent) { 86 hideIntentLayout(); 87 } 88 transitionToSettings(); 89 } else { 90 if (isCaptureIntent) { 91 transitionToIntentLayout(); 92 } else { 93 transitionToCapture(); 94 } 95 } 96 } 97 }); 98 mSettingsOverlay.setReferenceViewParent(mSettingsLayout); 99 } 100 101 /** 102 * Hide the intent layout. This is necessary for switching between 103 * the intent capture layout and the bottom bar settings. 104 */ 105 private void hideIntentLayout() { 106 mIntentLayout.setVisibility(View.INVISIBLE); 107 } 108 109 /** 110 * Perform a transition from the bottom bar capture layout to the 111 * bottom bar settings layout. 112 */ 113 private void transitionToCapture() { 114 mSettingsLayout.setVisibility(View.INVISIBLE); 115 mCaptureLayout.setVisibility(View.VISIBLE); 116 } 117 118 /** 119 * Perform a transition from the bottom bar settings layout to the 120 * bottom bar capture layout. 121 */ 122 private void transitionToSettings() { 123 mSettingsLayout.setVisibility(View.VISIBLE); 124 mCaptureLayout.setVisibility(View.INVISIBLE); 125 } 126 127 /** 128 * Perform a transition to the global intent layout. The current 129 * layout state of the bottom bar is irrelevant. 130 */ 131 public void transitionToIntentLayout() { 132 mCaptureLayout.setVisibility(View.VISIBLE); 133 mSettingsLayout.setVisibility(View.INVISIBLE); 134 mSettingsOverlay.setVisibility(View.VISIBLE); 135 mIntentLayout.setVisibility(View.VISIBLE); 136 137 View button; 138 button = mIntentLayout.findViewById(R.id.done_button); 139 button.setVisibility(View.INVISIBLE); 140 button = mIntentLayout.findViewById(R.id.retake_button); 141 button.setVisibility(View.INVISIBLE); 142 } 143 144 /** 145 * Perform a transition to the global intent review layout. 146 * The current layout state of the bottom bar is irrelevant. 147 */ 148 public void transitionToIntentReviewLayout() { 149 mCaptureLayout.setVisibility(View.INVISIBLE); 150 mSettingsLayout.setVisibility(View.INVISIBLE); 151 mSettingsOverlay.setVisibility(View.INVISIBLE); 152 153 View button; 154 button = mIntentLayout.findViewById(R.id.done_button); 155 button.setVisibility(View.VISIBLE); 156 button = mIntentLayout.findViewById(R.id.retake_button); 157 button.setVisibility(View.VISIBLE); 158 mIntentLayout.setVisibility(View.VISIBLE); 159 } 160 161 @Override 162 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 163 mWidth = MeasureSpec.getSize(widthMeasureSpec); 164 mHeight = MeasureSpec.getSize(heightMeasureSpec); 165 if (mWidth == 0 || mHeight == 0) { 166 return; 167 } 168 169 if (mOffsetShorterEdge != 0 && mOffsetLongerEdge != 0) { 170 float previewAspectRatio = 171 mOffsetLongerEdge / mOffsetShorterEdge; 172 if (previewAspectRatio < 1.0) { 173 previewAspectRatio = 1.0f/previewAspectRatio; 174 } 175 float screenAspectRatio = (float) mWidth / (float) mHeight; 176 if (screenAspectRatio < 1.0) { 177 screenAspectRatio = 1.0f/screenAspectRatio; 178 } 179 if (previewAspectRatio >= screenAspectRatio) { 180 mOverLayBottomBar = true; 181 setAlpha(0.5f); 182 } else { 183 mOverLayBottomBar = false; 184 setAlpha(1.0f); 185 } 186 } 187 188 // Calculates the width and height needed for the bar. 189 int barWidth, barHeight; 190 if (mWidth > mHeight) { 191 ((LayoutParams) getLayoutParams()).gravity = Gravity.RIGHT; 192 if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) { 193 barWidth = mOptimalHeight; 194 barHeight = mHeight; 195 } else { 196 barWidth = (int) (mWidth - mOffsetLongerEdge); 197 barHeight = mHeight; 198 } 199 } else { 200 ((LayoutParams) getLayoutParams()).gravity = Gravity.BOTTOM; 201 if ((mOffsetLongerEdge == 0 && mOffsetShorterEdge == 0) || mOverLayBottomBar) { 202 barWidth = mWidth; 203 barHeight = mOptimalHeight; 204 } else { 205 barWidth = mWidth; 206 barHeight = (int) (mHeight - mOffsetLongerEdge); 207 } 208 } 209 super.onMeasure(MeasureSpec.makeMeasureSpec(barWidth, MeasureSpec.EXACTLY), 210 MeasureSpec.makeMeasureSpec(barHeight, MeasureSpec.EXACTLY)); 211 } 212 213 private void adjustBottomBar(float scaledTextureWidth, 214 float scaledTextureHeight) { 215 setOffset(scaledTextureWidth, scaledTextureHeight); 216 } 217 218 @Override 219 public void onPreviewAreaSizeChanged(float scaledTextureWidth, 220 float scaledTextureHeight) { 221 adjustBottomBar(scaledTextureWidth, scaledTextureHeight); 222 } 223 224 private void setOffset(float scaledTextureWidth, float scaledTextureHeight) { 225 float offsetLongerEdge, offsetShorterEdge; 226 if (scaledTextureHeight > scaledTextureWidth) { 227 offsetLongerEdge = scaledTextureHeight; 228 offsetShorterEdge = scaledTextureWidth; 229 } else { 230 offsetLongerEdge = scaledTextureWidth; 231 offsetShorterEdge = scaledTextureHeight; 232 } 233 if (mOffsetLongerEdge != offsetLongerEdge || mOffsetShorterEdge != offsetShorterEdge) { 234 mOffsetLongerEdge = offsetLongerEdge; 235 mOffsetShorterEdge = offsetShorterEdge; 236 requestLayout(); 237 } 238 } 239 240 @Override 241 protected void onConfigurationChanged(Configuration config) { 242 super.onConfigurationChanged(config); 243 } 244 245 // prevent touches on bottom bar (not its children) 246 // from triggering a touch event on preview area 247 @Override 248 public boolean onTouchEvent(MotionEvent event) { 249 return true; 250 } 251} 252