ActivityBase.java revision c1f6c073113e20fd0dbeae6d26dcc651c9049fd7
1/* 2 * Copyright (C) 2009 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; 18 19import android.content.BroadcastReceiver; 20import android.content.ContentResolver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.graphics.Bitmap; 25import android.graphics.BitmapFactory; 26import android.graphics.Rect; 27import android.hardware.Camera.Parameters; 28import android.net.Uri; 29import android.os.AsyncTask; 30import android.os.Bundle; 31import android.os.Handler; 32import android.os.Message; 33import android.support.v4.content.LocalBroadcastManager; 34import android.util.Log; 35import android.view.KeyEvent; 36import android.view.View; 37import android.view.Window; 38import android.view.WindowManager; 39import android.view.animation.AlphaAnimation; 40import android.view.animation.Animation; 41import android.view.animation.DecelerateInterpolator; 42 43import com.android.camera.ui.CameraPicker; 44import com.android.camera.ui.LayoutChangeNotifier; 45import com.android.camera.ui.PopupManager; 46import com.android.camera.ui.RotateImageView; 47import com.android.gallery3d.app.AbstractGalleryActivity; 48import com.android.gallery3d.app.AppBridge; 49import com.android.gallery3d.app.GalleryActionBar; 50import com.android.gallery3d.app.PhotoPage; 51import com.android.gallery3d.common.ApiHelper; 52import com.android.gallery3d.ui.ScreenNail; 53import com.android.gallery3d.util.MediaSetUtils; 54 55import java.io.File; 56 57/** 58 * Superclass of Camera and VideoCamera activities. 59 */ 60public abstract class ActivityBase extends AbstractGalleryActivity 61 implements LayoutChangeNotifier.Listener { 62 63 private static final String TAG = "ActivityBase"; 64 private static final int CAMERA_APP_VIEW_TOGGLE_TIME = 100; // milliseconds 65 private static final String ACTION_DELETE_PICTURE = 66 "com.android.gallery3d.action.DELETE_PICTURE"; 67 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = 68 "android.media.action.STILL_IMAGE_CAMERA_SECURE"; 69 // The intent extra for camera from secure lock screen. True if the gallery 70 // should only show newly captured pictures. sSecureAlbumId does not 71 // increment. This is used when switching between camera, camcorder, and 72 // panorama. If the extra is not set, it is in the normal camera mode. 73 public static final String SECURE_CAMERA_EXTRA = "secure_camera"; 74 75 private int mResultCodeForTesting; 76 private Intent mResultDataForTesting; 77 private OnScreenHint mStorageHint; 78 private View mSingleTapArea; 79 80 // The bitmap of the last captured picture thumbnail and the URI of the 81 // original picture. 82 protected Thumbnail mThumbnail; 83 protected int mThumbnailViewWidth; // layout width of the thumbnail 84 protected AsyncTask<Void, Void, Thumbnail> mLoadThumbnailTask; 85 // An imageview showing the last captured picture thumbnail. 86 protected RotateImageView mThumbnailView; 87 protected CameraPicker mCameraPicker; 88 89 protected boolean mOpenCameraFail; 90 protected boolean mCameraDisabled; 91 protected CameraManager.CameraProxy mCameraDevice; 92 protected Parameters mParameters; 93 // The activity is paused. The classes that extend this class should set 94 // mPaused the first thing in onResume/onPause. 95 protected boolean mPaused; 96 protected GalleryActionBar mActionBar; 97 98 // multiple cameras support 99 protected int mNumberOfCameras; 100 protected int mCameraId; 101 // The activity is going to switch to the specified camera id. This is 102 // needed because texture copy is done in GL thread. -1 means camera is not 103 // switching. 104 protected int mPendingSwitchCameraId = -1; 105 106 protected MyAppBridge mAppBridge; 107 protected ScreenNail mCameraScreenNail; // This shows camera preview. 108 // The view containing only camera related widgets like control panel, 109 // indicator bar, focus indicator and etc. 110 protected View mCameraAppView; 111 protected boolean mShowCameraAppView = true; 112 private Animation mCameraAppViewFadeIn; 113 private Animation mCameraAppViewFadeOut; 114 // Secure album id. This should be incremented every time the camera is 115 // launched from the secure lock screen. The id should be the same when 116 // switching between camera, camcorder, and panorama. 117 protected static int sSecureAlbumId; 118 // True if the gallery should only show newly captured pictures or recorded 119 // videos. 120 protected boolean mSecureCamera; 121 122 private long mStorageSpace = Storage.LOW_STORAGE_THRESHOLD; 123 private static final int UPDATE_STORAGE_HINT = 0; 124 private final Handler mHandler = new Handler() { 125 @Override 126 public void handleMessage(Message msg) { 127 switch (msg.what) { 128 case UPDATE_STORAGE_HINT: 129 updateStorageHint(); 130 return; 131 } 132 } 133 }; 134 135 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 136 @Override 137 public void onReceive(Context context, Intent intent) { 138 String action = intent.getAction(); 139 if (action.equals(Intent.ACTION_MEDIA_MOUNTED) 140 || action.equals(Intent.ACTION_MEDIA_UNMOUNTED) 141 || action.equals(Intent.ACTION_MEDIA_CHECKING) 142 || action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) { 143 updateStorageSpaceAndHint(); 144 } 145 } 146 }; 147 148 private boolean mUpdateThumbnailDelayed; 149 private IntentFilter mDeletePictureFilter = 150 new IntentFilter(ACTION_DELETE_PICTURE); 151 private BroadcastReceiver mDeletePictureReceiver = 152 new BroadcastReceiver() { 153 @Override 154 public void onReceive(Context context, Intent intent) { 155 if (mShowCameraAppView) { 156 getLastThumbnailUncached(); 157 } else { 158 mUpdateThumbnailDelayed = true; 159 } 160 } 161 }; 162 163 // close activity when screen turns off 164 private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { 165 @Override 166 public void onReceive(Context context, Intent intent) { 167 finish(); 168 } 169 }; 170 171 protected class CameraOpenThread extends Thread { 172 @Override 173 public void run() { 174 try { 175 mCameraDevice = Util.openCamera(ActivityBase.this, mCameraId); 176 mParameters = mCameraDevice.getParameters(); 177 } catch (CameraHardwareException e) { 178 mOpenCameraFail = true; 179 } catch (CameraDisabledException e) { 180 mCameraDisabled = true; 181 } 182 } 183 } 184 185 @Override 186 public void onCreate(Bundle icicle) { 187 // Setting the flag FLAG_SECURE causes white screen and flickering on Gingerbread, 188 // so we do not set the flag. 189 if (ApiHelper.CAN_USE_FLAG_SECURE) { 190 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); 191 } 192 super.disableToggleStatusBar(); 193 // Set a theme with action bar. It is not specified in manifest because 194 // we want to hide it by default. setTheme must happen before 195 // setContentView. 196 // 197 // This must be set before we call super.onCreate(), where the window's 198 // background is removed. 199 setTheme(R.style.Theme_Gallery); 200 getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 201 if (ApiHelper.HAS_ACTION_BAR) { 202 requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); 203 } else { 204 requestWindowFeature(Window.FEATURE_NO_TITLE); 205 } 206 207 // Check if this is in the secure camera mode. 208 Intent intent = getIntent(); 209 if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(intent.getAction())) { 210 mSecureCamera = true; 211 // Use a new album when this is started from the lock screen. 212 sSecureAlbumId++; 213 } else { 214 mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false); 215 } 216 if (mSecureCamera) { 217 IntentFilter intentFilter = new IntentFilter(); 218 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 219 registerReceiver(mScreenOffReceiver, intentFilter); 220 } 221 super.onCreate(icicle); 222 } 223 224 public boolean isPanoramaActivity() { 225 return false; 226 } 227 228 @Override 229 protected void onResume() { 230 super.onResume(); 231 LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this); 232 manager.registerReceiver(mDeletePictureReceiver, mDeletePictureFilter); 233 234 installIntentFilter(); 235 if(updateStorageHintOnResume()) { 236 updateStorageSpace(); 237 mHandler.sendEmptyMessageDelayed(UPDATE_STORAGE_HINT, 200); 238 } 239 } 240 241 @Override 242 protected void onPause() { 243 super.onPause(); 244 LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this); 245 manager.unregisterReceiver(mDeletePictureReceiver); 246 247 saveThumbnailToFile(); 248 249 if (mLoadThumbnailTask != null) { 250 mLoadThumbnailTask.cancel(true); 251 mLoadThumbnailTask = null; 252 } 253 254 if (mStorageHint != null) { 255 mStorageHint.cancel(); 256 mStorageHint = null; 257 } 258 259 unregisterReceiver(mReceiver); 260 } 261 262 @Override 263 public void setContentView(int layoutResID) { 264 super.setContentView(layoutResID); 265 // getActionBar() should be after setContentView 266 mActionBar = new GalleryActionBar(this); 267 mActionBar.hide(); 268 } 269 270 @Override 271 public boolean onSearchRequested() { 272 return false; 273 } 274 275 @Override 276 public boolean onKeyDown(int keyCode, KeyEvent event) { 277 // Prevent software keyboard or voice search from showing up. 278 if (keyCode == KeyEvent.KEYCODE_SEARCH 279 || keyCode == KeyEvent.KEYCODE_MENU) { 280 if (event.isLongPress()) return true; 281 } 282 if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraAppView) { 283 return true; 284 } 285 286 return super.onKeyDown(keyCode, event); 287 } 288 289 @Override 290 public boolean onKeyUp(int keyCode, KeyEvent event) { 291 if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraAppView) { 292 return true; 293 } 294 return super.onKeyUp(keyCode, event); 295 } 296 297 protected void setResultEx(int resultCode) { 298 mResultCodeForTesting = resultCode; 299 setResult(resultCode); 300 } 301 302 protected void setResultEx(int resultCode, Intent data) { 303 mResultCodeForTesting = resultCode; 304 mResultDataForTesting = data; 305 setResult(resultCode, data); 306 } 307 308 public int getResultCode() { 309 return mResultCodeForTesting; 310 } 311 312 public Intent getResultData() { 313 return mResultDataForTesting; 314 } 315 316 @Override 317 protected void onDestroy() { 318 PopupManager.removeInstance(this); 319 if (mSecureCamera) unregisterReceiver(mScreenOffReceiver); 320 super.onDestroy(); 321 } 322 323 protected void installIntentFilter() { 324 // install an intent filter to receive SD card related events. 325 IntentFilter intentFilter = 326 new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); 327 intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); 328 intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); 329 intentFilter.addAction(Intent.ACTION_MEDIA_CHECKING); 330 intentFilter.addDataScheme("file"); 331 registerReceiver(mReceiver, intentFilter); 332 } 333 334 protected void updateStorageSpace() { 335 mStorageSpace = Storage.getAvailableSpace(); 336 } 337 338 protected long getStorageSpace() { 339 return mStorageSpace; 340 } 341 342 protected void updateStorageSpaceAndHint() { 343 updateStorageSpace(); 344 updateStorageHint(mStorageSpace); 345 } 346 347 protected void updateStorageHint() { 348 updateStorageHint(mStorageSpace); 349 } 350 351 protected boolean updateStorageHintOnResume() { 352 return true; 353 } 354 355 protected void updateStorageHint(long storageSpace) { 356 String message = null; 357 if (storageSpace == Storage.UNAVAILABLE) { 358 message = getString(R.string.no_storage); 359 } else if (storageSpace == Storage.PREPARING) { 360 message = getString(R.string.preparing_sd); 361 } else if (storageSpace == Storage.UNKNOWN_SIZE) { 362 message = getString(R.string.access_sd_fail); 363 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD) { 364 message = getString(R.string.spaceIsLow_content); 365 } 366 367 if (message != null) { 368 if (mStorageHint == null) { 369 mStorageHint = OnScreenHint.makeText(this, message); 370 } else { 371 mStorageHint.setText(message); 372 } 373 mStorageHint.show(); 374 } else if (mStorageHint != null) { 375 mStorageHint.cancel(); 376 mStorageHint = null; 377 } 378 } 379 380 protected void updateThumbnailView() { 381 if (mThumbnail != null) { 382 mThumbnailView.setBitmap(mThumbnail.getBitmap()); 383 mThumbnailView.setVisibility(View.VISIBLE); 384 } else { 385 mThumbnailView.setBitmap(null); 386 mThumbnailView.setVisibility(View.GONE); 387 } 388 } 389 390 protected void getLastThumbnail() { 391 mThumbnail = ThumbnailHolder.getLastThumbnail(getContentResolver()); 392 // Suppose users tap the thumbnail view, go to the gallery, delete the 393 // image, and coming back to the camera. Thumbnail file will be invalid. 394 // Since the new thumbnail will be loaded in another thread later, the 395 // view should be set to gone to prevent from opening the invalid image. 396 updateThumbnailView(); 397 if (mThumbnail == null && !mSecureCamera) { 398 mLoadThumbnailTask = new LoadThumbnailTask(true).execute(); 399 } 400 } 401 402 protected void getLastThumbnailUncached() { 403 if (mSecureCamera) { 404 // Check if the thumbnail is valid. 405 if (mThumbnail != null && !Util.isUriValid( 406 mThumbnail.getUri(), getContentResolver())) { 407 mThumbnail = null; 408 updateThumbnailView(); 409 } 410 } else { 411 if (mLoadThumbnailTask != null) mLoadThumbnailTask.cancel(true); 412 mLoadThumbnailTask = new LoadThumbnailTask(false).execute(); 413 } 414 } 415 416 private class LoadThumbnailTask extends AsyncTask<Void, Void, Thumbnail> { 417 private boolean mLookAtCache; 418 419 public LoadThumbnailTask(boolean lookAtCache) { 420 mLookAtCache = lookAtCache; 421 } 422 423 @Override 424 protected Thumbnail doInBackground(Void... params) { 425 // Load the thumbnail from the file. 426 ContentResolver resolver = getContentResolver(); 427 Thumbnail t = null; 428 if (mLookAtCache) { 429 t = Thumbnail.getLastThumbnailFromFile(getFilesDir(), resolver); 430 } 431 432 if (isCancelled()) return null; 433 434 if (t == null) { 435 Thumbnail result[] = new Thumbnail[1]; 436 // Load the thumbnail from the media provider. 437 int code = Thumbnail.getLastThumbnailFromContentResolver( 438 resolver, result); 439 switch (code) { 440 case Thumbnail.THUMBNAIL_FOUND: 441 return result[0]; 442 case Thumbnail.THUMBNAIL_NOT_FOUND: 443 return null; 444 case Thumbnail.THUMBNAIL_DELETED: 445 cancel(true); 446 return null; 447 } 448 } 449 return t; 450 } 451 452 @Override 453 protected void onPostExecute(Thumbnail thumbnail) { 454 if (isCancelled()) return; 455 mThumbnail = thumbnail; 456 updateThumbnailView(); 457 } 458 } 459 460 protected void gotoGallery() { 461 // Move the next picture with capture animation. "1" means next. 462 mAppBridge.switchWithCaptureAnimation(1); 463 } 464 465 protected void saveThumbnailToFile() { 466 if (mThumbnail != null && !mThumbnail.fromFile()) { 467 new SaveThumbnailTask().execute(mThumbnail); 468 } 469 } 470 471 private class SaveThumbnailTask extends AsyncTask<Thumbnail, Void, Void> { 472 @Override 473 protected Void doInBackground(Thumbnail... params) { 474 final int n = params.length; 475 final File filesDir = getFilesDir(); 476 for (int i = 0; i < n; i++) { 477 params[i].saveLastThumbnailToFile(filesDir); 478 } 479 return null; 480 } 481 } 482 483 // Call this after setContentView. 484 protected void createCameraScreenNail(boolean getPictures) { 485 mCameraAppView = findViewById(R.id.camera_app_root); 486 Bundle data = new Bundle(); 487 String path; 488 if (mSecureCamera) { 489 path = "/secure/all/" + sSecureAlbumId; 490 } else { 491 path = "/local/all/"; 492 // Intent mode does not show camera roll. Use 0 as a work around for 493 // invalid bucket id. 494 // TODO: add support of empty media set in gallery. 495 path += (getPictures ? MediaSetUtils.CAMERA_BUCKET_ID : "0"); 496 } 497 data.putString(PhotoPage.KEY_MEDIA_SET_PATH, path); 498 data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, path); 499 500 // Send an AppBridge to gallery to enable the camera preview. 501 mAppBridge = new MyAppBridge(); 502 data.putParcelable(PhotoPage.KEY_APP_BRIDGE, mAppBridge); 503 getStateManager().startState(PhotoPage.class, data); 504 mCameraScreenNail = mAppBridge.getCameraScreenNail(); 505 } 506 507 private class HideCameraAppView implements Animation.AnimationListener { 508 @Override 509 public void onAnimationEnd(Animation animation) { 510 // We cannot set this as GONE because we want to receive the 511 // onLayoutChange() callback even when we are invisible. 512 mCameraAppView.setVisibility(View.INVISIBLE); 513 } 514 515 @Override 516 public void onAnimationRepeat(Animation animation) { 517 } 518 519 @Override 520 public void onAnimationStart(Animation animation) { 521 } 522 } 523 524 protected void updateCameraAppView() { 525 // Initialize the animation. 526 if (mCameraAppViewFadeIn == null) { 527 mCameraAppViewFadeIn = new AlphaAnimation(0f, 1f); 528 mCameraAppViewFadeIn.setDuration(CAMERA_APP_VIEW_TOGGLE_TIME); 529 mCameraAppViewFadeIn.setInterpolator(new DecelerateInterpolator()); 530 531 mCameraAppViewFadeOut = new AlphaAnimation(1f, 0f); 532 mCameraAppViewFadeOut.setDuration(CAMERA_APP_VIEW_TOGGLE_TIME); 533 mCameraAppViewFadeOut.setInterpolator(new DecelerateInterpolator()); 534 mCameraAppViewFadeOut.setAnimationListener(new HideCameraAppView()); 535 } 536 537 if (mShowCameraAppView) { 538 mCameraAppView.setVisibility(View.VISIBLE); 539 // The "transparent region" is not recomputed when a sibling of 540 // SurfaceView changes visibility (unless it involves GONE). It's 541 // been broken since 1.0. Call requestLayout to work around it. 542 mCameraAppView.requestLayout(); 543 mCameraAppView.startAnimation(mCameraAppViewFadeIn); 544 } else { 545 mCameraAppView.startAnimation(mCameraAppViewFadeOut); 546 } 547 } 548 549 protected void onFullScreenChanged(boolean full) { 550 if (mShowCameraAppView == full) return; 551 mShowCameraAppView = full; 552 if (mPaused || isFinishing()) return; 553 updateCameraAppView(); 554 555 // If we received DELETE_PICTURE broadcasts while the Camera UI is 556 // hidden, we update the thumbnail now. 557 if (full && mUpdateThumbnailDelayed) { 558 getLastThumbnailUncached(); 559 mUpdateThumbnailDelayed = false; 560 } 561 } 562 563 @Override 564 public GalleryActionBar getGalleryActionBar() { 565 return mActionBar; 566 } 567 568 // Preview frame layout has changed. 569 @Override 570 public void onLayoutChange(View v, int left, int top, int right, int bottom) { 571 if (mAppBridge == null) return; 572 573 int width = right - left; 574 int height = bottom - top; 575 if (ApiHelper.HAS_SURFACE_TEXTURE) { 576 CameraScreenNail screenNail = (CameraScreenNail) mCameraScreenNail; 577 if (Util.getDisplayRotation(this) % 180 == 0) { 578 screenNail.setPreviewFrameLayoutSize(width, height); 579 } else { 580 // Swap the width and height. Camera screen nail draw() is based on 581 // natural orientation, not the view system orientation. 582 screenNail.setPreviewFrameLayoutSize(height, width); 583 } 584 } 585 586 // Find out the coordinates of the preview frame relative to GL 587 // root view. 588 View root = (View) getGLRoot(); 589 int[] rootLocation = new int[2]; 590 int[] viewLocation = new int[2]; 591 root.getLocationInWindow(rootLocation); 592 v.getLocationInWindow(viewLocation); 593 594 int l = viewLocation[0] - rootLocation[0]; 595 int t = viewLocation[1] - rootLocation[1]; 596 int r = l + width; 597 int b = t + height; 598 Rect frame = new Rect(l, t, r, b); 599 Log.d(TAG, "set CameraRelativeFrame as " + frame); 600 mAppBridge.setCameraRelativeFrame(frame); 601 } 602 603 protected void setSingleTapUpListener(View singleTapArea) { 604 mSingleTapArea = singleTapArea; 605 } 606 607 private boolean onSingleTapUp(int x, int y) { 608 // Ignore if listener is null or the camera control is invisible. 609 if (mSingleTapArea == null || !mShowCameraAppView) return false; 610 611 int[] relativeLocation = Util.getRelativeLocation((View) getGLRoot(), 612 mSingleTapArea); 613 x -= relativeLocation[0]; 614 y -= relativeLocation[1]; 615 if (x >= 0 && x < mSingleTapArea.getWidth() && y >= 0 616 && y < mSingleTapArea.getHeight()) { 617 onSingleTapUp(mSingleTapArea, x, y); 618 return true; 619 } 620 return false; 621 } 622 623 protected void onSingleTapUp(View view, int x, int y) { 624 } 625 626 protected void setSwipingEnabled(boolean enabled) { 627 mAppBridge.setSwipingEnabled(enabled); 628 } 629 630 protected void notifyScreenNailChanged() { 631 mAppBridge.notifyScreenNailChanged(); 632 } 633 634 protected void onPreviewTextureCopied() { 635 } 636 637 protected void addSecureAlbumItemIfNeeded(boolean isVideo, Uri uri) { 638 if (mSecureCamera) { 639 int id = Integer.parseInt(uri.getLastPathSegment()); 640 mAppBridge.addSecureAlbumItem(isVideo, id); 641 } 642 } 643 644 ////////////////////////////////////////////////////////////////////////// 645 // The is the communication interface between the Camera Application and 646 // the Gallery PhotoPage. 647 ////////////////////////////////////////////////////////////////////////// 648 649 class MyAppBridge extends AppBridge implements CameraScreenNail.Listener { 650 @SuppressWarnings("hiding") 651 private ScreenNail mCameraScreenNail; 652 private Server mServer; 653 654 @Override 655 public ScreenNail attachScreenNail() { 656 if (mCameraScreenNail == null) { 657 if (ApiHelper.HAS_SURFACE_TEXTURE) { 658 mCameraScreenNail = new CameraScreenNail(this); 659 } else { 660 Bitmap b = BitmapFactory.decodeResource(getResources(), 661 R.drawable.wallpaper_picker_preview); 662 mCameraScreenNail = new StaticBitmapScreenNail(b); 663 } 664 } 665 return mCameraScreenNail; 666 } 667 668 @Override 669 public void detachScreenNail() { 670 mCameraScreenNail = null; 671 } 672 673 public ScreenNail getCameraScreenNail() { 674 return mCameraScreenNail; 675 } 676 677 // Return true if the tap is consumed. 678 @Override 679 public boolean onSingleTapUp(int x, int y) { 680 return ActivityBase.this.onSingleTapUp(x, y); 681 } 682 683 // This is used to notify that the screen nail will be drawn in full screen 684 // or not in next draw() call. 685 @Override 686 public void onFullScreenChanged(boolean full) { 687 ActivityBase.this.onFullScreenChanged(full); 688 } 689 690 @Override 691 public void requestRender() { 692 getGLRoot().requestRender(); 693 } 694 695 @Override 696 public void onPreviewTextureCopied() { 697 ActivityBase.this.onPreviewTextureCopied(); 698 } 699 700 @Override 701 public void setServer(Server s) { 702 mServer = s; 703 } 704 705 @Override 706 public boolean isPanorama() { 707 return ActivityBase.this.isPanoramaActivity(); 708 } 709 710 @Override 711 public boolean isStaticCamera() { 712 return !ApiHelper.HAS_SURFACE_TEXTURE; 713 } 714 715 public void addSecureAlbumItem(boolean isVideo, int id) { 716 if (mServer != null) mServer.addSecureAlbumItem(isVideo, id); 717 } 718 719 private void setCameraRelativeFrame(Rect frame) { 720 if (mServer != null) mServer.setCameraRelativeFrame(frame); 721 } 722 723 private void switchWithCaptureAnimation(int offset) { 724 if (mServer != null) mServer.switchWithCaptureAnimation(offset); 725 } 726 727 private void setSwipingEnabled(boolean enabled) { 728 if (mServer != null) mServer.setSwipingEnabled(enabled); 729 } 730 731 private void notifyScreenNailChanged() { 732 if (mServer != null) mServer.notifyScreenNailChanged(); 733 } 734 } 735} 736