Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright (C) 2010 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 
     17 package com.android.camera.ui;
     18 
     19 import android.graphics.Rect;
     20 import android.view.View.MeasureSpec;
     21 import android.view.animation.AlphaAnimation;
     22 import android.view.animation.Animation;
     23 import android.view.animation.AnimationSet;
     24 import android.view.animation.OvershootInterpolator;
     25 import android.view.animation.ScaleAnimation;
     26 
     27 import javax.microedition.khronos.opengles.GL11;
     28 
     29 class PopupWindow extends GLView {
     30 
     31     protected BitmapTexture mAnchor;
     32     protected int mAnchorOffset;
     33 
     34     protected int mAnchorPosition;
     35     private final RotatePane mRotatePane = new RotatePane();
     36     private RawTexture mBackupTexture;
     37 
     38     protected Texture mBackground;
     39     private boolean mUsingStencil;
     40 
     41     public PopupWindow() {
     42         super.addComponent(mRotatePane);
     43     }
     44 
     45     @Override
     46     protected void onAttachToRoot(GLRootView root) {
     47         super.onAttachToRoot(root);
     48         mUsingStencil = root.getEGLConfigChooser().getStencilBits() > 0;
     49     }
     50 
     51     public void setBackground(Texture background) {
     52         if (background == mBackground) return;
     53         mBackground = background;
     54         if (background != null && background instanceof NinePatchTexture) {
     55             setPaddings(((NinePatchTexture) mBackground).getPaddings());
     56         } else {
     57             setPaddings(0, 0, 0, 0);
     58         }
     59         invalidate();
     60     }
     61 
     62     public void setAnchor(BitmapTexture anchor, int offset) {
     63         mAnchor = anchor;
     64         mAnchorOffset = offset;
     65     }
     66 
     67     @Override
     68     public void addComponent(GLView component) {
     69         throw new UnsupportedOperationException("use setContent(GLView)");
     70     }
     71 
     72     @Override
     73     protected void onMeasure(int widthSpec, int heightSpec) {
     74         int widthMode = MeasureSpec.getMode(widthSpec);
     75         if (widthMode != MeasureSpec.UNSPECIFIED) {
     76             Rect p = mPaddings;
     77             int width = MeasureSpec.getSize(widthSpec);
     78             widthSpec = MeasureSpec.makeMeasureSpec(
     79                     Math.max(0, width - p.left - p.right
     80                     - mAnchor.getWidth() + mAnchorOffset), widthMode);
     81         }
     82 
     83         int heightMode = MeasureSpec.getMode(heightSpec);
     84         if (heightMode != MeasureSpec.UNSPECIFIED) {
     85             int height = MeasureSpec.getSize(widthSpec);
     86             widthSpec = MeasureSpec.makeMeasureSpec(Math.max(
     87                     0, height - mPaddings.top - mPaddings.bottom), heightMode);
     88         }
     89 
     90         Rect p = mPaddings;
     91         GLView child = mRotatePane;
     92         child.measure(widthSpec, heightSpec);
     93         setMeasuredSize(child.getMeasuredWidth()
     94                 + p.left + p.right + mAnchor.getWidth() - mAnchorOffset,
     95                 child.getMeasuredHeight() + p.top + p.bottom);
     96     }
     97 
     98     @Override
     99     protected void onLayout(
    100             boolean change, int left, int top, int right, int bottom) {
    101         Rect p = getPaddings();
    102         GLView view = mRotatePane;
    103         view.layout(p.left, p.top,
    104                 getWidth() - p.right - mAnchor.getWidth() + mAnchorOffset,
    105                 getHeight() - p.bottom);
    106     }
    107 
    108     public void setAnchorPosition(int yoffset) {
    109         mAnchorPosition = yoffset;
    110     }
    111 
    112     private void renderBackgroundWithStencil(GLRootView root, GL11 gl) {
    113         int width = getWidth();
    114         int height = getHeight();
    115         int aWidth = mAnchor.getWidth();
    116         int aHeight = mAnchor.getHeight();
    117 
    118         Rect p = mPaddings;
    119         int aXoffset = width - aWidth;
    120         int aYoffset = Math.max(p.top, mAnchorPosition - aHeight / 2);
    121         aYoffset = Math.min(aYoffset, height - p.bottom - aHeight);
    122 
    123         if (mAnchor != null) {
    124             gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
    125             gl.glStencilFunc(GL11.GL_ALWAYS, 1, 1);
    126             mAnchor.draw(root, aXoffset, aYoffset);
    127             gl.glStencilFunc(GL11.GL_NOTEQUAL, 1, 1);
    128             gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
    129         }
    130 
    131         if (mBackground != null) {
    132             mBackground.draw(root, 0, 0,
    133                     width - aWidth + mAnchorOffset, height);
    134         }
    135     }
    136 
    137     private void renderBackgroundWithoutStencil(GLRootView root, GL11 gl) {
    138         int width = getWidth();
    139         int height = getHeight();
    140         int aWidth = mAnchor.getWidth();
    141         int aHeight = mAnchor.getHeight();
    142 
    143         Rect p = mPaddings;
    144         int aXoffset = width - aWidth;
    145         int aYoffset = Math.max(p.top, mAnchorPosition - aHeight / 2);
    146         aYoffset = Math.min(aYoffset, height - p.bottom - aHeight);
    147 
    148         if (mAnchor != null) {
    149             mAnchor.draw(root, aXoffset, aYoffset);
    150         }
    151 
    152         if (mBackupTexture == null || mBackupTexture.getBoundGL() != gl) {
    153             mBackupTexture = RawTexture.newInstance(gl);
    154         }
    155 
    156         RawTexture backup = mBackupTexture;
    157         try {
    158             // Copy the current drawing results of the triangle area into
    159             // "backup", so that we can restore the content after it is
    160             // overlaid by the background.
    161             root.copyTexture2D(backup, aXoffset, aYoffset, aWidth, aHeight);
    162         } catch (GLOutOfMemoryException e) {
    163             e.printStackTrace();
    164         }
    165 
    166         if (mBackground != null) {
    167             mBackground.draw(root, 0, 0,
    168                     width - aWidth + mAnchorOffset, height);
    169         }
    170 
    171         gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ZERO);
    172         backup.drawBack(root, aXoffset, aYoffset, aWidth, aHeight);
    173         gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
    174     }
    175 
    176     @Override
    177     protected void renderBackground(GLRootView root, GL11 gl) {
    178         if (mUsingStencil) {
    179             renderBackgroundWithStencil(root, gl);
    180         } else {
    181             renderBackgroundWithoutStencil(root, gl);
    182         }
    183     }
    184 
    185     public void setContent(GLView content) {
    186         mRotatePane.setContent(content);
    187     }
    188 
    189     @Override
    190     public void clearComponents() {
    191         throw new UnsupportedOperationException();
    192     }
    193 
    194     public void popup() {
    195         setVisibility(GLView.VISIBLE);
    196 
    197         AnimationSet set = new AnimationSet(false);
    198         Animation scale = new ScaleAnimation(
    199                 0.7f, 1f, 0.7f, 1f, getWidth(), mAnchorPosition);
    200         Animation alpha = new AlphaAnimation(0.5f, 1.0f);
    201 
    202         set.addAnimation(scale);
    203         set.addAnimation(alpha);
    204         scale.setDuration(150);
    205         alpha.setDuration(100);
    206         scale.setInterpolator(new OvershootInterpolator());
    207         startAnimation(set);
    208     }
    209 
    210     public void popoff() {
    211         setVisibility(GLView.INVISIBLE);
    212         Animation alpha = new AlphaAnimation(0.7f, 0.0f);
    213         alpha.setDuration(100);
    214         startAnimation(alpha);
    215     }
    216 
    217     public void setOrientation(int orientation) {
    218         switch (orientation) {
    219             case 90:
    220                 mRotatePane.setOrientation(RotatePane.LEFT);
    221                 break;
    222             case 180:
    223                 mRotatePane.setOrientation(RotatePane.DOWN);
    224                 break;
    225             case 270:
    226                 mRotatePane.setOrientation(RotatePane.RIGHT);
    227                 break;
    228             default:
    229                 mRotatePane.setOrientation(RotatePane.UP);
    230                 break;
    231         }
    232     }
    233 }
    234