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