content: /*
   * Copyright (C) 2011 Google Inc.
   * Licensed to The Android Open Source Project.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.android.ex.photo.loaders;
  
  import android.content.ContentResolver;
  import android.content.Context;
  import android.graphics.Bitmap;
  import android.net.Uri;
  import androidx.loader.content.AsyncTaskLoader;
  import android.util.DisplayMetrics;
  
  import com.android.ex.photo.PhotoViewController;
  import com.android.ex.photo.loaders.PhotoBitmapLoaderInterface.BitmapResult;
  import com.android.ex.photo.util.ImageUtils;
  
  /**
   * Loader for the bitmap of a photo.
   */
  public class PhotoBitmapLoader extends AsyncTaskLoader<BitmapResult>
      implements PhotoBitmapLoaderInterface {
      private String mPhotoUri;
      private Bitmap mBitmap;
  
      public PhotoBitmapLoader(Context context, String photoUri) {
          super(context);
          mPhotoUri = photoUri;
      }
  
      @Override
      public void setPhotoUri(String photoUri) {
          mPhotoUri = photoUri;
      }
  
      @Override
      public BitmapResult loadInBackground() {
          BitmapResult result = new BitmapResult();
          Context context = getContext();
          if (context != null && mPhotoUri != null) {
              final ContentResolver resolver = context.getContentResolver();
              try {
                  result = ImageUtils.createLocalBitmap(resolver, Uri.parse(mPhotoUri),
                          PhotoViewController.sMaxPhotoSize);
                  if (result.bitmap != null) {
                      result.bitmap.setDensity(DisplayMetrics.DENSITY_MEDIUM);
                  }
              } catch (UnsupportedOperationException ex) {
                  // We got image bytes, but unable to decode to a Bitmap
                  result.status = BitmapResult.STATUS_EXCEPTION;
              }
          }
  
          return result;
      }
  
      /**
       * Called when there is new data to deliver to the client.  The
       * super class will take care of delivering it; the implementation
       * here just adds a little more logic.
       */
      @Override
      public void deliverResult(BitmapResult result) {
          Bitmap bitmap = result != null ? result.bitmap : null;
          if (isReset()) {
              // An async query came in while the loader is stopped.  We
              // don't need the result.
              if (bitmap != null) {
                  onReleaseResources(bitmap);
              }
              return;
          }
          Bitmap oldBitmap = mBitmap;
          mBitmap = bitmap;
  
          if (isStarted()) {
              // If the Loader is currently started, we can immediately
              // deliver its results.
              super.deliverResult(result);
          }
  
          // At this point we can release the resources associated with
          // 'oldBitmap' if needed; now that the new result is delivered we
          // know that it is no longer in use.
          if (oldBitmap != null && oldBitmap != bitmap && !oldBitmap.isRecycled()) {
              onReleaseResources(oldBitmap);
          }
      }
  
      /**
       * Handles a request to start the Loader.
       */
      @Override
      protected void onStartLoading() {
          if (mBitmap != null) {
              // If we currently have a result available, deliver it
              // immediately.
              BitmapResult result = new BitmapResult();
              result.status = BitmapResult.STATUS_SUCCESS;
              result.bitmap = mBitmap;
              deliverResult(result);
          }
  
          if (takeContentChanged() || mBitmap == null) {
              // If the data has changed since the last time it was loaded
              // or is not currently available, start a load.
              forceLoad();
          }
      }
  
      /**
       * Handles a request to stop the Loader.
       */
      @Override protected void onStopLoading() {
          // Attempt to cancel the current load task if possible.
          cancelLoad();
      }
  
      /**
       * Handles a request to cancel a load.
       */
      @Override
      public void onCanceled(BitmapResult result) {
          super.onCanceled(result);
  
          // At this point we can release the resources associated with 'bitmap'
          // if needed.
          if (result != null) {
              onReleaseResources(result.bitmap);
          }
      }
  
      /**
       * Handles a request to completely reset the Loader.
       */
      @Override
      protected void onReset() {
          super.onReset();
  
          // Ensure the loader is stopped
          onStopLoading();
  
          // At this point we can release the resources associated with 'bitmap'
          // if needed.
          if (mBitmap != null) {
              onReleaseResources(mBitmap);
              mBitmap = null;
          }
      }
  
      /**
       * Helper function to take care of releasing resources associated
       * with an actively loaded data set.
       */
      protected void onReleaseResources(Bitmap bitmap) {
          if (bitmap != null && !bitmap.isRecycled()) {
              bitmap.recycle();
          }
      }
  }
  