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