• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.photoeditor;
18 
19 import android.content.Context;
20 import android.graphics.Bitmap;
21 import android.net.Uri;
22 import android.util.AttributeSet;
23 import android.view.MotionEvent;
24 import android.widget.RelativeLayout;
25 
26 import com.android.photoeditor.animation.FadeAnimation;
27 import com.android.photoeditor.animation.Rotate3DAnimation;
28 import com.android.photoeditor.animation.Rotate3DAnimation.Rotate;
29 
30 /**
31  * Toolbar that contains all tools and handles all operations for editing photo.
32  */
33 public class Toolbar extends RelativeLayout {
34 
35     private static final int UNDO_REDO_ANIMATION_DURATION = 100;
36     private static final int QUICKVIEW_ANIMATION_DURATION = 150;
37 
38     private final FilterStack filterStack = new FilterStack();
39     private ToolbarLayoutHandler layoutHandler;
40     private ToolbarIdleHandler idleHandler;
41     private EffectsBar effectsBar;
42     private ActionBar actionBar;
43     private PhotoView photoView;
44     private SpinnerProgressDialog progressDialog;
45     private Uri sourceUri;
46 
Toolbar(Context context, AttributeSet attrs)47     public Toolbar(Context context, AttributeSet attrs) {
48         super(context, attrs);
49     }
50 
51     @Override
onInterceptTouchEvent(MotionEvent ev)52     public boolean onInterceptTouchEvent(MotionEvent ev) {
53         idleHandler.killIdle();
54         return false;
55     }
56 
57     @Override
onLayout(boolean changed, int l, int t, int r, int b)58     protected void onLayout(boolean changed, int l, int t, int r, int b) {
59         super.onLayout(changed, l, t, r, b);
60 
61         layoutHandler.extraLayout(l, t, r, b);
62     }
63 
initialize()64     public void initialize() {
65         photoView = (PhotoView) findViewById(R.id.photo_view);
66         initializeEffectsBar();
67         initializeActionBar();
68         layoutHandler = new ToolbarLayoutHandler(this);
69         idleHandler = new ToolbarIdleHandler(this);
70         idleHandler.killIdle();
71     }
72 
initializeEffectsBar()73     private void initializeEffectsBar() {
74         effectsBar = (EffectsBar) findViewById(R.id.effects_bar);
75         effectsBar.initialize(filterStack, photoView, this);
76     }
77 
initializeActionBar()78     private void initializeActionBar() {
79         final PhotoOutputCallback callback = new PhotoOutputCallback() {
80 
81             @Override
82             public void onReady(Photo photo) {
83                 photoView.setTransitionAnimations(
84                         FadeAnimation.getFadeOutInAnimations(UNDO_REDO_ANIMATION_DURATION));
85                 photoView.update(photo);
86                 progressDialog.dismiss();
87             }
88         };
89 
90         actionBar = (ActionBar) findViewById(R.id.action_bar);
91         actionBar.initialize(new ActionBar.ActionBarListener() {
92 
93             @Override
94             public void onUndo() {
95                 effectsBar.effectsOff(new Runnable() {
96 
97                     @Override
98                     public void run() {
99                         progressDialog = SpinnerProgressDialog.show(Toolbar.this);
100                         filterStack.undo(callback);
101                     }
102                 });
103             }
104 
105             @Override
106             public void onRedo() {
107                 effectsBar.effectsOff(new Runnable() {
108 
109                     @Override
110                     public void run() {
111                         progressDialog = SpinnerProgressDialog.show(Toolbar.this);
112                         filterStack.redo(callback);
113                     }
114                 });
115             }
116 
117             @Override
118             public void onQuickview(final boolean on) {
119                 final PhotoOutputCallback callback = new PhotoOutputCallback() {
120 
121                     @Override
122                     public void onReady(Photo photo) {
123                         photoView.setTransitionAnimations(Rotate3DAnimation.getFlipAnimations(
124                                 on ? Rotate.RIGHT : Rotate.LEFT, QUICKVIEW_ANIMATION_DURATION));
125                         photoView.update(photo);
126                     }
127                 };
128 
129                 if (on) {
130                     effectsBar.effectsOff(new Runnable() {
131 
132                         @Override
133                         public void run() {
134                             effectsBar.setVisibility(INVISIBLE);
135                             filterStack.getSourceCopy(callback);
136                         }
137                     });
138                 } else {
139                     effectsBar.setVisibility(VISIBLE);
140                     filterStack.getResultCopy(callback);
141                 }
142             }
143 
144             @Override
145             public void onSave() {
146                 effectsBar.effectsOff(new Runnable() {
147 
148                     @Override
149                     public void run() {
150                         savePhoto(null);
151                     }
152                 });
153             }
154         });
155     }
156 
openPhoto(Uri uri)157     public void openPhoto(Uri uri) {
158         sourceUri = uri;
159         filterStack.setStackListener(actionBar);
160 
161         // clearPhotoSource() should be called before loading a new source photo to avoid OOM.
162         progressDialog = SpinnerProgressDialog.show(this);
163         filterStack.clearPhotoSource();
164         new LoadScreennailTask(getContext(), new LoadScreennailTask.Callback() {
165 
166             @Override
167             public void onComplete(Bitmap bitmap) {
168                 filterStack.setPhotoSource(Photo.create(bitmap));
169                 filterStack.getResultCopy(new PhotoOutputCallback() {
170 
171                     @Override
172                     public void onReady(Photo photo) {
173                         photoView.update(photo);
174                         progressDialog.dismiss();
175                         effectsBar.setEnabled(photo != null);
176                     }
177                 });
178             }
179         }).execute(sourceUri);
180     }
181 
182     /**
183      * Saves photo and executes runnable (if provided) after saving done.
184      */
savePhoto(final Runnable runnable)185     public void savePhoto(final Runnable runnable) {
186         progressDialog = SpinnerProgressDialog.show(this);
187         filterStack.getResultCopy(new PhotoOutputCallback() {
188 
189             @Override
190             public void onReady(Photo photo) {
191                 new SaveCopyTask(getContext(), sourceUri, new SaveCopyTask.Callback() {
192 
193                     @Override
194                     public void onComplete(Uri uri) {
195                         // TODO: Handle saving failure.
196                         progressDialog.dismiss();
197                         actionBar.disableSave();
198                         if (runnable != null) {
199                             runnable.run();
200                         }
201                     }
202                 }).execute(photo);
203             }
204         });
205     }
206 }
207