Full Code of glassLake/PhotoPicker for AI

master 45621240a331 cached
87 files
196.6 KB
50.2k tokens
333 symbols
1 requests
Download .txt
Showing preview only (223K chars total). Download the full file or copy to clipboard to get everything.
Repository: glassLake/PhotoPicker
Branch: master
Commit: 45621240a331
Files: 87
Total size: 196.6 KB

Directory structure:
gitextract_jrq830pw/

├── .gitattributes
├── .gitignore
├── .travis.yml
├── LICENSE
├── PhotoPicker/
│   ├── .gitignore
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── me/
│           │       └── iwf/
│           │           └── photopicker/
│           │               ├── PhotoPagerActivity.java
│           │               ├── PhotoPickUtils.java
│           │               ├── PhotoPicker.java
│           │               ├── PhotoPickerActivity.java
│           │               ├── PhotoPreview.java
│           │               ├── adapter/
│           │               │   ├── PhotoGridAdapter.java
│           │               │   ├── PhotoPagerAdapter.java
│           │               │   ├── PopupDirectoryListAdapter.java
│           │               │   └── SelectableAdapter.java
│           │               ├── entity/
│           │               │   ├── Photo.java
│           │               │   └── PhotoDirectory.java
│           │               ├── event/
│           │               │   ├── OnItemCheckListener.java
│           │               │   ├── OnPhotoClickListener.java
│           │               │   └── Selectable.java
│           │               ├── fragment/
│           │               │   ├── ImagePagerFragment.java
│           │               │   └── PhotoPickerFragment.java
│           │               ├── utils/
│           │               │   ├── ExifUtils.java
│           │               │   ├── ImageCaptureManager.java
│           │               │   ├── MediaStoreHelper.java
│           │               │   ├── PhotoDirectoryLoader.java
│           │               │   └── PhotoPickerIntent.java
│           │               └── widget/
│           │                   ├── MultiPickResultView.java
│           │                   ├── PhotoAdapter.java
│           │                   ├── SquareItemLayout.java
│           │                   ├── Titlebar.java
│           │                   └── TouchImageView.java
│           └── res/
│               ├── anim/
│               │   ├── dialog_enter.xml
│               │   └── dialog_exit.xml
│               ├── drawable/
│               │   ├── __picker_bg_material_item.xml
│               │   ├── __picker_camera.xml
│               │   ├── __picker_checkbox_bg.xml
│               │   ├── __picker_default_weixin.xml
│               │   ├── __picker_delete.xml
│               │   └── __picker_photo_bg.xml
│               ├── drawable-v21/
│               │   └── __picker_bg_material_item.xml
│               ├── layout/
│               │   ├── __picker_activity_photo_pager.xml
│               │   ├── __picker_activity_photo_picker.xml
│               │   ├── __picker_fragment_photo_picker.xml
│               │   ├── __picker_item_directory.xml
│               │   ├── __picker_item_photo.xml
│               │   ├── __picker_picker_fragment_image_pager.xml
│               │   ├── __picker_picker_item_pager.xml
│               │   ├── __picker_toolbar.xml
│               │   └── view_titlebar.xml
│               ├── menu/
│               │   ├── __picker_menu_picker.xml
│               │   └── __picker_menu_preview.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimen.xml
│               │   ├── strings.xml
│               │   ├── styles.xml
│               │   └── values.xml
│               ├── values-pt/
│               │   └── strings.xml
│               ├── values-v21/
│               │   └── colors.xml
│               └── values-zh/
│                   └── strings.xml
├── PhotoPicker-release.aar
├── README.md
├── build.gradle
├── circle.sh
├── circle.yml
├── demo.apk
├── gradle/
│   ├── gradle-mvn-push.gradle
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── photopickerdemo/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── me/
│           │       └── iwf/
│           │           └── PhotoPickerDemo/
│           │               ├── MainActivity.java
│           │               ├── PicChosenListInterface.java
│           │               └── RecyclerItemClickListener.java
│           └── res/
│               ├── layout/
│               │   └── activity_main.xml
│               ├── values/
│               │   ├── color.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               └── values-zh/
│                   └── strings.xml
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================

# Auto detect text files and perform LF normalization
* text=auto


================================================
FILE: .gitignore
================================================
.idea/**
.gradle
/local.properties
.DS_Store
/build
/captures

# Built application files


# Files for the Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/

# Gradle files
.gradle/
/PhotoPicker/PhotoPicker-PhotoPicker.iml
build/
/*/build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

*.iml


================================================
FILE: .travis.yml
================================================
language: android

before_install:
 - chmod +x gradlew

android:
  components:
    - tools
    - platform-tools
    - build-tools-23.0.3
    - android-23
    - extra-android-m2repository

notifications:
  email: false

sudo: false

script: ./gradlew build

================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2015 Huang Donglu

   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.



================================================
FILE: PhotoPicker/.gitignore
================================================
/build
PhotoPicker-PhotoPicker.iml

================================================
FILE: PhotoPicker/build.gradle
================================================
apply plugin: 'com.android.library'

android {
  compileSdkVersion 23
  buildToolsVersion "23.0.3"
  resourcePrefix "__picker_"

  defaultConfig {
    minSdkVersion 11
    targetSdkVersion 23
    versionCode 1
    versionName "0.8.5"
  }
}
apply from: '../gradle/gradle-mvn-push.gradle'

repositories {
  jcenter()
  mavenCentral()  // GPUImage for Android
}

dependencies {
  compile 'com.android.support:support-v4:23.4.0'
  compile 'com.android.support:appcompat-v7:23.4.0'
  compile 'com.android.support:design:23.4.0'
  compile 'com.android.support:recyclerview-v7:23.4.0'
  compile 'com.android.support:support-annotations:23.4.0'
  compile 'com.nineoldandroids:library:2.4.0'
  compile 'com.github.bumptech.glide:glide:3.7.0'
  compile 'jp.wasabeef:glide-transformations:2.0.1'

}



================================================
FILE: PhotoPicker/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest package="me.iwf.photopicker">

</manifest>


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPagerActivity.java
================================================
package me.iwf.photopicker;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.List;

import me.iwf.photopicker.fragment.ImagePagerFragment;
import me.iwf.photopicker.widget.MultiPickResultView;
import me.iwf.photopicker.widget.Titlebar;

import static me.iwf.photopicker.PhotoPicker.KEY_SELECTED_PHOTOS;
import static me.iwf.photopicker.PhotoPreview.EXTRA_CURRENT_ITEM;
import static me.iwf.photopicker.PhotoPreview.EXTRA_PHOTOS;
import static me.iwf.photopicker.PhotoPreview.EXTRA_SHOW_DELETE;
import static me.iwf.photopicker.PhotoPreview.EXTRA_ACTION;

/**
 * Created by donglua on 15/6/24.
 */
public class PhotoPagerActivity extends AppCompatActivity {

  private ImagePagerFragment pagerFragment;

  //private ActionBar actionBar;
  private boolean showDelete;
  private Titlebar titlebar;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.__picker_activity_photo_pager);

    int currentItem = getIntent().getIntExtra(EXTRA_CURRENT_ITEM, 0);
    List<String> paths = getIntent().getStringArrayListExtra(EXTRA_PHOTOS);
    showDelete = getIntent().getBooleanExtra(EXTRA_SHOW_DELETE, true);
    int action = getIntent().getIntExtra(EXTRA_ACTION, MultiPickResultView.ACTION_ONLY_SHOW);

    if (pagerFragment == null) {
      pagerFragment =
          (ImagePagerFragment) getSupportFragmentManager().findFragmentById(R.id.photoPagerFragment);
    }
    pagerFragment.setPhotos(paths, currentItem);
    titlebar = (Titlebar) findViewById(R.id.titlebar);
    titlebar.init(this);
    if (action == MultiPickResultView.ACTION_SELECT){
      titlebar.setRitht(getApplicationContext().getResources().getDrawable(R.drawable.__picker_delete), "", new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          int position = pagerFragment.getViewPager().getCurrentItem();
          if (pagerFragment.getPaths().size() >0){
            pagerFragment.getPaths().remove(position);
            pagerFragment.getViewPager().getAdapter().notifyDataSetChanged();
            if (pagerFragment.getPaths().size() ==0){
              titlebar.setTitle(getString(R.string.__picker_preview) +" "+getString(R.string.__picker_image_index, 0,
                      pagerFragment.getPaths().size()));
            }

          }


        }
      });
    }

    titlebar.setTitle(getString(R.string.__picker_preview));


    /*Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(mToolbar);

    actionBar = getSupportActionBar();

   // centerActionBarTitle(this);

    if (actionBar != null) {
      actionBar.setDisplayHomeAsUpEnabled(true);
      updateActionBarTitle();
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        actionBar.setElevation(25);
      }
    }*/


    pagerFragment.getViewPager().addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
      @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        titlebar.setTitle(getString(R.string.__picker_preview) +" "+getString(R.string.__picker_image_index, pagerFragment.getViewPager().getCurrentItem() + 1,
                pagerFragment.getPaths().size()));
       // updateActionBarTitle();
      }
    });
  }

  //把actionBar的文字标题居中
  public static void centerActionBarTitle(Activity activity)
  {
    int titleId = activity.getResources().getIdentifier("action_bar_title", "id", "android");
    if (titleId<=0)return;
    TextView titleTextView = (TextView)activity.findViewById(titleId);
    DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
    LinearLayout.LayoutParams txvPars = (LinearLayout.LayoutParams) titleTextView.getLayoutParams();
    txvPars.gravity = Gravity.CENTER_HORIZONTAL;
    txvPars.width = metrics.widthPixels;
    titleTextView.setLayoutParams(txvPars);
    titleTextView.setGravity(Gravity.CENTER);
  }


  @Override public boolean onCreateOptionsMenu(Menu menu) {
    if (showDelete){
      getMenuInflater().inflate(R.menu.__picker_menu_preview, menu);
    }
    return true;
  }


  @Override public void onBackPressed() {

    Intent intent = new Intent();
    intent.putExtra(KEY_SELECTED_PHOTOS, pagerFragment.getPaths());
    setResult(RESULT_OK, intent);
    finish();

    super.onBackPressed();
  }


  @Override
  public boolean onOptionsItemSelected(MenuItem item) {

    if (item.getItemId() == android.R.id.home) {
      onBackPressed();
      return true;
    }

    if (item.getItemId() == R.id.delete) {
      final int index = pagerFragment.getCurrentItem();

      final String deletedPath =  pagerFragment.getPaths().get(index);

      Snackbar snackbar = Snackbar.make(pagerFragment.getView(), R.string.__picker_deleted_a_photo,
          Snackbar.LENGTH_LONG);

      if (pagerFragment.getPaths().size() <= 1) {

        // show confirm dialog
        new AlertDialog.Builder(this)
            .setTitle(R.string.__picker_confirm_to_delete)
            .setPositiveButton(R.string.__picker_yes, new DialogInterface.OnClickListener() {
              @Override public void onClick(DialogInterface dialogInterface, int i) {
                dialogInterface.dismiss();
                pagerFragment.getPaths().remove(index);
                pagerFragment.getViewPager().getAdapter().notifyDataSetChanged();
                onBackPressed();
              }
            })
            .setNegativeButton(R.string.__picker_cancel, new DialogInterface.OnClickListener() {
              @Override public void onClick(DialogInterface dialogInterface, int i) {
                dialogInterface.dismiss();
              }
            })
            .show();

      } else {

        snackbar.show();

        pagerFragment.getPaths().remove(index);
        pagerFragment.getViewPager().getAdapter().notifyDataSetChanged();
      }

      snackbar.setAction(R.string.__picker_undo, new View.OnClickListener() {
        @Override public void onClick(View view) {
          if (pagerFragment.getPaths().size() > 0) {
            pagerFragment.getPaths().add(index, deletedPath);
          } else {
            pagerFragment.getPaths().add(deletedPath);
          }
          pagerFragment.getViewPager().getAdapter().notifyDataSetChanged();
          pagerFragment.getViewPager().setCurrentItem(index, true);
        }
      });

      return true;
    }

    return super.onOptionsItemSelected(item);
  }

 /* public void updateActionBarTitle() {
    if (actionBar != null) actionBar.setTitle(
        getString(R.string.__picker_image_index, pagerFragment.getViewPager().getCurrentItem() + 1,
            pagerFragment.getPaths().size()));
  }*/
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPickUtils.java
================================================
package me.iwf.photopicker;

import android.app.Activity;
import android.content.Intent;

import java.util.ArrayList;

/**
 * Created by Administrator on 2016/8/5 0005.
 */
public class PhotoPickUtils {

    public static void onActivityResult(int requestCode, int resultCode, Intent data,PickHandler pickHandler ) {

        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == PhotoPicker.REQUEST_CODE) {//第一次,选择图片后返回
                if (data != null) {
                    ArrayList<String> photos = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
                    pickHandler.onPickSuccess(photos);
                   /* if (photos != null){
                        if (photos.size() >0){

                        }else {
                            pickHandler.onPickFail("未选择图片1");
                        }
                    }else {
                        pickHandler.onPickFail("未选择图片2");
                    }*/
                } else {
                    pickHandler.onPickFail("选择图片失败");
                }
            }else if (requestCode == PhotoPreview.REQUEST_CODE){//如果是预览与删除后返回
                if (data != null) {
                    ArrayList<String> photos = data.getStringArrayListExtra(PhotoPicker.KEY_SELECTED_PHOTOS);
                    pickHandler.onPreviewBack(photos);
                } else {
                   // pickHandler.onPickFail("选择图片失败");
                }

            }
        }else {

            if (requestCode == PhotoPicker.REQUEST_CODE){
                pickHandler.onPickCancle();
            }
        }


    }

    public static void startPick(Activity context,boolean showGif,int photoCount,ArrayList<String> photos){
        PhotoPicker.builder()
                .setPhotoCount(photoCount)
                .setShowCamera(false)
                .setShowGif(showGif)
                .setSelected(photos)
                .setPreviewEnabled(true)
                .start(context, PhotoPicker.REQUEST_CODE);
    }



    public interface  PickHandler{
        void onPickSuccess(ArrayList<String> photos);
        void onPreviewBack(ArrayList<String> photos);
        void onPickFail(String error);
        void onPickCancle();
    }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPicker.java
================================================
package me.iwf.photopicker;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import java.util.ArrayList;

/**
 * Created by Donglua on 16/6/25.
 * Builder class to ease Intent setup.
 */
public class PhotoPicker {

  public static final int REQUEST_CODE             = 233;

  public final static int DEFAULT_MAX_COUNT        = 9;
  public final static int DEFAULT_COLUMN_NUMBER    = 3;

  public final static String KEY_SELECTED_PHOTOS   = "SELECTED_PHOTOS";

  public final static String EXTRA_MAX_COUNT       = "MAX_COUNT";
  public final static String EXTRA_SHOW_CAMERA     = "SHOW_CAMERA";
  public final static String EXTRA_SHOW_GIF        = "SHOW_GIF";
  public final static String EXTRA_GRID_COLUMN     = "column";
  public final static String EXTRA_ORIGINAL_PHOTOS = "ORIGINAL_PHOTOS";
  public final static String EXTRA_PREVIEW_ENABLED = "PREVIEW_ENABLED";

  public static PhotoPickerBuilder builder() {
    return new PhotoPickerBuilder();
  }

  public static class PhotoPickerBuilder {
    private Bundle mPickerOptionsBundle;
    private Intent mPickerIntent;

    public PhotoPickerBuilder() {
      mPickerOptionsBundle = new Bundle();
      mPickerIntent = new Intent();
    }

    /**
     * Send the Intent from an Activity with a custom request code
     *
     * @param activity    Activity to receive result
     * @param requestCode requestCode for result
     */
    public void start(@NonNull Activity activity, int requestCode) {
      activity.startActivityForResult(getIntent(activity), requestCode);
    }

    /**
     * Send the Intent with a custom request code
     *
     * @param fragment    Fragment to receive result
     * @param requestCode requestCode for result
     */
    public void start(@NonNull Context context, @NonNull android.support.v4.app.Fragment fragment, int requestCode) {
      fragment.startActivityForResult(getIntent(context), requestCode);
    }

    /**
     * Send the Intent with a custom request code
     *
     * @param fragment    Fragment to receive result
     */
    public void start(@NonNull Context context, @NonNull android.support.v4.app.Fragment fragment) {
      fragment.startActivityForResult(getIntent(context), REQUEST_CODE);
    }

    /**
     * Get Intent to start {@link PhotoPickerActivity}
     *
     * @return Intent for {@link PhotoPickerActivity}
     */
    public Intent getIntent(@NonNull Context context) {
      mPickerIntent.setClass(context, PhotoPickerActivity.class);
      mPickerIntent.putExtras(mPickerOptionsBundle);
      return mPickerIntent;
    }

    /**
     * Send the crop Intent from an Activity
     *
     * @param activity Activity to receive result
     */
    public void start(@NonNull Activity activity) {
      start(activity, REQUEST_CODE);
    }

    public PhotoPickerBuilder setPhotoCount(int photoCount) {
      mPickerOptionsBundle.putInt(EXTRA_MAX_COUNT, photoCount);
      return this;
    }

    public PhotoPickerBuilder setGridColumnCount(int columnCount) {
      mPickerOptionsBundle.putInt(EXTRA_GRID_COLUMN, columnCount);
      return this;
    }

    public PhotoPickerBuilder setShowGif(boolean showGif) {
      mPickerOptionsBundle.putBoolean(EXTRA_SHOW_GIF, showGif);
      return this;
    }

    public PhotoPickerBuilder setShowCamera(boolean showCamera) {
      mPickerOptionsBundle.putBoolean(EXTRA_SHOW_CAMERA, showCamera);
      return this;
    }

    public PhotoPickerBuilder setSelected(ArrayList<String> imagesUri) {
      mPickerOptionsBundle.putStringArrayList(EXTRA_ORIGINAL_PHOTOS, imagesUri);
      return this;
    }

    public PhotoPickerBuilder setPreviewEnabled(boolean previewEnabled) {
      mPickerOptionsBundle.putBoolean(EXTRA_PREVIEW_ENABLED, previewEnabled);
      return this;
    }
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPickerActivity.java
================================================
package me.iwf.photopicker;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

import me.iwf.photopicker.entity.Photo;
import me.iwf.photopicker.event.OnItemCheckListener;
import me.iwf.photopicker.fragment.ImagePagerFragment;
import me.iwf.photopicker.fragment.PhotoPickerFragment;
import me.iwf.photopicker.widget.Titlebar;

import static android.widget.Toast.LENGTH_LONG;
import static me.iwf.photopicker.PhotoPicker.DEFAULT_COLUMN_NUMBER;
import static me.iwf.photopicker.PhotoPicker.DEFAULT_MAX_COUNT;
import static me.iwf.photopicker.PhotoPicker.EXTRA_GRID_COLUMN;
import static me.iwf.photopicker.PhotoPicker.EXTRA_MAX_COUNT;
import static me.iwf.photopicker.PhotoPicker.EXTRA_ORIGINAL_PHOTOS;
import static me.iwf.photopicker.PhotoPicker.EXTRA_PREVIEW_ENABLED;
import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_CAMERA;
import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_GIF;
import static me.iwf.photopicker.PhotoPicker.KEY_SELECTED_PHOTOS;

public class PhotoPickerActivity extends AppCompatActivity {

  private PhotoPickerFragment pickerFragment;
  private ImagePagerFragment imagePagerFragment;
  //private MenuItem menuDoneItem;

  private int maxCount = DEFAULT_MAX_COUNT;

  /** to prevent multiple calls to inflate menu */
 // private boolean menuIsInflated = false;

  private boolean showGif = false;
  private int columnNumber = DEFAULT_COLUMN_NUMBER;
  private ArrayList<String> originalPhotos = null;

  private Titlebar titlebar;


  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    boolean showCamera      = getIntent().getBooleanExtra(EXTRA_SHOW_CAMERA, true);
    boolean showGif         = getIntent().getBooleanExtra(EXTRA_SHOW_GIF, false);
    boolean previewEnabled  = getIntent().getBooleanExtra(EXTRA_PREVIEW_ENABLED, true);

    setShowGif(showGif);

    setContentView(R.layout.__picker_activity_photo_picker);

    titlebar = (Titlebar) findViewById(R.id.titlebar);
    titlebar.init(this);

   /* Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(mToolbar);
    setTitle("");//去掉原生的标题

    //将原生的返回图标换掉
    mToolbar.setNavigationIcon(R.drawable.__picker_delete);
    mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        PhotoPickerActivity.this.finish();
      }
    });



    ActionBar actionBar = getSupportActionBar();

    assert actionBar != null;
    actionBar.setDisplayHomeAsUpEnabled(true);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      actionBar.setElevation(25);
    }*/

    maxCount = getIntent().getIntExtra(EXTRA_MAX_COUNT, DEFAULT_MAX_COUNT);
    columnNumber = getIntent().getIntExtra(EXTRA_GRID_COLUMN, DEFAULT_COLUMN_NUMBER);
    originalPhotos = getIntent().getStringArrayListExtra(EXTRA_ORIGINAL_PHOTOS);

    pickerFragment = (PhotoPickerFragment) getSupportFragmentManager().findFragmentByTag("tag");
    if (pickerFragment == null) {
      pickerFragment = PhotoPickerFragment
          .newInstance(showCamera, showGif, previewEnabled, columnNumber, maxCount, originalPhotos);
      getSupportFragmentManager()
          .beginTransaction()
          .replace(R.id.container, pickerFragment, "tag")
          .commit();
      getSupportFragmentManager().executePendingTransactions();
    }

    //右边的点击事件
    titlebar.getTvRight().setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        ArrayList<String> photos = pickerFragment.getPhotoGridAdapter().getSelectedPhotoPaths();
        if (photos != null && photos.size() > 0){
          Intent intent = new Intent();
          intent.putStringArrayListExtra(KEY_SELECTED_PHOTOS, photos);
          setResult(RESULT_OK, intent);
          finish();
        }else {
          Toast.makeText(getApplicationContext(),"还没有选择图片",Toast.LENGTH_SHORT).show();
        }
      }
    });

    pickerFragment.getPhotoGridAdapter().setOnItemCheckListener(new OnItemCheckListener() {
      @Override public boolean OnItemCheck(int position, Photo photo, final boolean isCheck, int selectedItemCount) {

        int total = selectedItemCount + (isCheck ? -1 : 1);

       // menuDoneItem.setEnabled(total > 0);


        if (maxCount <= 1) {
          List<Photo> photos = pickerFragment.getPhotoGridAdapter().getSelectedPhotos();
          if (!photos.contains(photo)) {
            photos.clear();
            pickerFragment.getPhotoGridAdapter().notifyDataSetChanged();
          }
          return true;
        }

        if (total > maxCount) {
          Toast.makeText(getActivity(), getString(R.string.__picker_over_max_count_tips, maxCount),
              LENGTH_LONG).show();
          return false;
        }
        titlebar.getTvRight().setText(getString(R.string.__picker_done_with_count, total, maxCount));
        return true;
      }
    });

  }


  /**
   * Overriding this method allows us to run our exit animation first, then exiting
   * the activity when it complete.
   */
  @Override public void onBackPressed() {
    if (imagePagerFragment != null && imagePagerFragment.isVisible()) {
      imagePagerFragment.runExitAnimation(new Runnable() {
        public void run() {
          if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            getSupportFragmentManager().popBackStack();
          }
        }
      });
    } else {
      super.onBackPressed();
    }
  }


  public void addImagePagerFragment(ImagePagerFragment imagePagerFragment) {
    this.imagePagerFragment = imagePagerFragment;
    getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.container, this.imagePagerFragment)
        .addToBackStack(null)
        .commit();
  }

 /* @Override public boolean onCreateOptionsMenu(Menu menu) {
    if (!menuIsInflated) {
      getMenuInflater().inflate(R.menu.__picker_menu_picker, menu);
      menuDoneItem = menu.findItem(R.id.done);
      if (originalPhotos != null && originalPhotos.size() > 0) {
        menuDoneItem.setEnabled(true);
        menuDoneItem.setTitle(
                getString(R.string.__picker_done_with_count, originalPhotos.size(), maxCount));
      } else {
        menuDoneItem.setEnabled(false);
      }

      menuIsInflated = true;
      return true;
    }
    return false;
  }*/


 /* @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == android.R.id.home) {
      super.onBackPressed();
      return true;
    }

    if (item.getItemId() == R.id.done) {
      Intent intent = new Intent();
      ArrayList<String> selectedPhotos = pickerFragment.getPhotoGridAdapter().getSelectedPhotoPaths();
      intent.putStringArrayListExtra(KEY_SELECTED_PHOTOS, selectedPhotos);
      setResult(RESULT_OK, intent);
      finish();
      return true;
    }

    return super.onOptionsItemSelected(item);
  }*/

  public PhotoPickerActivity getActivity() {
    return this;
  }

  public boolean isShowGif() {
    return showGif;
  }

  public void setShowGif(boolean showGif) {
    this.showGif = showGif;
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPreview.java
================================================
package me.iwf.photopicker;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import java.util.ArrayList;

/**
 * Created by Donglua on 16/6/25.
 * Builder class to ease Intent setup.
 */
public class PhotoPreview {

  public final static int REQUEST_CODE = 666;

  public final static String EXTRA_CURRENT_ITEM = "current_item";
  public final static String EXTRA_PHOTOS       = "photos";
  public final static String EXTRA_SHOW_DELETE  = "show_delete";

  public final static String EXTRA_ACTION       = "action";


  public static PhotoPreviewBuilder builder() {
    return new PhotoPreviewBuilder();
  }


  public static class PhotoPreviewBuilder {
    private Bundle mPreviewOptionsBundle;
    private Intent mPreviewIntent;

    public PhotoPreviewBuilder() {
      mPreviewOptionsBundle = new Bundle();
      mPreviewIntent = new Intent();
    }

    /**
     * Send the Intent from an Activity with a custom request code
     *
     * @param activity    Activity to receive result
     * @param requestCode requestCode for result
     */
    public void start(@NonNull Activity activity, int requestCode) {
      activity.startActivityForResult(getIntent(activity), requestCode);
    }

    /**
     * Send the Intent with a custom request code
     *
     * @param fragment    Fragment to receive result
     * @param requestCode requestCode for result
     */
    public void start(@NonNull Context context, @NonNull android.support.v4.app.Fragment fragment, int requestCode) {
      fragment.startActivityForResult(getIntent(context), requestCode);
    }

    /**
     * Send the Intent with a custom request code
     *
     * @param fragment    Fragment to receive result
     */
    public void start(@NonNull Context context, @NonNull android.support.v4.app.Fragment fragment) {
      fragment.startActivityForResult(getIntent(context), REQUEST_CODE);
    }

    /**
     * Send the crop Intent from an Activity
     *
     * @param activity Activity to receive result
     */
    public void start(@NonNull Activity activity) {
      start(activity, REQUEST_CODE);
    }

    /**
     * Get Intent to start {@link PhotoPickerActivity}
     *
     * @return Intent for {@link PhotoPickerActivity}
     */
    public Intent getIntent(@NonNull Context context) {
      mPreviewIntent.setClass(context, PhotoPagerActivity.class);
      mPreviewIntent.putExtras(mPreviewOptionsBundle);
      return mPreviewIntent;
    }

    public PhotoPreviewBuilder setPhotos(ArrayList<String> photoPaths) {
      mPreviewOptionsBundle.putStringArrayList(EXTRA_PHOTOS, photoPaths);
      return this;
    }

    public PhotoPreviewBuilder setAction(int action) {
      mPreviewOptionsBundle.putInt(EXTRA_ACTION, action);
      return this;
    }

    public PhotoPreviewBuilder setCurrentItem(int currentItem) {
      mPreviewOptionsBundle.putInt(EXTRA_CURRENT_ITEM, currentItem);
      return this;
    }

    public PhotoPreviewBuilder setShowDeleteButton(boolean showDeleteButton) {
      mPreviewOptionsBundle.putBoolean(EXTRA_SHOW_DELETE, showDeleteButton);
      return this;
    }
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoGridAdapter.java
================================================
package me.iwf.photopicker.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import me.iwf.photopicker.R;
import me.iwf.photopicker.entity.Photo;
import me.iwf.photopicker.entity.PhotoDirectory;
import me.iwf.photopicker.event.OnItemCheckListener;
import me.iwf.photopicker.event.OnPhotoClickListener;
import me.iwf.photopicker.utils.MediaStoreHelper;

/**
 * Created by donglua on 15/5/31.
 */
public class PhotoGridAdapter extends SelectableAdapter<PhotoGridAdapter.PhotoViewHolder> {

  private LayoutInflater inflater;
  private RequestManager glide;

  private OnItemCheckListener onItemCheckListener    = null;
  private OnPhotoClickListener onPhotoClickListener  = null;
  private View.OnClickListener onCameraClickListener = null;

  public final static int ITEM_TYPE_CAMERA = 100;
  public final static int ITEM_TYPE_PHOTO  = 101;
  private final static int COL_NUMBER_DEFAULT = 3;

  private boolean hasCamera = true;
  private boolean previewEnable = true;

  private int imageSize;
  private int columnNumber = COL_NUMBER_DEFAULT;


  public PhotoGridAdapter(Context context, RequestManager requestManager, List<PhotoDirectory> photoDirectories) {
    this.photoDirectories = photoDirectories;
    this.glide = requestManager;
    inflater = LayoutInflater.from(context);
    setColumnNumber(context, columnNumber);
  }

  public PhotoGridAdapter(Context context, RequestManager requestManager,  List<PhotoDirectory> photoDirectories, ArrayList<String> orginalPhotos, int colNum) {
    this(context, requestManager, photoDirectories);
    setColumnNumber(context, colNum);
    setOriginalPhotos(orginalPhotos);
  }

  private void setOriginalPhotos(ArrayList<String> originalPhotos){
    this.originalPhotos = originalPhotos;
  }

  private void setColumnNumber(Context context, int columnNumber) {
    this.columnNumber = columnNumber;
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    DisplayMetrics metrics = new DisplayMetrics();
    wm.getDefaultDisplay().getMetrics(metrics);
    int widthPixels = metrics.widthPixels;
    imageSize = widthPixels / columnNumber;
  }

  @Override public int getItemViewType(int position) {
    return (showCamera() && position == 0) ? ITEM_TYPE_CAMERA : ITEM_TYPE_PHOTO;
  }


  @Override public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = inflater.inflate(R.layout.__picker_item_photo, parent, false);
    PhotoViewHolder holder = new PhotoViewHolder(itemView);
    if (viewType == ITEM_TYPE_CAMERA) {
      holder.vSelected.setVisibility(View.GONE);
      holder.ivPhoto.setScaleType(ImageView.ScaleType.CENTER);

      holder.ivPhoto.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View view) {
          if (onCameraClickListener != null) {
            onCameraClickListener.onClick(view);
          }
        }
      });
    }
    return holder;
  }


  @Override public void onBindViewHolder(final PhotoViewHolder holder, int position) {

    if (getItemViewType(position) == ITEM_TYPE_PHOTO) {

      List<Photo> photos = getCurrentPhotos();
      final Photo photo;

      if (showCamera()) {
        photo = photos.get(position - 1);
      } else {
        photo = photos.get(position);
      }

      glide
          .load(new File(photo.getPath()))
          .centerCrop()
          .dontAnimate()
          .thumbnail(0.5f)
          .override(imageSize, imageSize)
          .placeholder(R.drawable.__picker_default_weixin)
          .error(R.drawable.__picker_ic_broken_image_black_48dp)
          .into(holder.ivPhoto);

      final boolean isChecked = isSelected(photo);

      holder.vSelected.setSelected(isChecked);
      holder.cover.setSelected(isChecked);

      holder.ivPhoto.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View view) {
          if (onPhotoClickListener != null) {
            int pos = holder.getAdapterPosition();
            if (previewEnable) {
              onPhotoClickListener.onClick(view, pos, showCamera());
            } else {
              holder.vSelected.performClick();
            }
          }
        }
      });
      holder.vSelected.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View view) {
          int pos = holder.getAdapterPosition();
          boolean isEnable = true;

          if (onItemCheckListener != null) {
            isEnable = onItemCheckListener.OnItemCheck(pos, photo, isChecked,
                getSelectedPhotos().size());
          }
          if (isEnable) {
            toggleSelection(photo);
            notifyItemChanged(pos);
          }
        }
      });

    } else {
      holder.ivPhoto.setImageResource(R.drawable.__picker_camera);
    }
  }


  @Override public int getItemCount() {
    int photosCount =
        photoDirectories.size() == 0 ? 0 : getCurrentPhotos().size();
    if (showCamera()) {
      return photosCount + 1;
    }
    return photosCount;
  }


  public static class PhotoViewHolder extends RecyclerView.ViewHolder {
    private ImageView ivPhoto;
    private View vSelected;
    private View cover;

    public PhotoViewHolder(View itemView) {
      super(itemView);
      ivPhoto   = (ImageView) itemView.findViewById(R.id.iv_photo);
      vSelected = itemView.findViewById(R.id.v_selected);
      cover = itemView.findViewById(R.id.cover);
    }
  }


  public void setOnItemCheckListener(OnItemCheckListener onItemCheckListener) {
    this.onItemCheckListener = onItemCheckListener;
  }


  public void setOnPhotoClickListener(OnPhotoClickListener onPhotoClickListener) {
    this.onPhotoClickListener = onPhotoClickListener;
  }


  public void setOnCameraClickListener(View.OnClickListener onCameraClickListener) {
    this.onCameraClickListener = onCameraClickListener;
  }


  public ArrayList<String> getSelectedPhotoPaths() {
    ArrayList<String> selectedPhotoPaths = new ArrayList<>(getSelectedItemCount());

    for (Photo photo : selectedPhotos) {
      selectedPhotoPaths.add(photo.getPath());
    }

    return selectedPhotoPaths;
  }


  public void setShowCamera(boolean hasCamera) {
    this.hasCamera = hasCamera;
  }

  public void setPreviewEnable(boolean previewEnable) {
    this.previewEnable = previewEnable;
  }

  public boolean showCamera() {
    return (hasCamera && currentDirectoryIndex == MediaStoreHelper.INDEX_ALL_PHOTOS);
  }

  @Override public void onViewRecycled(PhotoViewHolder holder) {
    Glide.clear(holder.ivPhoto);
    super.onViewRecycled(holder);
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoPagerAdapter.java
================================================
package me.iwf.photopicker.adapter;

import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import me.iwf.photopicker.R;

/**
 * Created by donglua on 15/6/21.
 */
public class PhotoPagerAdapter extends PagerAdapter {

  private List<String> paths = new ArrayList<>();
  private RequestManager mGlide;

  public PhotoPagerAdapter(RequestManager glide, List<String> paths) {
    this.paths = paths;
    this.mGlide = glide;
  }

  @Override public Object instantiateItem(ViewGroup container, int position) {
    final Context context = container.getContext();
    View itemView = LayoutInflater.from(context)
        .inflate(R.layout.__picker_picker_item_pager, container, false);

    final ImageView imageView = (ImageView) itemView.findViewById(R.id.iv_pager);

    final String path = paths.get(position);
    final Uri uri;
    if (path.startsWith("http")) {
      uri = Uri.parse(path);
    } else {
      uri = Uri.fromFile(new File(path));
    }
    mGlide.load(uri)
        .thumbnail(0.1f)
        .dontAnimate()
        .dontTransform()
        .override(800, 800)
        .placeholder(R.drawable.__picker_ic_photo_black_48dp)
        .error(R.drawable.__picker_ic_broken_image_black_48dp)
        .into(imageView);

    imageView.setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View view) {
        if (context instanceof Activity) {
          if (!((Activity) context).isFinishing()) {
            ((Activity) context).onBackPressed();
          }
        }
      }
    });

    container.addView(itemView);

    return itemView;
  }


  @Override public int getCount() {
    return paths.size();
  }


  @Override public boolean isViewFromObject(View view, Object object) {
    return view == object;
  }


  @Override
  public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    Glide.clear((View) object);
  }

  @Override
  public int getItemPosition (Object object) { return POSITION_NONE; }

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PopupDirectoryListAdapter.java
================================================
package me.iwf.photopicker.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.RequestManager;
import java.util.ArrayList;
import java.util.List;
import me.iwf.photopicker.R;
import me.iwf.photopicker.entity.PhotoDirectory;

/**
 * Created by donglua on 15/6/28.
 */
public class PopupDirectoryListAdapter extends BaseAdapter {


  private List<PhotoDirectory> directories = new ArrayList<>();
  private RequestManager glide;

  public PopupDirectoryListAdapter(RequestManager glide, List<PhotoDirectory> directories) {
    this.directories = directories;
    this.glide = glide;
  }


  @Override public int getCount() {
    return directories.size();
  }


  @Override public PhotoDirectory getItem(int position) {
    return directories.get(position);
  }


  @Override public long getItemId(int position) {
    return directories.get(position).hashCode();
  }


  @Override public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
      LayoutInflater mLayoutInflater = LayoutInflater.from(parent.getContext());
      convertView = mLayoutInflater.inflate(R.layout.__picker_item_directory, parent, false);
      holder = new ViewHolder(convertView);
      convertView.setTag(holder);
    } else {
      holder = (ViewHolder) convertView.getTag();
    }

    holder.bindData(directories.get(position));

    return convertView;
  }

  private class ViewHolder {

    public ImageView ivCover;
    public TextView tvName;
    public TextView tvCount;

    public ViewHolder(View rootView) {
      ivCover = (ImageView) rootView.findViewById(R.id.iv_dir_cover);
      tvName  = (TextView)  rootView.findViewById(R.id.tv_dir_name);
      tvCount = (TextView)  rootView.findViewById(R.id.tv_dir_count);
    }

    public void bindData(PhotoDirectory directory) {
      glide.load(directory.getCoverPath())
          .dontAnimate()
          .thumbnail(0.1f)
          .into(ivCover);
      tvName.setText(directory.getName());
      tvCount.setText(tvCount.getContext().getString(R.string.__picker_image_count, directory.getPhotos().size()));
    }
  }

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/SelectableAdapter.java
================================================
package me.iwf.photopicker.adapter;

import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

import me.iwf.photopicker.entity.Photo;
import me.iwf.photopicker.entity.PhotoDirectory;
import me.iwf.photopicker.event.Selectable;

public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder>
    extends RecyclerView.Adapter<VH> implements Selectable {

  private static final String TAG = SelectableAdapter.class.getSimpleName();

  protected List<PhotoDirectory> photoDirectories;
  protected List<Photo> selectedPhotos;
  //初始进入时已选的照片 original selected photos
  protected ArrayList<String> originalPhotos = null;

  public int currentDirectoryIndex = 0;


  public SelectableAdapter() {
    photoDirectories = new ArrayList<>();
    selectedPhotos = new ArrayList<>();
  }


  /**
   * Indicates if the item at position where is selected
   *
   * @param photo Photo of the item to check
   * @return true if the item is selected, false otherwise
   */
  @Override public boolean isSelected(Photo photo) {
    if (originalPhotos != null && originalPhotos.contains(photo.getPath()) && !selectedPhotos.contains(photo)) {
      selectedPhotos.add(photo);
    }
    return getSelectedPhotos().contains(photo);
  }


  /**
   * Toggle the selection status of the item at a given position
   *
   * @param photo Photo of the item to toggle the selection status for
   */
  @Override public void toggleSelection(Photo photo) {
    if (selectedPhotos.contains(photo)) {
      selectedPhotos.remove(photo);
      if(originalPhotos!=null &&originalPhotos.contains(photo.getPath())){
        originalPhotos.remove(photo.getPath());
      }
    } else {
      selectedPhotos.add(photo);
    }
  }


  /**
   * Clear the selection status for all items
   */
  @Override public void clearSelection() {
    selectedPhotos.clear();
  }


  /**
   * Count the selected items
   *
   * @return Selected items count
   */
  @Override public int getSelectedItemCount() {
    return selectedPhotos.size();
  }


  public void setCurrentDirectoryIndex(int currentDirectoryIndex) {
    this.currentDirectoryIndex = currentDirectoryIndex;
  }


  public List<Photo> getCurrentPhotos() {
    return photoDirectories.get(currentDirectoryIndex).getPhotos();
  }


  public List<String> getCurrentPhotoPaths() {
    List<String> currentPhotoPaths = new ArrayList<>(getCurrentPhotos().size());
    for (Photo photo : getCurrentPhotos()) {
      currentPhotoPaths.add(photo.getPath());
    }
    return currentPhotoPaths;
  }


  public List<Photo> getSelectedPhotos() {
    return selectedPhotos;
  }

}

================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/entity/Photo.java
================================================
package me.iwf.photopicker.entity;

/**
 * Created by donglua on 15/6/30.
 */
public class Photo {

  private int id;
  private String path;

  public Photo(int id, String path) {
    this.id = id;
    this.path = path;
  }

  public Photo() {
  }

  @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Photo)) return false;

    Photo photo = (Photo) o;

    return id == photo.id;
  }

  @Override public int hashCode() {
    return id;
  }

  public String getPath() {
    return path;
  }

  public void setPath(String path) {
    this.path = path;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/entity/PhotoDirectory.java
================================================
package me.iwf.photopicker.entity;

import android.text.TextUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by donglua on 15/6/28.
 */
public class PhotoDirectory {

  private String id;
  private String coverPath;
  private String name;
  private long   dateAdded;
  private List<Photo> photos = new ArrayList<>();

  @Override public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof PhotoDirectory)) return false;

    PhotoDirectory directory = (PhotoDirectory) o;

    boolean hasId = !TextUtils.isEmpty(id);
    boolean otherHasId = !TextUtils.isEmpty(directory.id);

    if (hasId && otherHasId) {
      if (!TextUtils.equals(id, directory.id)) {
        return false;
      }

      return TextUtils.equals(name, directory.name);
    }

    return false;
  }

  @Override public int hashCode() {
    if (TextUtils.isEmpty(id)) {
      if (TextUtils.isEmpty(name)) {
        return 0;
      }

      return name.hashCode();
    }

    int result = id.hashCode();

    if (TextUtils.isEmpty(name)) {
      return result;
    }

    result = 31 * result + name.hashCode();
    return result;
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getCoverPath() {
    return coverPath;
  }

  public void setCoverPath(String coverPath) {
    this.coverPath = coverPath;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public long getDateAdded() {
    return dateAdded;
  }

  public void setDateAdded(long dateAdded) {
    this.dateAdded = dateAdded;
  }

  public List<Photo> getPhotos() {
    return photos;
  }

  public void setPhotos(List<Photo> photos) {
    this.photos = photos;
  }

  public List<String> getPhotoPaths() {
    List<String> paths = new ArrayList<>(photos.size());
    for (Photo photo : photos) {
      paths.add(photo.getPath());
    }
    return paths;
  }

  public void addPhoto(int id, String path) {
    photos.add(new Photo(id, path));
  }

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/event/OnItemCheckListener.java
================================================
package me.iwf.photopicker.event;

import me.iwf.photopicker.entity.Photo;

/**
 * Created by donglua on 15/6/20.
 */
public interface OnItemCheckListener {

  /***
   *
   * @param position 所选图片的位置
   * @param path     所选的图片
   * @param isCheck   当前状态
   * @param selectedItemCount  已选数量
   * @return enable check
   */
  boolean OnItemCheck(int position, Photo path, boolean isCheck, int selectedItemCount);

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/event/OnPhotoClickListener.java
================================================
/*
 * Copyright (c) 2015. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
 * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
 * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
 * Vestibulum commodo. Ut rhoncus gravida arcu.
 */

package me.iwf.photopicker.event;

import android.view.View;

/**
 * Created by donglua on 15/6/20.
 */
public interface OnPhotoClickListener {

  void onClick(View v, int position, boolean showCamera);
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/event/Selectable.java
================================================
package me.iwf.photopicker.event;

import me.iwf.photopicker.entity.Photo;

/**
 * Created by donglua on 15/6/30.
 */
public interface Selectable {


  /**
   * Indicates if the item at position position is selected
   *
   * @param photo Photo of the item to check
   * @return true if the item is selected, false otherwise
   */
  boolean isSelected(Photo photo);

  /**
   * Toggle the selection status of the item at a given position
   *
   * @param photo Photo of the item to toggle the selection status for
   */
  void toggleSelection(Photo photo);

  /**
   * Clear the selection status for all items
   */
  void clearSelection();

  /**
   * Count the selected items
   *
   * @return Selected items count
   */
  int getSelectedItemCount();

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/fragment/ImagePagerFragment.java
================================================
package me.iwf.photopicker.fragment;

import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import com.bumptech.glide.Glide;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import me.iwf.photopicker.R;
import me.iwf.photopicker.adapter.PhotoPagerAdapter;

/**
 * Created by donglua on 15/6/21.
 */
public class ImagePagerFragment extends Fragment {

  public final static String ARG_PATH = "PATHS";
  public final static String ARG_CURRENT_ITEM = "ARG_CURRENT_ITEM";

  private ArrayList<String> paths;
  private ViewPager mViewPager;
  private PhotoPagerAdapter mPagerAdapter;

  public final static long ANIM_DURATION = 200L;

  public final static String ARG_THUMBNAIL_TOP    = "THUMBNAIL_TOP";
  public final static String ARG_THUMBNAIL_LEFT   = "THUMBNAIL_LEFT";
  public final static String ARG_THUMBNAIL_WIDTH  = "THUMBNAIL_WIDTH";
  public final static String ARG_THUMBNAIL_HEIGHT = "THUMBNAIL_HEIGHT";
  public final static String ARG_HAS_ANIM = "HAS_ANIM";

  private int thumbnailTop    = 0;
  private int thumbnailLeft   = 0;
  private int thumbnailWidth  = 0;
  private int thumbnailHeight = 0;

  private boolean hasAnim = false;

  private final ColorMatrix colorizerMatrix = new ColorMatrix();

  private int currentItem = 0;


  public static ImagePagerFragment newInstance(List<String> paths, int currentItem) {

    ImagePagerFragment f = new ImagePagerFragment();

    Bundle args = new Bundle();
    args.putStringArray(ARG_PATH, paths.toArray(new String[paths.size()]));
    args.putInt(ARG_CURRENT_ITEM, currentItem);
    args.putBoolean(ARG_HAS_ANIM, false);

    f.setArguments(args);

    return f;
  }


  public static ImagePagerFragment newInstance(List<String> paths, int currentItem, int[] screenLocation, int thumbnailWidth, int thumbnailHeight) {

    ImagePagerFragment f = newInstance(paths, currentItem);

    f.getArguments().putInt(ARG_THUMBNAIL_LEFT, screenLocation[0]);
    f.getArguments().putInt(ARG_THUMBNAIL_TOP, screenLocation[1]);
    f.getArguments().putInt(ARG_THUMBNAIL_WIDTH, thumbnailWidth);
    f.getArguments().putInt(ARG_THUMBNAIL_HEIGHT, thumbnailHeight);
    f.getArguments().putBoolean(ARG_HAS_ANIM, true);

    return f;
  }


  public void setPhotos(List<String> paths, int currentItem) {
    this.paths.clear();
    this.paths.addAll(paths);
    this.currentItem = currentItem;

    mViewPager.setCurrentItem(currentItem);
    mViewPager.getAdapter().notifyDataSetChanged();
  }


  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    paths = new ArrayList<>();

    Bundle bundle = getArguments();

    if (bundle != null) {
      String[] pathArr = bundle.getStringArray(ARG_PATH);
      paths.clear();
      if (pathArr != null) {

        paths = new ArrayList<>(Arrays.asList(pathArr));
      }

      hasAnim         = bundle.getBoolean(ARG_HAS_ANIM);
      currentItem     = bundle.getInt(ARG_CURRENT_ITEM);
      thumbnailTop    = bundle.getInt(ARG_THUMBNAIL_TOP);
      thumbnailLeft   = bundle.getInt(ARG_THUMBNAIL_LEFT);
      thumbnailWidth  = bundle.getInt(ARG_THUMBNAIL_WIDTH);
      thumbnailHeight = bundle.getInt(ARG_THUMBNAIL_HEIGHT);
    }

    mPagerAdapter = new PhotoPagerAdapter(Glide.with(this), paths);
  }


  @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.__picker_picker_fragment_image_pager, container, false);

    mViewPager = (ViewPager) rootView.findViewById(R.id.vp_photos);
    mViewPager.setAdapter(mPagerAdapter);
    mViewPager.setCurrentItem(currentItem);
    mViewPager.setOffscreenPageLimit(5);

    // Only run the animation if we're coming from the parent activity, not if
    // we're recreated automatically by the window manager (e.g., device rotation)
    if (savedInstanceState == null && hasAnim) {
      ViewTreeObserver observer = mViewPager.getViewTreeObserver();
      observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {

          mViewPager.getViewTreeObserver().removeOnPreDrawListener(this);

          // Figure out where the thumbnail and full size versions are, relative
          // to the screen and each other
          int[] screenLocation = new int[2];
          mViewPager.getLocationOnScreen(screenLocation);
          thumbnailLeft = thumbnailLeft - screenLocation[0];
          thumbnailTop  = thumbnailTop - screenLocation[1];

          runEnterAnimation();

          return true;
        }
      });
    }


    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

      }

      @Override public void onPageSelected(int position) {
        hasAnim = currentItem == position;
      }

      @Override public void onPageScrollStateChanged(int state) {

      }
    });

    return rootView;
  }


  /**
   * The enter animation scales the picture in from its previous thumbnail
   * size/location, colorizing it in parallel. In parallel, the background of the
   * activity is fading in. When the pictue is in place, the text description
   * drops down.
   */
  private void runEnterAnimation() {
    final long duration = ANIM_DURATION;

    // Set starting values for properties we're going to animate. These
    // values scale and position the full size version down to the thumbnail
    // size/location, from which we'll animate it back up
    ViewHelper.setPivotX(mViewPager, 0);
    ViewHelper.setPivotY(mViewPager, 0);
    ViewHelper.setScaleX(mViewPager, (float) thumbnailWidth / mViewPager.getWidth());
    ViewHelper.setScaleY(mViewPager, (float) thumbnailHeight / mViewPager.getHeight());
    ViewHelper.setTranslationX(mViewPager, thumbnailLeft);
    ViewHelper.setTranslationY(mViewPager, thumbnailTop);

    // Animate scale and translation to go from thumbnail to full size
    ViewPropertyAnimator.animate(mViewPager)
        .setDuration(duration)
        .scaleX(1)
        .scaleY(1)
        .translationX(0)
        .translationY(0)
        .setInterpolator(new DecelerateInterpolator());

    // Fade in the black background
    ObjectAnimator bgAnim = ObjectAnimator.ofInt(mViewPager.getBackground(), "alpha", 0, 255);
    bgAnim.setDuration(duration);
    bgAnim.start();

    // Animate a color filter to take the image from grayscale to full color.
    // This happens in parallel with the image scaling and moving into place.
    ObjectAnimator colorizer = ObjectAnimator.ofFloat(ImagePagerFragment.this,
        "saturation", 0, 1);
    colorizer.setDuration(duration);
    colorizer.start();

  }


  /**
   * The exit animation is basically a reverse of the enter animation, except that if
   * the orientation has changed we simply scale the picture back into the center of
   * the screen.
   *
   * @param endAction This action gets run after the animation completes (this is
   * when we actually switch activities)
   */
  public void runExitAnimation(final Runnable endAction) {

    if (!getArguments().getBoolean(ARG_HAS_ANIM, false) || !hasAnim) {
      endAction.run();
      return;
    }

    final long duration = ANIM_DURATION;

    // Animate image back to thumbnail size/location
    ViewPropertyAnimator.animate(mViewPager)
        .setDuration(duration)
        .setInterpolator(new AccelerateInterpolator())
        .scaleX((float) thumbnailWidth / mViewPager.getWidth())
        .scaleY((float) thumbnailHeight / mViewPager.getHeight())
        .translationX(thumbnailLeft)
        .translationY(thumbnailTop)
        .setListener(new Animator.AnimatorListener() {
          @Override public void onAnimationStart(Animator animation) {
          }
          @Override public void onAnimationEnd(Animator animation) {
            endAction.run();
          }
          @Override public void onAnimationCancel(Animator animation) {
          }
          @Override public void onAnimationRepeat(Animator animation) {
          }
        });

    // Fade out background
    ObjectAnimator bgAnim = ObjectAnimator.ofInt(mViewPager.getBackground(), "alpha", 0);
    bgAnim.setDuration(duration);
    bgAnim.start();

    // Animate a color filter to take the image back to grayscale,
    // in parallel with the image scaling and moving into place.
    ObjectAnimator colorizer =
        ObjectAnimator.ofFloat(ImagePagerFragment.this, "saturation", 1, 0);
    colorizer.setDuration(duration);
    colorizer.start();
  }


  /**
   * This is called by the colorizing animator. It sets a saturation factor that is then
   * passed onto a filter on the picture's drawable.
   * @param value saturation
   */
  public void setSaturation(float value) {
    colorizerMatrix.setSaturation(value);
    ColorMatrixColorFilter colorizerFilter = new ColorMatrixColorFilter(colorizerMatrix);
    mViewPager.getBackground().setColorFilter(colorizerFilter);
  }


  public ViewPager getViewPager() {
    return mViewPager;
  }


  public ArrayList<String> getPaths() {
    return paths;
  }


  public int getCurrentItem() {
    return mViewPager.getCurrentItem();
  }

  @Override public void onDestroy() {
    super.onDestroy();

    paths.clear();
    paths = null;

    if (mViewPager != null) {
      mViewPager.setAdapter(null);
    }
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/fragment/PhotoPickerFragment.java
================================================
package me.iwf.photopicker.fragment;

import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.ListPopupWindow;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import me.iwf.photopicker.PhotoPickerActivity;
import me.iwf.photopicker.PhotoPreview;
import me.iwf.photopicker.R;
import me.iwf.photopicker.adapter.PhotoGridAdapter;
import me.iwf.photopicker.adapter.PopupDirectoryListAdapter;
import me.iwf.photopicker.entity.Photo;
import me.iwf.photopicker.entity.PhotoDirectory;
import me.iwf.photopicker.event.OnPhotoClickListener;
import me.iwf.photopicker.utils.ImageCaptureManager;
import me.iwf.photopicker.utils.MediaStoreHelper;
import me.iwf.photopicker.widget.Titlebar;

import static android.app.Activity.RESULT_OK;
import static me.iwf.photopicker.PhotoPicker.DEFAULT_COLUMN_NUMBER;
import static me.iwf.photopicker.PhotoPicker.EXTRA_PREVIEW_ENABLED;
import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_GIF;
import static me.iwf.photopicker.utils.MediaStoreHelper.INDEX_ALL_PHOTOS;

/**
 * Created by donglua on 15/5/31.
 */
public class PhotoPickerFragment extends Fragment {

  private ImageCaptureManager captureManager;
  private PhotoGridAdapter photoGridAdapter;

  private PopupDirectoryListAdapter listAdapter;
  //所有photos的路径
  private List<PhotoDirectory> directories;
  //传入的已选照片
  private ArrayList<String> originalPhotos;

  private int SCROLL_THRESHOLD = 30;
  int column;
  //目录弹出框的一次最多显示的目录数目
  public static int COUNT_MAX = 4;
  private final static String EXTRA_CAMERA = "camera";
  private final static String EXTRA_COLUMN = "column";
  private final static String EXTRA_COUNT = "count";
  private final static String EXTRA_GIF = "gif";
  private final static String EXTRA_ORIGIN = "origin";
  private ListPopupWindow listPopupWindow;
  private RequestManager mGlideRequestManager;
  private Context mContext;

  private Titlebar titlebar;

  public static PhotoPickerFragment newInstance(boolean showCamera, boolean showGif,
      boolean previewEnable, int column, int maxCount, ArrayList<String> originalPhotos) {
    Bundle args = new Bundle();
    args.putBoolean(EXTRA_CAMERA, showCamera);
    args.putBoolean(EXTRA_GIF, showGif);
    args.putBoolean(EXTRA_PREVIEW_ENABLED, previewEnable);
    args.putInt(EXTRA_COLUMN, column);
    args.putInt(EXTRA_COUNT, maxCount);
    args.putStringArrayList(EXTRA_ORIGIN, originalPhotos);
    PhotoPickerFragment fragment = new PhotoPickerFragment();
    fragment.setArguments(args);
    return fragment;
  }

  @Override public void onAttach(Context context) {
    super.onAttach(context);
    mContext = context;
  }

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRetainInstance(true);

    mGlideRequestManager = Glide.with(this);

    directories = new ArrayList<>();
    originalPhotos = getArguments().getStringArrayList(EXTRA_ORIGIN);

    column = getArguments().getInt(EXTRA_COLUMN, DEFAULT_COLUMN_NUMBER);
    boolean showCamera = getArguments().getBoolean(EXTRA_CAMERA, true);
    boolean previewEnable = getArguments().getBoolean(EXTRA_PREVIEW_ENABLED, true);

    photoGridAdapter = new PhotoGridAdapter(mContext, mGlideRequestManager, directories, originalPhotos, column);
    photoGridAdapter.setShowCamera(showCamera);
    photoGridAdapter.setPreviewEnable(previewEnable);

    Bundle mediaStoreArgs = new Bundle();

    boolean showGif = getArguments().getBoolean(EXTRA_GIF);
    mediaStoreArgs.putBoolean(EXTRA_SHOW_GIF, showGif);
    MediaStoreHelper.getPhotoDirs(getActivity(), mediaStoreArgs,
        new MediaStoreHelper.PhotosResultCallback() {
          @Override public void onResultCallback(List<PhotoDirectory> dirs) {
            directories.clear();
            directories.addAll(dirs);
            photoGridAdapter.notifyDataSetChanged();
            listAdapter.notifyDataSetChanged();
            adjustHeight();
          }
        });

    captureManager = new ImageCaptureManager(getActivity());
  }


  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {

    final View rootView = inflater.inflate(R.layout.__picker_fragment_photo_picker, container, false);
    titlebar = (Titlebar) rootView.findViewById(R.id.titlebar);

    listAdapter  = new PopupDirectoryListAdapter(mGlideRequestManager, directories);

    RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.rv_photos);
    StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(column, OrientationHelper.VERTICAL);
    layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(photoGridAdapter);

    recyclerView.setItemAnimator(new DefaultItemAnimator());

    final Button btSwitchDirectory = (Button) rootView.findViewById(R.id.button);

    Button btnPreview = (Button) rootView.findViewById(R.id.btn_preview);

    listPopupWindow = new ListPopupWindow(getActivity());

    listPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//替换背景
    WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
    int widths = wm.getDefaultDisplay().getWidth();
    listPopupWindow.setWidth(widths);//ListPopupWindow.MATCH_PARENT还是会有边距,直接拿到屏幕宽度来设置也不行,因为默认的background有左右padding值。
  /*  int height = wm.getDefaultDisplay().getHeight();
    listPopupWindow.setHeight((int) (height *0.7));*/
    listPopupWindow.setAnchorView(btSwitchDirectory);
    listPopupWindow.setAdapter(listAdapter);
    listPopupWindow.setModal(true);

    listPopupWindow.setDropDownGravity(Gravity.BOTTOM);
    listPopupWindow.setAnimationStyle(R.style.__picker_mystyle);

    listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        listPopupWindow.dismiss();

        PhotoDirectory directory = directories.get(position);

        btSwitchDirectory.setText(directory.getName().toLowerCase());//默认会大写,这里要改成小写

        photoGridAdapter.setCurrentDirectoryIndex(position);
        photoGridAdapter.notifyDataSetChanged();
      }
    });

    photoGridAdapter.setOnPhotoClickListener(new OnPhotoClickListener() {
      @Override public void onClick(View v, int position, boolean showCamera) {
        final int index = showCamera ? position - 1 : position;

        List<String> photos = photoGridAdapter.getCurrentPhotoPaths();

        int[] screenLocation = new int[2];
        v.getLocationOnScreen(screenLocation);
        ImagePagerFragment imagePagerFragment =
            ImagePagerFragment.newInstance(photos, index, screenLocation, v.getWidth(),
                v.getHeight());

        ((PhotoPickerActivity) getActivity()).addImagePagerFragment(imagePagerFragment);
      }
    });

    photoGridAdapter.setOnCameraClickListener(new OnClickListener() {
      @Override public void onClick(View view) {
        try {
          Intent intent = captureManager.dispatchTakePictureIntent();
          startActivityForResult(intent, ImageCaptureManager.REQUEST_TAKE_PHOTO);
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    });

    btSwitchDirectory.setOnClickListener(new OnClickListener() {
      @Override public void onClick(View v) {

        if (listPopupWindow.isShowing()) {
          listPopupWindow.dismiss();
        } else if (!getActivity().isFinishing()) {
          adjustHeight();
          listPopupWindow.show();
          listPopupWindow.getListView().setVerticalScrollBarEnabled(false);

          //去掉滑动条,listview 在show之后才建立,所以需要该方法在show之后调用,否则会空指针
        }
      }
    });


    //预览按钮
    btnPreview.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
       if (photoGridAdapter.getSelectedPhotoPaths().size() > 0){
         PhotoPreview.builder()
                 .setPhotos(photoGridAdapter.getSelectedPhotoPaths())
                 .setCurrentItem(0)
                 .start(getActivity());
       }else {
         Toast.makeText(getActivity(),"还没有选择图片",Toast.LENGTH_SHORT).show();
       }
      }
    });


    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
      @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        // Log.d(">>> Picker >>>", "dy = " + dy);
        if (Math.abs(dy) > SCROLL_THRESHOLD) {
          mGlideRequestManager.pauseRequests();
        } else {
          mGlideRequestManager.resumeRequests();
        }
      }
      @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
          mGlideRequestManager.resumeRequests();
        }
      }
    });

    return rootView;
  }


  @Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == ImageCaptureManager.REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
      captureManager.galleryAddPic();
      if (directories.size() > 0) {
        String path = captureManager.getCurrentPhotoPath();
        PhotoDirectory directory = directories.get(INDEX_ALL_PHOTOS);
        directory.getPhotos().add(INDEX_ALL_PHOTOS, new Photo(path.hashCode(), path));
        directory.setCoverPath(path);
        photoGridAdapter.notifyDataSetChanged();
      }
    }
  }


  public PhotoGridAdapter getPhotoGridAdapter() {
    return photoGridAdapter;
  }


  @Override public void onSaveInstanceState(Bundle outState) {
    captureManager.onSaveInstanceState(outState);
    super.onSaveInstanceState(outState);
  }


  @Override public void onViewStateRestored(Bundle savedInstanceState) {
    captureManager.onRestoreInstanceState(savedInstanceState);
    super.onViewStateRestored(savedInstanceState);
  }

  public ArrayList<String> getSelectedPhotoPaths() {
    return photoGridAdapter.getSelectedPhotoPaths();
  }

  public void adjustHeight() {
    if (listAdapter == null) return;
    int count = listAdapter.getCount();
    count = count < COUNT_MAX ? count : COUNT_MAX;
    if (listPopupWindow != null) {
      listPopupWindow.setHeight(count * getResources().getDimensionPixelOffset(R.dimen.__picker_item_directory_height));
    }
  }

  @Override public void onDestroy() {
    super.onDestroy();

    if (directories == null) {
      return;
    }

    for (PhotoDirectory directory : directories) {
      directory.getPhotoPaths().clear();
      directory.getPhotos().clear();
      directory.setPhotos(null);
    }
    directories.clear();
    directories = null;
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/ExifUtils.java
================================================
package me.iwf.photopicker.utils;

import android.media.ExifInterface;

import java.io.IOException;

/**
 * Created by Administrator on 2016/8/15 0015.
 */
public class ExifUtils {

    public static void clearSensitiveInfo(String filePath){
        ExifInterface exifInterface = null;
        try {
            exifInterface = new ExifInterface(filePath);
            exifInterface.setAttribute(ExifInterface.TAG_DATETIME ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_MAKE ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_MODEL ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_APERTURE ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_ISO ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_SUBSEC_TIME  ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIG  ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_SUBSEC_TIME_DIG  ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_ALTITUDE  ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF  ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP  ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_DATESTAMP   ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_WHITE_BALANCE  ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_FOCAL_LENGTH   ,"0");
            exifInterface.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD    ,"0");
            exifInterface.saveAttributes();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/ImageCaptureManager.java
================================================
package me.iwf.photopicker.utils;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * Created by donglua on 15/6/23.
 *
 *
 * http://developer.android.com/training/camera/photobasics.html
 */
public class ImageCaptureManager {

  private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";
  public static final int REQUEST_TAKE_PHOTO = 1;

  private String mCurrentPhotoPath;
  private Context mContext;

  public ImageCaptureManager(Context mContext) {
    this.mContext = mContext;
  }

  private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + ".jpg";
    File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

    if (!storageDir.exists()) {
      if (!storageDir.mkdir()) {
        Log.e("TAG", "Throwing Errors....");
        throw new IOException();
      }
    }

    File image = new File(storageDir, imageFileName);
    //                File.createTempFile(
    //                imageFileName,  /* prefix */
    //                ".jpg",         /* suffix */
    //                storageDir      /* directory */
    //        );

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
  }


  public Intent dispatchTakePictureIntent() throws IOException {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
      // Create the File where the photo should go
      File photoFile = createImageFile();
      // Continue only if the File was successfully created
      if (photoFile != null) {
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
            Uri.fromFile(photoFile));
      }
    }
    return takePictureIntent;
  }


  public void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

    if (TextUtils.isEmpty(mCurrentPhotoPath)) {
      return;
    }

    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    mContext.sendBroadcast(mediaScanIntent);
  }


  public String getCurrentPhotoPath() {
    return mCurrentPhotoPath;
  }


  public void onSaveInstanceState(Bundle savedInstanceState) {
    if (savedInstanceState != null && mCurrentPhotoPath != null) {
      savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath);
    }
  }

  public void onRestoreInstanceState(Bundle savedInstanceState) {
    if (savedInstanceState != null && savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
      mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY);
    }
  }

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/MediaStoreHelper.java
================================================
package me.iwf.photopicker.utils;

import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import me.iwf.photopicker.PhotoPicker;
import me.iwf.photopicker.R;
import me.iwf.photopicker.entity.PhotoDirectory;

import static android.provider.BaseColumns._ID;
import static android.provider.MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME;
import static android.provider.MediaStore.Images.ImageColumns.BUCKET_ID;
import static android.provider.MediaStore.MediaColumns.DATA;
import static android.provider.MediaStore.MediaColumns.DATE_ADDED;

/**
 * Created by donglua on 15/5/31.
 */
public class MediaStoreHelper {

  public final static int INDEX_ALL_PHOTOS = 0;


  public static void getPhotoDirs(FragmentActivity activity, Bundle args, PhotosResultCallback resultCallback) {
    activity.getSupportLoaderManager()
        .initLoader(0, args, new PhotoDirLoaderCallbacks(activity, resultCallback));
  }

  static class PhotoDirLoaderCallbacks implements LoaderManager.LoaderCallbacks<Cursor> {

    private WeakReference<Context> context;
    private PhotosResultCallback resultCallback;

    public PhotoDirLoaderCallbacks(Context context, PhotosResultCallback resultCallback) {
      this.context = new WeakReference<>(context);
      this.resultCallback = resultCallback;
    }

    @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) {
      return new PhotoDirectoryLoader(context.get(), args.getBoolean(PhotoPicker.EXTRA_SHOW_GIF, false));
    }

    @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

      if (data == null)  return;
      List<PhotoDirectory> directories = new ArrayList<>();
      PhotoDirectory photoDirectoryAll = new PhotoDirectory();
      photoDirectoryAll.setName(context.get().getString(R.string.__picker_all_image));
      photoDirectoryAll.setId("ALL");

      while (data.moveToNext()) {

        int imageId  = data.getInt(data.getColumnIndexOrThrow(_ID));
        String bucketId = data.getString(data.getColumnIndexOrThrow(BUCKET_ID));
        String name = data.getString(data.getColumnIndexOrThrow(BUCKET_DISPLAY_NAME));
        String path = data.getString(data.getColumnIndexOrThrow(DATA));

        PhotoDirectory photoDirectory = new PhotoDirectory();
        photoDirectory.setId(bucketId);
        photoDirectory.setName(name);

        if (!directories.contains(photoDirectory)) {
          photoDirectory.setCoverPath(path);
          photoDirectory.addPhoto(imageId, path);
          photoDirectory.setDateAdded(data.getLong(data.getColumnIndexOrThrow(DATE_ADDED)));
          directories.add(photoDirectory);
        } else {
          directories.get(directories.indexOf(photoDirectory)).addPhoto(imageId, path);
        }

        photoDirectoryAll.addPhoto(imageId, path);
      }
      if (photoDirectoryAll.getPhotoPaths().size() > 0) {
        photoDirectoryAll.setCoverPath(photoDirectoryAll.getPhotoPaths().get(0));
      }
      directories.add(INDEX_ALL_PHOTOS, photoDirectoryAll);
      if (resultCallback != null) {
        resultCallback.onResultCallback(directories);
      }
    }

    @Override public void onLoaderReset(Loader<Cursor> loader) {

    }
  }


  public interface PhotosResultCallback {
    void onResultCallback(List<PhotoDirectory> directories);
  }

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/PhotoDirectoryLoader.java
================================================
package me.iwf.photopicker.utils;

import android.content.Context;
import android.net.Uri;
import android.provider.MediaStore.Images.Media;
import android.support.v4.content.CursorLoader;

import static android.provider.MediaStore.MediaColumns.MIME_TYPE;

/**
 * Created by 黄东鲁 on 15/6/28.
 */
public class PhotoDirectoryLoader extends CursorLoader {

  final String[] IMAGE_PROJECTION = {
      Media._ID,
      Media.DATA,
      Media.BUCKET_ID,
      Media.BUCKET_DISPLAY_NAME,
      Media.DATE_ADDED
  };

  public PhotoDirectoryLoader(Context context, boolean showGif) {
    super(context);

    setProjection(IMAGE_PROJECTION);
    setUri(Media.EXTERNAL_CONTENT_URI);
    setSortOrder(Media.DATE_ADDED + " DESC");

    setSelection(
        MIME_TYPE + "=? or " + MIME_TYPE + "=? or "+ MIME_TYPE + "=? " + (showGif ? ("or " + MIME_TYPE + "=?") : ""));
    String[] selectionArgs;
    if (showGif) {
      selectionArgs = new String[] { "image/jpeg", "image/png", "image/jpg","image/gif" };
    } else {
      selectionArgs = new String[] { "image/jpeg", "image/png", "image/jpg" };
    }
    setSelectionArgs(selectionArgs);
  }


  private PhotoDirectoryLoader(Context context, Uri uri, String[] projection, String selection,
      String[] selectionArgs, String sortOrder) {
    super(context, uri, projection, selection, selectionArgs, sortOrder);
  }


}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/PhotoPickerIntent.java
================================================
package me.iwf.photopicker.utils;

import android.content.Intent;
import java.util.ArrayList;

import static me.iwf.photopicker.PhotoPicker.EXTRA_GRID_COLUMN;
import static me.iwf.photopicker.PhotoPicker.EXTRA_MAX_COUNT;
import static me.iwf.photopicker.PhotoPicker.EXTRA_ORIGINAL_PHOTOS;
import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_CAMERA;
import static me.iwf.photopicker.PhotoPicker.EXTRA_SHOW_GIF;

/**
 * Created by donglua on 15/7/2.
 */
@Deprecated
public class PhotoPickerIntent {
  public static void setPhotoCount(Intent intent, int photoCount) {
    intent.putExtra(EXTRA_MAX_COUNT, photoCount);
  }

  public static void setShowCamera(Intent intent, boolean showCamera) {
    intent.putExtra(EXTRA_SHOW_CAMERA, showCamera);
  }

  public static void setShowGif(Intent intent, boolean showGif) {
    intent.putExtra(EXTRA_SHOW_GIF, showGif);
  }

  public static void setColumn(Intent intent, int column) {
    intent.putExtra(EXTRA_GRID_COLUMN, column);
  }

  /**
   * To set some photos that have been selected before
   * @param intent
   * @param imagesUri Selected photos
     */
  public static void setSelected(Intent intent, ArrayList<String> imagesUri) {
    intent.putExtra(EXTRA_ORIGINAL_PHOTOS, imagesUri);
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/MultiPickResultView.java
================================================
package me.iwf.photopicker.widget;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.IntDef;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.Toast;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;

import me.iwf.photopicker.PhotoPickUtils;

/**
 * Created by Administrator on 2016/8/15 0015.
 */
public class MultiPickResultView extends FrameLayout {

    @IntDef({ACTION_SELECT, ACTION_ONLY_SHOW})

    //Tell the compiler not to store annotation data in the .class file
    @Retention(RetentionPolicy.SOURCE)

    //Declare the NavigationMode annotation
    public @interface MultiPicAction {}




    public static final int ACTION_SELECT = 1;//该组件用于图片选择
    public static final int ACTION_ONLY_SHOW = 2;//该组件仅用于图片显示

    private int action;

    private int maxCount;


    android.support.v7.widget.RecyclerView recyclerView;
    PhotoAdapter photoAdapter;
    ArrayList<String> selectedPhotos;
    public MultiPickResultView(Context context) {
        this(context,null,0);
    }

    public MultiPickResultView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MultiPickResultView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context,attrs);
        initData(context,attrs);
        initEvent(context,attrs);
    }

    private void initEvent(Context context, AttributeSet attrs) {

    }

    private void initData(Context context, AttributeSet attrs) {

    }

    private void initView(Context context, AttributeSet attrs) {

        recyclerView = new android.support.v7.widget.RecyclerView(context,attrs);
        recyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, OrientationHelper.VERTICAL));
        this.addView(recyclerView);
    }


    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MultiPickResultView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        this(context, attrs, defStyleAttr);
    }

    public void init(Activity context,@MultiPicAction  int action, ArrayList<String> photos){
        this.action = action;
        if (action == MultiPickResultView.ACTION_ONLY_SHOW){//当只用作显示图片时,一行显示3张
            recyclerView.setLayoutManager(new StaggeredGridLayoutManager(3, OrientationHelper.VERTICAL));
        }

        selectedPhotos = new ArrayList<>();

        this.action = action;
        if (photos != null && photos.size() >0){
            selectedPhotos.addAll(photos);
        }
        photoAdapter = new PhotoAdapter(context, selectedPhotos);
        photoAdapter.setAction(action);
        recyclerView.setAdapter(photoAdapter);
        //recyclerView.setLayoutFrozen(true);


    }


    public void showPics(List<String> paths){
        if (paths != null){
            selectedPhotos.clear();
            selectedPhotos.addAll(paths);
           photoAdapter.notifyDataSetChanged();
        }

    }








    public  void onActivityResult(int requestCode, int resultCode, Intent data){
        if (action == ACTION_SELECT){
            PhotoPickUtils.onActivityResult(requestCode, resultCode, data, new PhotoPickUtils.PickHandler() {
                @Override
                public void onPickSuccess(ArrayList<String> photos) {
                    photoAdapter.refresh(photos);
                }

                @Override
                public void onPreviewBack(ArrayList<String> photos) {
                    photoAdapter.refresh(photos);
                }

                @Override
                public void onPickFail(String error) {
                    Toast.makeText(getContext(),error,Toast.LENGTH_LONG).show();
                    selectedPhotos.clear();
                    photoAdapter.notifyDataSetChanged();
                }

                @Override
                public void onPickCancle() {
                    //Toast.makeText(getContext(),"取消选择",Toast.LENGTH_LONG).show();
                }
            });
        }

    }


    public ArrayList<String> getPhotos() {
        return selectedPhotos;
    }


}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/PhotoAdapter.java
================================================
package me.iwf.photopicker.widget;

import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;

import com.bumptech.glide.Glide;

import java.io.File;
import java.util.ArrayList;

import me.iwf.photopicker.PhotoPickUtils;
import me.iwf.photopicker.PhotoPreview;
import me.iwf.photopicker.R;

/**
 * Created by donglua on 15/5/31.
 */
public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.PhotoViewHolder> {

  private ArrayList<String> photoPaths ;
  private LayoutInflater inflater;

  private Context mContext;


  public void setAction(@MultiPickResultView.MultiPicAction int action) {
    this.action = action;
  }

  private int action;




  public PhotoAdapter(Context mContext, ArrayList<String> photoPaths) {
    this.photoPaths = photoPaths;
    this.mContext = mContext;
    inflater = LayoutInflater.from(mContext);
    padding = dip2Px(8);

  }

  public void add(ArrayList<String> photoPaths){
    if (photoPaths != null && photoPaths.size() >0){
      this.photoPaths.addAll(photoPaths);
      notifyDataSetChanged();
    }

  }

  public void refresh(ArrayList<String> photoPaths){
    this.photoPaths.clear();
    if (photoPaths != null && photoPaths.size() >0){
      this.photoPaths.addAll(photoPaths);
    }
    notifyDataSetChanged();
  }


  @Override public PhotoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = inflater.inflate(R.layout.__picker_item_photo, parent, false);
    return new PhotoViewHolder(itemView);
  }

  public  int dip2Px(int dip) {
    // px/dip = density;
    float density = mContext.getResources().getDisplayMetrics().density;
    int px = (int) (dip * density + .5f);
    return px;
  }

  int padding;
  @Override
  public void onBindViewHolder(final PhotoViewHolder holder, final int position) {

    if (action == MultiPickResultView.ACTION_SELECT){
     // RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.ivPhoto.getLayoutParams();

      holder.ivPhoto.setPadding(padding,padding,padding,padding);


      if (position == getItemCount() -1){//最后一个始终是+号,点击能够跳去添加图片
        Glide.with(mContext)
                .load("")
                .centerCrop()
                .thumbnail(0.1f)
                .placeholder(R.drawable.icon_pic_default)
                .error(R.drawable.icon_pic_default)
                .into(holder.ivPhoto);
        holder.ivPhoto.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
            if (photoPaths != null && photoPaths.size() ==9){
              Toast.makeText(mContext,"已选了9张图片",Toast.LENGTH_SHORT).show();
            }else {
              PhotoPickUtils.startPick((Activity) mContext,false,9,photoPaths);
            }
          }
        });

        holder.deleteBtn.setVisibility(View.GONE);

      }else {
        String str = photoPaths.get(position);
        Log.e("file",str);
        Uri uri = Uri.fromFile(new File(photoPaths.get(position)));
        Glide.with(mContext)
                .load(uri)
                .centerCrop()
                .thumbnail(0.1f)
               // .bitmapTransform(new RoundedCornersTransformation(mContext,6,0))
                .placeholder(R.drawable.__picker_default_weixin)
                .error(R.drawable.__picker_ic_broken_image_black_48dp)
                .into(holder.ivPhoto);


        holder.deleteBtn.setVisibility(View.VISIBLE);
        holder.deleteBtn.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              photoPaths.remove(position);
            notifyDataSetChanged();
          }
        });

        holder.ivPhoto.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
            PhotoPreview.builder()
                    .setPhotos(photoPaths)
                    .setAction(action)
                    .setCurrentItem(position)
                    .start((Activity) mContext);
          }
        });
      }
    }else if (action == MultiPickResultView.ACTION_ONLY_SHOW){
      //Uri uri = Uri.fromFile(new File(photoPaths.get(position)));
      //Uri uri = Uri.parse(photoPaths.get(position));
      Log.e("pic",photoPaths.get(position));
              Glide.with(mContext)
              .load(photoPaths.get(position))
                      .centerCrop()
                      .thumbnail(0.1f)
                     // .bitmapTransform(new RoundedCornersTransformation(mContext,4,0))
              .placeholder(R.drawable.__picker_default_weixin)
              .error(R.drawable.__picker_ic_broken_image_black_48dp)
              .into(holder.ivPhoto);

      holder.ivPhoto.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

          PhotoPreview.builder()
                  .setPhotos(photoPaths)
                  .setAction(action)
                  .setCurrentItem(position)
                  .start((Activity) mContext);
        }
      });
    }




  }




  @Override public int getItemCount() {
    return action == MultiPickResultView.ACTION_SELECT ? photoPaths.size()+1 : photoPaths.size();
  }


  public static class PhotoViewHolder extends RecyclerView.ViewHolder {
    private ImageView ivPhoto;
    private View vSelected;
    public View cover;
    public View deleteBtn;
    public PhotoViewHolder(View itemView) {
      super(itemView);
      ivPhoto   = (ImageView) itemView.findViewById(R.id.iv_photo);
      vSelected = itemView.findViewById(R.id.v_selected);
      vSelected.setVisibility(View.GONE);
      cover = itemView.findViewById(R.id.cover);
      cover.setVisibility(View.GONE);
      deleteBtn = itemView.findViewById(R.id.v_delete);
      deleteBtn.setVisibility(View.GONE);
    }
  }

}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/SquareItemLayout.java
================================================
package me.iwf.photopicker.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

/**
 * Created by donglua on 15/6/21.
 */
public class SquareItemLayout extends RelativeLayout {
  public SquareItemLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
  }

  public SquareItemLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public SquareItemLayout(Context context) {
    super(context);
  }

  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec));
    int childWidthSize = getMeasuredWidth();
    heightMeasureSpec =
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY);
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/Titlebar.java
================================================
package me.iwf.photopicker.widget;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import me.iwf.photopicker.R;

/**
 * Created by Administrator on 2016/8/5.
 */
public class Titlebar extends FrameLayout {
    private RelativeLayout rootView;
    private TextView tvLeft;
    private ImageView ivLeft;

    public TextView getTvTitle() {
        return tvTitle;
    }

    public ImageView getIvLeft() {
        return ivLeft;
    }

    public TextView getTvLeft() {
        return tvLeft;
    }

    public TextView getTvRight() {
        return tvRight;
    }

    public ImageView getIvRight() {
        return ivRight;
    }

    @Override
    public RelativeLayout getRootView() {
        return rootView;
    }

    private TextView tvTitle;
    private TextView tvRight;
    private ImageView ivRight;

    private OnClickListener leftOnclickListener;
    private OnClickListener rightOnclickListener;

    private Activity mActivity;

    public Titlebar(Context context) {
        this(context,null);
    }

    public Titlebar(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public Titlebar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
        initData(context, attrs,defStyleAttr);
        initEvent(context,attrs,defStyleAttr);
    }

    public void init(Activity activity){
        mActivity = activity;
        leftOnclickListener = new OnClickListener() {
            @Override
            public void onClick(View view) {
                mActivity.finish();
            }
        };
        ivLeft.setOnClickListener(leftOnclickListener);

    }

    private void initEvent(Context context, AttributeSet attrs, int defStyleAttr) {

        if (context instanceof Activity){
            final Activity activity = (Activity) context;
            leftOnclickListener = new OnClickListener() {
                @Override
                public void onClick(View view) {
                    activity.finish();
                }
            };
        }


    }

    public void setLeftOnclickListener(OnClickListener listener){
        if (listener != null){
            leftOnclickListener = listener;
            ivLeft.setOnClickListener(leftOnclickListener);
            tvLeft.setOnClickListener(leftOnclickListener);
        }

    }

    public void setRightOnclickListener(OnClickListener listener){
        if (listener != null){
            rightOnclickListener = listener;
            ivRight.setOnClickListener(rightOnclickListener);
            tvRight.setOnClickListener(rightOnclickListener);
        }
    }

    public void setTitle(String title){
        if (!TextUtils.isEmpty(title)){
            tvTitle.setText(title);
            tvTitle.setVisibility(VISIBLE);
        }
    }

    public void setLeft(Drawable leftDrawable,String leftTxt,OnClickListener listener){
        if (leftDrawable != null){
            ivLeft.setVisibility(VISIBLE);
            ivLeft.setImageDrawable(leftDrawable);
            tvLeft.setVisibility(GONE);
        }else if (!TextUtils.isEmpty(leftTxt)){
            tvLeft.setVisibility(VISIBLE);
            tvLeft.setText(leftTxt);
            ivLeft.setVisibility(GONE);
        }else {//all not set,default

        }

        if (listener != null){
            leftOnclickListener = listener;
        }




    }

    public void setRitht(Drawable rightDrawable,String rightTxt,OnClickListener listener){
        if (!TextUtils.isEmpty(rightTxt)){
            tvRight.setVisibility(VISIBLE);
            tvRight.setText(rightTxt);
            ivRight.setVisibility(GONE);
            if (listener != null){
                rightOnclickListener = listener;
                tvRight.setOnClickListener(rightOnclickListener);
            }
        }else if (rightDrawable != null){
            ivRight.setVisibility(VISIBLE);
            tvRight.setVisibility(GONE);
            ivRight.setImageDrawable(rightDrawable);
            if (listener != null){
                rightOnclickListener = listener;
                ivRight.setOnClickListener(rightOnclickListener);
            }
        }else {

        }

        if (listener != null){
            rightOnclickListener = listener;
            ivRight.setOnClickListener(rightOnclickListener);
        }
    }

    private void initData(Context context, AttributeSet attrs, int defStyleAttr) {

        TypedArray typedArray = null;
        try {
            typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTitlebar);
          String  leftTxt = typedArray.getString(R.styleable.MyTitlebar_mtb_leftTxt);
            String  title = typedArray.getString(R.styleable.MyTitlebar_mtb_title);
            String  rightTxt = typedArray.getString(R.styleable.MyTitlebar_mtb_rightTxt);

            Drawable leftDrawable = typedArray.getDrawable(R.styleable.MyTitlebar_mtb_left_icon);
            Drawable rightDrawable = typedArray.getDrawable(R.styleable.MyTitlebar_mtb_right_icon);

           //left:drawable first
           setLeft(leftDrawable,leftTxt,null);

            //center
            setTitle(title);


            //right: text first
            setRitht(rightDrawable,rightTxt,null);


        } finally {
            if (typedArray != null) {
                typedArray.recycle();
            }
        }

    }

    private void initView(Context context) {
        rootView = (RelativeLayout) View.inflate(context,R.layout.view_titlebar,null);
        ivLeft = (ImageView) rootView.findViewById(R.id.iv_left);
        tvLeft = (TextView) rootView.findViewById(R.id.tv_left);

        tvTitle = (TextView) rootView.findViewById(R.id.tv_title);

        ivRight = (ImageView) rootView.findViewById(R.id.iv_right);
        tvRight = (TextView) rootView.findViewById(R.id.tv_right);
        this.addView(rootView);

    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public Titlebar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        this(context, attrs, defStyleAttr);
    }
}


================================================
FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/TouchImageView.java
================================================
/*
 * TouchImageView.java
 * By: Michael Ortiz
 * Updated By: Patrick Lackemacher
 * Updated By: Babay88
 * Updated By: @ipsilondev
 * Updated By: hank-cp
 * Updated By: singpolyma
 * -------------------
 * Extends Android ImageView to include pinch zooming, panning, fling and double tap zoom.
 */

package me.iwf.photopicker.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.OverScroller;
import android.widget.Scroller;

public class TouchImageView extends ImageView {

  private static final String DEBUG = "DEBUG";

  //
  // SuperMin and SuperMax multipliers. Determine how much the image can be
  // zoomed below or above the zoom boundaries, before animating back to the
  // min/max zoom boundary.
  //
  private static final float SUPER_MIN_MULTIPLIER = .75f;
  private static final float SUPER_MAX_MULTIPLIER = 1.25f;

  //
  // Scale of image ranges from minScale to maxScale, where minScale == 1
  // when the image is stretched to fit view.
  //
  private float normalizedScale;

  //
  // Matrix applied to image. MSCALE_X and MSCALE_Y should always be equal.
  // MTRANS_X and MTRANS_Y are the other values used. prevMatrix is the matrix
  // saved prior to the screen rotating.
  //
  private Matrix matrix, prevMatrix;

  private enum State {NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM}

  ;
  private State state;

  private float minScale;
  private float maxScale;
  private float superMinScale;
  private float superMaxScale;
  private float[] m;

  private Context context;
  private Fling fling;

  private ScaleType mScaleType;

  private boolean imageRenderedAtLeastOnce;
  private boolean onDrawReady;

  private ZoomVariables delayedZoomVariables;

  //
  // Size of view and previous view size (ie before rotation)
  //
  private int viewWidth, viewHeight, prevViewWidth, prevViewHeight;

  //
  // Size of image when it is stretched to fit view. Before and After rotation.
  //
  private float matchViewWidth, matchViewHeight, prevMatchViewWidth, prevMatchViewHeight;

  private ScaleGestureDetector mScaleDetector;
  private GestureDetector mGestureDetector;
  private GestureDetector.OnDoubleTapListener doubleTapListener = null;
  private OnTouchListener userTouchListener = null;
  private OnTouchImageViewListener touchImageViewListener = null;

  public TouchImageView(Context context) {
    super(context);
    sharedConstructing(context);
  }

  public TouchImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    sharedConstructing(context);
  }

  public TouchImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    sharedConstructing(context);
  }

  private void sharedConstructing(Context context) {
    super.setClickable(true);
    this.context = context;
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    mGestureDetector = new GestureDetector(context, new GestureListener());
    matrix = new Matrix();
    prevMatrix = new Matrix();
    m = new float[9];
    normalizedScale = 1;
    if (mScaleType == null) {
      mScaleType = ScaleType.FIT_CENTER;
    }
    minScale = 1;
    maxScale = 3;
    superMinScale = SUPER_MIN_MULTIPLIER * minScale;
    superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
    setImageMatrix(matrix);
    setScaleType(ScaleType.MATRIX);
    setState(State.NONE);
    onDrawReady = false;
    super.setOnTouchListener(new PrivateOnTouchListener());
  }

  @Override public void setOnTouchListener(View.OnTouchListener l) {
    userTouchListener = l;
  }

  public void setOnTouchImageViewListener(OnTouchImageViewListener l) {
    touchImageViewListener = l;
  }

  public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener l) {
    doubleTapListener = l;
  }

  @Override public void setImageResource(int resId) {
    super.setImageResource(resId);
    savePreviousImageValues();
    fitImageToView();
  }

  @Override public void setImageBitmap(Bitmap bm) {
    super.setImageBitmap(bm);
    savePreviousImageValues();
    fitImageToView();
  }

  @Override public void setImageDrawable(Drawable drawable) {
    super.setImageDrawable(drawable);
    savePreviousImageValues();
    fitImageToView();
  }

  @Override public void setImageURI(Uri uri) {
    super.setImageURI(uri);
    savePreviousImageValues();
    fitImageToView();
  }

  @Override public void setScaleType(ScaleType type) {
    if (type == ScaleType.FIT_START || type == ScaleType.FIT_END) {
      throw new UnsupportedOperationException(
          "TouchImageView does not support FIT_START or FIT_END");
    }
    if (type == ScaleType.MATRIX) {
      super.setScaleType(ScaleType.MATRIX);
    } else {
      mScaleType = type;
      if (onDrawReady) {
        //
        // If the image is already rendered, scaleType has been called programmatically
        // and the TouchImageView should be updated with the new scaleType.
        //
        setZoom(this);
      }
    }
  }

  @Override public ScaleType getScaleType() {
    return mScaleType;
  }

  /**
   * Returns false if image is in initial, unzoomed state. False, otherwise.
   *
   * @return true if image is zoomed
   */
  public boolean isZoomed() {
    return normalizedScale != 1;
  }

  /**
   * Return a Rect representing the zoomed image.
   *
   * @return rect representing zoomed image
   */
  public RectF getZoomedRect() {
    if (mScaleType == ScaleType.FIT_XY) {
      throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
    }
    PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
    PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);

    float w = getDrawable().getIntrinsicWidth();
    float h = getDrawable().getIntrinsicHeight();
    return new RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);
  }

  /**
   * Save the current matrix and view dimensions
   * in the prevMatrix and prevView variables.
   */
  private void savePreviousImageValues() {
    if (matrix != null && viewHeight != 0 && viewWidth != 0) {
      matrix.getValues(m);
      prevMatrix.setValues(m);
      prevMatchViewHeight = matchViewHeight;
      prevMatchViewWidth = matchViewWidth;
      prevViewHeight = viewHeight;
      prevViewWidth = viewWidth;
    }
  }

  @Override public Parcelable onSaveInstanceState() {
    Bundle bundle = new Bundle();
    bundle.putParcelable("instanceState", super.onSaveInstanceState());
    bundle.putFloat("saveScale", normalizedScale);
    bundle.putFloat("matchViewHeight", matchViewHeight);
    bundle.putFloat("matchViewWidth", matchViewWidth);
    bundle.putInt("viewWidth", viewWidth);
    bundle.putInt("viewHeight", viewHeight);
    matrix.getValues(m);
    bundle.putFloatArray("matrix", m);
    bundle.putBoolean("imageRendered", imageRenderedAtLeastOnce);
    return bundle;
  }

  @Override public void onRestoreInstanceState(Parcelable state) {
    if (state instanceof Bundle) {
      Bundle bundle = (Bundle) state;
      normalizedScale = bundle.getFloat("saveScale");
      m = bundle.getFloatArray("matrix");
      prevMatrix.setValues(m);
      prevMatchViewHeight = bundle.getFloat("matchViewHeight");
      prevMatchViewWidth = bundle.getFloat("matchViewWidth");
      prevViewHeight = bundle.getInt("viewHeight");
      prevViewWidth = bundle.getInt("viewWidth");
      imageRenderedAtLeastOnce = bundle.getBoolean("imageRendered");
      super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
      return;
    }

    super.onRestoreInstanceState(state);
  }

  @Override protected void onDraw(Canvas canvas) {
    onDrawReady = true;
    imageRenderedAtLeastOnce = true;
    if (delayedZoomVariables != null) {
      setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY,
          delayedZoomVariables.scaleType);
      delayedZoomVariables = null;
    }
    super.onDraw(canvas);
  }

  @Override public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    savePreviousImageValues();
  }

  /**
   * Get the max zoom multiplier.
   *
   * @return max zoom multiplier.
   */
  public float getMaxZoom() {
    return maxScale;
  }

  /**
   * Set the max zoom multiplier. Default value: 3.
   *
   * @param max max zoom multiplier.
   */
  public void setMaxZoom(float max) {
    maxScale = max;
    superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
  }

  /**
   * Get the min zoom multiplier.
   *
   * @return min zoom multiplier.
   */
  public float getMinZoom() {
    return minScale;
  }

  /**
   * Get the current zoom. This is the zoom relative to the initial
   * scale, not the original resource.
   *
   * @return current zoom multiplier.
   */
  public float getCurrentZoom() {
    return normalizedScale;
  }

  /**
   * Set the min zoom multiplier. Default value: 1.
   *
   * @param min min zoom multiplier.
   */
  public void setMinZoom(float min) {
    minScale = min;
    superMinScale = SUPER_MIN_MULTIPLIER * minScale;
  }

  /**
   * Reset zoom and translation to initial state.
   */
  public void resetZoom() {
    normalizedScale = 1;
    fitImageToView();
  }

  /**
   * Set zoom to the specified scale. Image will be centered by default.
   */
  public void setZoom(float scale) {
    setZoom(scale, 0.5f, 0.5f);
  }

  /**
   * Set zoom to the specified scale. Image will be centered around the point
   * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
   * as a fraction from the left and top of the view. For example, the top left
   * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
   */
  public void setZoom(float scale, float focusX, float focusY) {
    setZoom(scale, focusX, focusY, mScaleType);
  }

  /**
   * Set zoom to the specified scale. Image will be centered around the point
   * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
   * as a fraction from the left and top of the view. For example, the top left
   * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
   */
  public void setZoom(float scale, float focusX, float focusY, ScaleType scaleType) {
    //
    // setZoom can be called before the image is on the screen, but at this point,
    // image and view sizes have not yet been calculated in onMeasure. Thus, we should
    // delay calling setZoom until the view has been measured.
    //
    if (!onDrawReady) {
      delayedZoomVariables = new ZoomVariables(scale, focusX, focusY, scaleType);
      return;
    }

    if (scaleType != mScaleType) {
      setScaleType(scaleType);
    }
    resetZoom();
    scaleImage(scale, viewWidth / 2, viewHeight / 2, true);
    matrix.getValues(m);
    m[Matrix.MTRANS_X] = -((focusX * getImageWidth()) - (viewWidth * 0.5f));
    m[Matrix.MTRANS_Y] = -((focusY * getImageHeight()) - (viewHeight * 0.5f));
    matrix.setValues(m);
    fixTrans();
    setImageMatrix(matrix);
  }

  /**
   * Set zoom parameters equal to another TouchImageView. Including scale, position,
   * and ScaleType.
   */
  public void setZoom(TouchImageView img) {
    PointF center = img.getScrollPosition();
    setZoom(img.getCurrentZoom(), center.x, center.y, img.getScaleType());
  }

  /**
   * Return the point at the center of the zoomed image. The PointF coordinates range
   * in value between 0 and 1 and the focus point is denoted as a fraction from the left
   * and top of the view. For example, the top left corner of the image would be (0, 0).
   * And the bottom right corner would be (1, 1).
   *
   * @return PointF representing the scroll position of the zoomed image.
   */
  public PointF getScrollPosition() {
    Drawable drawable = getDrawable();
    if (drawable == null) {
      return null;
    }
    int drawableWidth = drawable.getIntrinsicWidth();
    int drawableHeight = drawable.getIntrinsicHeight();

    PointF point = transformCoordTouchToBitmap(viewWidth / 2, viewHeight / 2, true);
    point.x /= drawableWidth;
    point.y /= drawableHeight;
    return point;
  }

  /**
   * Set the focus point of the zoomed image. The focus points are denoted as a fraction from the
   * left and top of the view. The focus points can range in value between 0 and 1.
   */
  public void setScrollPosition(float focusX, float focusY) {
    setZoom(normalizedScale, focusX, focusY);
  }

  /**
   * Performs boundary checking and fixes the image matrix if it
   * is out of bounds.
   */
  private void fixTrans() {
    matrix.getValues(m);
    float transX = m[Matrix.MTRANS_X];
    float transY = m[Matrix.MTRANS_Y];

    float fixTransX = getFixTrans(transX, viewWidth, getImageWidth());
    float fixTransY = getFixTrans(transY, viewHeight, getImageHeight());

    if (fixTransX != 0 || fixTransY != 0) {
      matrix.postTranslate(fixTransX, fixTransY);
    }
  }

  /**
   * When transitioning from zooming from focus to zoom from center (or vice versa)
   * the image can become unaligned within the view. This is apparent when zooming
   * quickly. When the content size is less than the view size, the content will often
   * be centered incorrectly within the view. fixScaleTrans first calls fixTrans() and
   * then makes sure the image is centered correctly within the view.
   */
  private void fixScaleTrans() {
    fixTrans();
    matrix.getValues(m);
    if (getImageWidth() < viewWidth) {
      m[Matrix.MTRANS_X] = (viewWidth - getImageWidth()) / 2;
    }

    if (getImageHeight() < viewHeight) {
      m[Matrix.MTRANS_Y] = (viewHeight - getImageHeight()) / 2;
    }
    matrix.setValues(m);
  }

  private float getFixTrans(float trans, float viewSize, float contentSize) {
    float minTrans, maxTrans;

    if (contentSize <= viewSize) {
      minTrans = 0;
      maxTrans = viewSize - contentSize;
    } else {
      minTrans = viewSize - contentSize;
      maxTrans = 0;
    }

    if (trans < minTrans) return -trans + minTrans;
    if (trans > maxTrans) return -trans + maxTrans;
    return 0;
  }

  private float getFixDragTrans(float delta, float viewSize, float contentSize) {
    if (contentSize <= viewSize) {
      return 0;
    }
    return delta;
  }

  private float getImageWidth() {
    return matchViewWidth * normalizedScale;
  }

  private float getImageHeight() {
    return matchViewHeight * normalizedScale;
  }

  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    Drawable drawable = getDrawable();
    if (drawable == null || drawable.getIntrinsicWidth() == 0
        || drawable.getIntrinsicHeight() == 0) {
      setMeasuredDimension(0, 0);
      return;
    }

    int drawableWidth = drawable.getIntrinsicWidth();
    int drawableHeight = drawable.getIntrinsicHeight();
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    viewWidth = setViewSize(widthMode, widthSize, drawableWidth);
    viewHeight = setViewSize(heightMode, heightSize, drawableHeight);

    //
    // Set view dimensions
    //
    setMeasuredDimension(viewWidth, viewHeight);

    //
    // Fit content within view
    //
    fitImageToView();
  }

  /**
   * If the normalizedScale is equal to 1, then the image is made to fit the screen. Otherwise,
   * it is made to fit the screen according to the dimensions of the previous image matrix. This
   * allows the image to maintain its zoom after rotation.
   */
  private void fitImageToView() {
    Drawable drawable = getDrawable();
    if (drawable == null || drawable.getIntrinsicWidth() == 0
        || drawable.getIntrinsicHeight() == 0) {
      return;
    }
    if (matrix == null || prevMatrix == null) {
      return;
    }

    int drawableWidth = drawable.getIntrinsicWidth();
    int drawableHeight = drawable.getIntrinsicHeight();

    //
    // Scale image for view
    //
    float scaleX = (float) viewWidth / drawableWidth;
    float scaleY = (float) viewHeight / drawableHeight;

    switch (mScaleType) {
      case CENTER:
        scaleX = scaleY = 1;
        break;

      case CENTER_CROP:
        scaleX = scaleY = Math.max(scaleX, scaleY);
        break;

      case CENTER_INSIDE:
        scaleX = scaleY = Math.min(1, Math.min(scaleX, scaleY));

      case FIT_CENTER:
        scaleX = scaleY = Math.min(scaleX, scaleY);
        break;

      case FIT_XY:
        break;

      default:
        //
        // FIT_START and FIT_END not supported
        //
        throw new UnsupportedOperationException(
            "TouchImageView does not support FIT_START or FIT_END");
    }

    //
    // Center the image
    //
    float redundantXSpace = viewWidth - (scaleX * drawableWidth);
    float redundantYSpace = viewHeight - (scaleY * drawableHeight);
    matchViewWidth = viewWidth - redundantXSpace;
    matchViewHeight = viewHeight - redundantYSpace;
    if (!isZoomed() && !imageRenderedAtLeastOnce) {
      //
      // Stretch and center image to fit view
      //
      matrix.setScale(scaleX, scaleY);
      matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
      normalizedScale = 1;
    } else {
      //
      // These values should never be 0 or we will set viewWidth and viewHeight
      // to NaN in translateMatrixAfterRotate. To avoid this, call savePreviousImageValues
      // to set them equal to the current values.
      //
      if (prevMatchViewWidth == 0 || prevMatchViewHeight == 0) {
        savePreviousImageValues();
      }

      prevMatrix.getValues(m);

      //
      // Rescale Matrix after rotation
      //
      m[Matrix.MSCALE_X] = matchViewWidth / drawableWidth * normalizedScale;
      m[Matrix.MSCALE_Y] = matchViewHeight / drawableHeight * normalizedScale;

      //
      // TransX and TransY from previous matrix
      //
      float transX = m[Matrix.MTRANS_X];
      float transY = m[Matrix.MTRANS_Y];

      //
      // Width
      //
      float prevActualWidth = prevMatchViewWidth * normalizedScale;
      float actualWidth = getImageWidth();
      translateMatrixAfterRotate(Matrix.MTRANS_X, transX, prevActualWidth, actualWidth,
          prevViewWidth, viewWidth, drawableWidth);

      //
      // Height
      //
      float prevActualHeight = prevMatchViewHeight * normalizedScale;
      float actualHeight = getImageHeight();
      translateMatrixAfterRotate(Matrix.MTRANS_Y, transY, prevActualHeight, actualHeight,
          prevViewHeight, viewHeight, drawableHeight);

      //
      // Set the matrix to the adjusted scale and translate values.
      //
      matrix.setValues(m);
    }
    fixTrans();
    setImageMatrix(matrix);
  }

  /**
   * Set view dimensions based on layout params
   */
  private int setViewSize(int mode, int size, int drawableWidth) {
    int viewSize;
    switch (mode) {
      case MeasureSpec.EXACTLY:
        viewSize = size;
        break;

      case MeasureSpec.AT_MOST:
        viewSize = Math.min(drawableWidth, size);
        break;

      case MeasureSpec.UNSPECIFIED:
        viewSize = drawableWidth;
        break;

      default:
        viewSize = size;
        break;
    }
    return viewSize;
  }

  /**
   * After rotating, the matrix needs to be translated. This function finds the area of image
   * which was previously centered and adjusts translations so that is again the center,
   * post-rotation.
   *
   * @param axis Matrix.MTRANS_X or Matrix.MTRANS_Y
   * @param trans the value of trans in that axis before the rotation
   * @param prevImageSize the width/height of the image before the rotation
   * @param imageSize width/height of the image after rotation
   * @param prevViewSize width/height of view before rotation
   * @param viewSize width/height of view after rotation
   * @param drawableSize width/height of drawable
   */
  private void translateMatrixAfterRotate(int axis, float trans, float prevImageSize,
      float imageSize, int prevViewSize, int viewSize, int drawableSize) {
    if (imageSize < viewSize) {
      //
      // The width/height of image is less than the view's width/height. Center it.
      //
      m[axis] = (viewSize - (drawableSize * m[Matrix.MSCALE_X])) * 0.5f;
    } else if (trans > 0) {
      //
      // The image is larger than the view, but was not before rotation. Center it.
      //
      m[axis] = -((imageSize - viewSize) * 0.5f);
    } else {
      //
      // Find the area of the image which was previously centered in the view. Determine its distance
      // from the left/top side of the view as a fraction of the entire image's width/height. Use that percentage
      // to calculate the trans in the new view width/height.
      //
      float percentage = (Math.abs(trans) + (0.5f * prevViewSize)) / prevImageSize;
      m[axis] = -((percentage * imageSize) - (viewSize * 0.5f));
    }
  }

  private void setState(State state) {
    this.state = state;
  }

  public boolean canScrollHorizontallyFroyo(int direction) {
    return canScrollHorizontally(direction);
  }

  @Override public boolean canScrollHorizontally(int direction) {
    matrix.getValues(m);
    float x = m[Matrix.MTRANS_X];

    if (getImageWidth() < viewWidth) {
      return false;
    } else if (x >= -1 && direction < 0) {
      return false;
    } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
      return false;
    }

    return true;
  }

  /**
   * Gesture Listener detects a single click or long click and passes that on
   * to the view's listener.
   *
   * @author Ortiz
   */
  private class GestureListener extends GestureDetector.SimpleOnGestureListener {

    @Override public boolean onSingleTapConfirmed(MotionEvent e) {
      if (doubleTapListener != null) {
        return doubleTapListener.onSingleTapConfirmed(e);
      }
      return performClick();
    }

    @Override public void onLongPress(MotionEvent e) {
      performLongClick();
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      if (fling != null) {
        //
        // If a previous fling is still active, it should be cancelled so that two flings
        // are not run simultaenously.
        //
        fling.cancelFling();
      }
      fling = new Fling((int) velocityX, (int) velocityY);
      compatPostOnAnimation(fling);
      return super.onFling(e1, e2, velocityX, velocityY);
    }

    @Override public boolean onDoubleTap(MotionEvent e) {
      boolean consumed = false;
      if (doubleTapListener != null) {
        consumed = doubleTapListener.onDoubleTap(e);
      }
      if (state == State.NONE) {
        float targetZoom = (normalizedScale == minScale) ? maxScale : minScale;
        DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, e.getX(), e.getY(), false);
        compatPostOnAnimation(doubleTap);
        consumed = true;
      }
      return consumed;
    }

    @Override public boolean onDoubleTapEvent(MotionEvent e) {
      if (doubleTapListener != null) {
        return doubleTapListener.onDoubleTapEvent(e);
      }
      return false;
    }
  }

  public interface OnTouchImageViewListener {
    public void onMove();
  }

  /**
   * Responsible for all touch events. Handles the heavy lifting of drag and also sends
   * touch events to Scale Detector and Gesture Detector.
   *
   * @author Ortiz
   */
  private class PrivateOnTouchListener implements OnTouchListener {

    //
    // Remember last point position for dragging
    //
    private PointF last = new PointF();

    @Override public boolean onTouch(View v, MotionEvent event) {
      mScaleDetector.onTouchEvent(event);
      mGestureDetector.onTouchEvent(event);
      PointF curr = new PointF(event.getX(), event.getY());

      if (state == State.NONE || state == State.DRAG || state == State.FLING) {
        switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
            last.set(curr);
            if (fling != null) fling.cancelFling();
            setState(State.DRAG);
            break;

          case MotionEvent.ACTION_MOVE:
            if (state == State.DRAG) {
              float deltaX = curr.x - last.x;
              float deltaY = curr.y - last.y;
              float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth());
              float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight());
              matrix.postTranslate(fixTransX, fixTransY);
              fixTrans();
              last.set(curr.x, curr.y);
            }
            break;

          case MotionEvent.ACTION_UP:
          case MotionEvent.ACTION_POINTER_UP:
            setState(State.NONE);
            break;
        }
      }

      setImageMatrix(matrix);

      //
      // User-defined OnTouchListener
      //
      if (userTouchListener != null) {
        userTouchListener.onTouch(v, event);
      }

      //
      // OnTouchImageViewListener is set: TouchImageView dragged by user.
      //
      if (touchImageViewListener != null) {
        touchImageViewListener.onMove();
      }

      //
      // indicate event was handled
      //
      return true;
    }
  }

  /**
   * ScaleListener detects user two finger scaling and scales image.
   *
   * @author Ortiz
   */
  private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override public boolean onScaleBegin(ScaleGestureDetector detector) {
      setState(State.ZOOM);
      return true;
    }

    @Override public boolean onScale(ScaleGestureDetector detector) {
      scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true);

      //
      // OnTouchImageViewListener is set: TouchImageView pinch zoomed by user.
      //
      if (touchImageViewListener != null) {
        touchImageViewListener.onMove();
      }
      return true;
    }

    @Override public void onScaleEnd(ScaleGestureDetector detector) {
      super.onScaleEnd(detector);
      setState(State.NONE);
      boolean animateToZoomBoundary = false;
      float targetZoom = normalizedScale;
      if (normalizedScale > maxScale) {
        targetZoom = maxScale;
        animateToZoomBoundary = true;
      } else if (normalizedScale < minScale) {
        targetZoom = minScale;
        animateToZoomBoundary = true;
      }

      if (animateToZoomBoundary) {
        DoubleTapZoom doubleTap =
            new DoubleTapZoom(targetZoom, viewWidth / 2, viewHeight / 2, true);
        compatPostOnAnimation(doubleTap);
      }
    }
  }

  private void scaleImage(double deltaScale, float focusX, float focusY,
      boolean stretchImageToSuper) {

    float lowerScale, upperScale;
    if (stretchImageToSuper) {
      lowerScale = superMinScale;
      upperScale = superMaxScale;
    } else {
      lowerScale = minScale;
      upperScale = maxScale;
    }

    float origScale = normalizedScale;
    normalizedScale *= deltaScale;
    if (normalizedScale > upperScale) {
      normalizedScale = upperScale;
      deltaScale = upperScale / origScale;
    } else if (normalizedScale < lowerScale) {
      normalizedScale = lowerScale;
      deltaScale = lowerScale / origScale;
    }

    matrix.postScale((float) deltaScale, (float) deltaScale, focusX, focusY);
    fixScaleTrans();
  }

  /**
   * DoubleTapZoom calls a series of runnables which apply
   * an animated zoom in/out graphic to the image.
   *
   * @author Ortiz
   */
  private class DoubleTapZoom implements Runnable {

    private long startTime;
    private static final float ZOOM_TIME = 500;
    private float startZoom, targetZoom;
    private float bitmapX, bitmapY;
    private boolean stretchImageToSuper;
    private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
    private PointF startTouch;
    private PointF endTouch;

    DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean stretchImageToSuper) {
      setState(State.ANIMATE_ZOOM);
      startTime = System.currentTimeMillis();
      this.startZoom = normalizedScale;
      this.targetZoom = targetZoom;
      this.stretchImageToSuper = stretchImageToSuper;
      PointF bitmapPoint = transformCoordTouchToBitmap(focusX, focusY, false);
      this.bitmapX = bitmapPoint.x;
      this.bitmapY = bitmapPoint.y;

      //
      // Used for translating image during scaling
      //
      startTouch = transformCoordBitmapToTouch(bitmapX, bitmapY);
      endTouch = new PointF(viewWidth / 2, viewHeight / 2);
    }

    @Override public void run() {
      float t = interpolate();
      double deltaScale = calculateDeltaScale(t);
      scaleImage(deltaScale, bitmapX, bitmapY, stretchImageToSuper);
      translateImageToCenterTouchPosition(t);
      fixScaleTrans();
      setImageMatrix(matrix);

      //
      // OnTouchImageViewListener is set: double tap runnable updates listener
      // with every frame.
      //
      if (touchImageViewListener != null) {
        touchImageViewListener.onMove();
      }

      if (t < 1f) {
        //
        // We haven't finished zooming
        //
        compatPostOnAnimation(this);
      } else {
        //
        // Finished zooming
        //
        setState(State.NONE);
      }
    }

    /**
     * Interpolate between where the image should start and end in order to translate
     * the image so that the point that is touched is what ends up centered at the end
     * of the zoom.
     */
    private void translateImageToCenterTouchPosition(float t) {
      float targetX = startTouch.x + t * (endTouch.x - startTouch.x);
      float targetY = startTouch.y + t * (endTouch.y - startTouch.y);
      PointF curr = transformCoordBitmapToTouch(bitmapX, bitmapY);
      matrix.postTranslate(targetX - curr.x, targetY - curr.y);
    }

    /**
     * Use interpolator to get t
     */
    private float interpolate() {
      long currTime = System.currentTimeMillis();
      float elapsed = (currTime - startTime) / ZOOM_TIME;
      elapsed = Math.min(1f, elapsed);
      return interpolator.getInterpolation(elapsed);
    }

    /**
     * Interpolate the current targeted zoom and get the delta
     * from the current zoom.
     */
    private double calculateDeltaScale(float t) {
      double zoom = startZoom + t * (targetZoom - startZoom);
      return zoom / normalizedScale;
    }
  }

  /**
   * This function will transform the coordinates in the touch event to the coordinate
   * system of the drawable that the imageview contain
   *
   * @param x x-coordinate of touch event
   * @param y y-coordinate of touch event
   * @param clipToBitmap Touch event may occur within view, but outside image content. True, to clip
   * return value
   * to the bounds of the bitmap size.
   * @return Coordinates of the point touched, in the coordinate system of the original drawable.
   */
  private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) {
    matrix.getValues(m);
    float origW = getDrawable().getIntrinsicWidth();
    float origH = getDrawable().getIntrinsicHeight();
    float transX = m[Matrix.MTRANS_X];
    float transY = m[Matrix.MTRANS_Y];
    float finalX = ((x - transX) * origW) / getImageWidth();
    float finalY = ((y - transY) * origH) / getImageHeight();

    if (clipToBitmap) {
      finalX = Math.min(Math.max(finalX, 0), origW);
      finalY = Math.min(Math.max(finalY, 0), origH);
    }

    return new PointF(finalX, finalY);
  }

  /**
   * Inverse of transformCoordTouchToBitmap. This function will transform the coordinates in the
   * drawable's coordinate system to the view's coordinate system.
   *
   * @param bx x-coordinate in original bitmap coordinate system
   * @param by y-coordinate in original bitmap coordinate system
   * @return Coordinates of the point in the view's coordinate system.
   */
  private PointF transformCoordBitmapToTouch(float bx, float by) {
    matrix.getValues(m);
    float origW = getDrawable().getIntrinsicWidth();
    float origH = getDrawable().getIntrinsicHeight();
    float px = bx / origW;
    float py = by / origH;
    float finalX = m[Matrix.MTRANS_X] + getImageWidth() * px;
    float finalY = m[Matrix.MTRANS_Y] + getImageHeight() * py;
    return new PointF(finalX, finalY);
  }

  /**
   * Fling launches sequential runnables which apply
   * the fling graphic to the image. The values for the translation
   * are interpolated by the Scroller.
   *
   * @author Ortiz
   */
  private class Fling implements Runnable {

    CompatScroller scroller;
    int currX, currY;

    Fling(int velocityX, int velocityY) {
      setState(State.FLING);
      scroller = new CompatScroller(context);
      matrix.getValues(m);

      int startX = (int) m[Matrix.MTRANS_X];
      int startY = (int) m[Matrix.MTRANS_Y];
      int minX, maxX, minY, maxY;

      if (getImageWidth() > viewWidth) {
        minX = viewWidth - (int) getImageWidth();
        maxX = 0;
      } else {
        minX = maxX = startX;
      }

      if (getImageHeight() > viewHeight) {
        minY = viewHeight - (int) getImageHeight();
        maxY = 0;
      } else {
        minY = maxY = startY;
      }

      scroller.fling(startX, startY, (int) velocityX, (int) velocityY, minX, maxX, minY, maxY);
      currX = startX;
      currY = startY;
    }

    public void cancelFling() {
      if (scroller != null) {
        setState(State.NONE);
        scroller.forceFinished(true);
      }
    }

    @Override public void run() {

      //
      // OnTouchImageViewListener is set: TouchImageView listener has been flung by user.
      // Listener runnable updated with each frame of fling animation.
      //
      if (touchImageViewListener != null) {
        touchImageViewListener.onMove();
      }

      if (scroller.isFinished()) {
        scroller = null;
        return;
      }

      if (scroller.computeScrollOffset()) {
        int newX = scroller.getCurrX();
        int newY = scroller.getCurrY();
        int transX = newX - currX;
        int transY = newY - currY;
        currX = newX;
        currY = newY;
        matrix.postTranslate(transX, transY);
        fixTrans();
        setImageMatrix(matrix);
        compatPostOnAnimation(this);
      }
    }
  }

  @TargetApi(Build.VERSION_CODES.GINGERBREAD) private class CompatScroller {
    Scroller scroller;
    OverScroller overScroller;
    boolean isPreGingerbread;

    public CompatScroller(Context context) {
      if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
        isPreGingerbread = true;
        scroller = new Scroller(context);
      } else {
        isPreGingerbread = false;
        overScroller = new OverScroller(context);
      }
    }

    public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX,
        int minY, int maxY) {
      if (isPreGingerbread) {
        scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
      } else {
        overScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
      }
    }

    public void forceFinished(boolean finished) {
      if (isPreGingerbread) {
        scroller.forceFinished(finished);
      } else {
        overScroller.forceFinished(finished);
      }
    }

    public boolean isFinished() {
      if (isPreGingerbread) {
        return scroller.isFinished();
      } else {
        return overScroller.isFinished();
      }
    }

    public boolean computeScrollOffset() {
      if (isPreGingerbread) {
        return scroller.computeScrollOffset();
      } else {
        overScroller.computeScrollOffset();
        return overScroller.computeScrollOffset();
      }
    }

    public int getCurrX() {
      if (isPreGingerbread) {
        return scroller.getCurrX();
      } else {
        return overScroller.getCurrX();
      }
    }

    public int getCurrY() {
      if (isPreGingerbread) {
        return scroller.getCurrY();
      } else {
        return overScroller.getCurrY();
      }
    }
  }

  @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void compatPostOnAnimation(Runnable runnable) {
    if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
      postOnAnimation(runnable);
    } else {
      postDelayed(runnable, 1000 / 60);
    }
  }

  private class ZoomVariables {
    public float scale;
    public float focusX;
    public float focusY;
    public ScaleType scaleType;

    public ZoomVariables(float scale, float focusX, float focusY, ScaleType scaleType) {
      this.scale = scale;
      this.focusX = focusX;
      this.focusY = focusY;
      this.scaleType = scaleType;
    }
  }

  private void printMatrixInfo() {
    float[] n = new float[9];
    matrix.getValues(n);
    Log.d(DEBUG, "Scale: " + n[Matrix.MSCALE_X] + " TransX: " + n[Matrix.MTRANS_X] + " TransY: "
        + n[Matrix.MTRANS_Y]);
  }
}

================================================
FILE: PhotoPicker/src/main/res/anim/dialog_enter.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:ignore="ResourceName">

    <translate
        android:fromYDelta="100%p"
        android:duration="400"
        />
</set>

================================================
FILE: PhotoPicker/src/main/res/anim/dialog_exit.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    tools:ignore="ResourceName">
    <translate
        android:toYDelta="100%p"
        android:duration="400"
        />
</set>

================================================
FILE: PhotoPicker/src/main/res/drawable/__picker_bg_material_item.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/__picker_common_primary" android:state_pressed="true" />
    <item android:drawable="@android:color/white" />
</selector>

================================================
FILE: PhotoPicker/src/main/res/drawable/__picker_camera.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:state_pressed="true" android:drawable="@drawable/__picker_ic_camera_p" />
  <item android:drawable="@drawable/__picker_ic_camera_n" />

</selector>

================================================
FILE: PhotoPicker/src/main/res/drawable/__picker_checkbox_bg.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:state_selected="true">
    <layer-list>
      <item>
        <!--仿微信效果,中间向上下渐变-->
        <shape>
          <corners android:radius="2dip"/>
          <padding android:top="-2dip"
              android:left="-2dip"
              android:bottom="-2dip"
              android:right="-2dip"/>
          <stroke android:width="1dip"
              android:color="@android:color/white"/>
        </shape>
      </item>
      <item android:drawable="@drawable/__picker_checkbox_marked"/>
    </layer-list>
  </item>

  <item>
    <layer-list>
      <item>
        <shape>
          <corners android:radius="2dip"/>
          <padding android:top="-2dip"
              android:left="-2dip"
              android:bottom="-2dip"
              android:right="-2dip"/>
          <stroke android:width="1dip"
              android:color="@android:color/white"/>
        </shape>
      </item>
      <item android:drawable="@drawable/__picker_checkbox_n"/>
    </layer-list>
  </item>

</selector>

================================================
FILE: PhotoPicker/src/main/res/drawable/__picker_default_weixin.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#cc000000"/>
    <gradient
        android:type="linear"
        android:angle="90"
        android:startColor="#3A3C39"
        android:endColor="#4D4F4C"/>

</shape>

================================================
FILE: PhotoPicker/src/main/res/drawable/__picker_delete.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

  <item android:state_pressed="true" android:drawable="@drawable/__picker_ic_delete_p" />
  <item android:drawable="@drawable/__picker_ic_delete_n" />

</selector>

================================================
FILE: PhotoPicker/src/main/res/drawable/__picker_photo_bg.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--中间蒙版层,为选中时,为中间向上下渐变,选中时,黑色半透明蒙版-->
  <item android:state_selected="true">
    <shape>

      <solid android:color="@color/__picker_item_selected_cover"/>
    </shape>
  </item>

  <item>
    <shape>
      <gradient
          android:startColor="@color/__picker_item_unselected_border"
          android:endColor="@color/__picker_item_unselected_border"
          android:centerX="0.5"
          android:centerY="0.5"
          android:centerColor="@color/__picker_item_unselected_center"
          android:angle="90"
        android:type="linear">

      </gradient>

    </shape>
  </item>


</selector>

================================================
FILE: PhotoPicker/src/main/res/drawable-v21/__picker_bg_material_item.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/__picker_common_primary"
    >
  <item android:drawable="@android:color/white"/>
</ripple>

================================================
FILE: PhotoPicker/src/main/res/layout/__picker_activity_photo_pager.xml
================================================
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/background_dark"
    xmlns:app="http://schemas.android.com/apk/res-auto"

    android:orientation="vertical"
    tools:context="${relativePackage}.${activityClass}">

  <!--<include layout="@layout/__picker_toolbar"/>-->
  <me.iwf.photopicker.widget.Titlebar
      android:id="@+id/titlebar"
      app:mtb_title="@string/__picker_title"
      android:layout_width="match_parent"
      android:layout_height="44dp"
      android:background="?attr/colorPrimary"/>

  <FrameLayout
      android:id="@+id/container"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      >

    <fragment
        android:id="@+id/photoPagerFragment"
        android:name="me.iwf.photopicker.fragment.ImagePagerFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

  </FrameLayout>

</LinearLayout>


================================================
FILE: PhotoPicker/src/main/res/layout/__picker_activity_photo_picker.xml
================================================
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">

  <!--<include layout="@layout/__picker_toolbar" />-->
  <me.iwf.photopicker.widget.Titlebar
      android:id="@+id/titlebar"
      app:mtb_title="@string/__picker_title"
      app:mtb_rightTxt="@string/__picker_done"
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:background="?attr/colorPrimary"/>

  <FrameLayout
      android:id="@+id/container"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      />

</LinearLayout>


================================================
FILE: PhotoPicker/src/main/res/layout/__picker_fragment_photo_picker.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="@android:color/black"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

  <android.support.v7.widget.RecyclerView
      android:id="@+id/rv_photos"
      android:layout_width="match_parent"
      android:gravity="center"
      android:layout_height="match_parent"
      />


  <RelativeLayout
      android:layout_alignParentBottom="true"
      android:layout_width="match_parent"
      android:background="#e54d4f4c"
      android:layout_height="wrap_content"
      >
        <Button
            android:layout_centerVertical="true"
            android:id="@+id/button"
            android:text="@string/__picker_all_image"
            android:layout_width="wrap_content"
            android:gravity="center"
            android:textColor="@android:color/white"
            android:layout_height="wrap_content"
            style="@style/Widget.AppCompat.ActionButton"
            android:drawablePadding="5dp"
            android:drawableRight="@drawable/icon_test_list_start"
            />

      <Button
          android:layout_alignParentRight="true"
          android:layout_centerVertical="true"
          style="@style/Widget.AppCompat.ActionButton"
          android:textColor="@android:color/white"
          android:id="@+id/btn_preview"
          android:textSize="14sp"
          android:text="@string/__picker_preview"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" />

  </RelativeLayout>

</RelativeLayout>

================================================
FILE: PhotoPicker/src/main/res/layout/__picker_item_directory.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:padding="10dip"
    android:background="@drawable/__picker_bg_material_item"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

  <ImageView
      android:id="@+id/iv_dir_cover"
      android:layout_width="60dip"
      android:layout_height="60dip"
      android:layout_marginRight="10dip"
      android:scaleType="centerCrop"
      />
  <LinearLayout
      android:gravity="center"
      android:orientation="vertical"
      android:layout_width="match_parent"
      android:layout_gravity="center"
      android:layout_height="wrap_content"
      >

      <TextView
          android:textColor="@color/__picker_text_40"
          android:id="@+id/tv_dir_name"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          />
      <TextView
          android:textColor="@color/__picker_text_80"
          android:id="@+id/tv_dir_count"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          />

  </LinearLayout>


</LinearLayout>


================================================
FILE: PhotoPicker/src/main/res/layout/__picker_item_photo.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<me.iwf.photopicker.widget.SquareItemLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
  <ImageView
      android:padding="1dip"
      android:layout_gravity="center"
      android:id="@+id/iv_photo"
      android:scaleType="centerCrop"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:adjustViewBounds="true"
      />
  <!--仿微信的蒙版-->
  <View
      android:id="@+id/cover"
      android:background="@drawable/__picker_photo_bg"
      android:layout_width="match_parent"
      android:layout_height="match_parent"/>

  <View
      android:visibility="gone"
      android:id="@+id/v_delete"
      android:background="@drawable/icon_delete"
      android:layout_alignParentRight="true"
      android:layout_width="15dp"
      android:layout_height="15dp"/>

  <ImageView
      android:layout_margin="5dip"
      android:layout_alignParentTop="true"
      android:layout_alignParentRight="true"
      android:clickable="true"
      android:padding="5dip"
      android:id="@+id/v_selected"
      android:src="@drawable/__picker_checkbox_bg"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      />

</me.iwf.photopicker.widget.SquareItemLayout>


================================================
FILE: PhotoPicker/src/main/res/layout/__picker_picker_fragment_image_pager.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
        android:id="@+id/vp_photos"
        android:background="@color/__picker_pager_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

================================================
FILE: PhotoPicker/src/main/res/layout/__picker_picker_item_pager.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--<ScrollView -->
    <!--android:orientation="vertical"-->
    <!--android:gravity="center"-->
    <!--android:layout_width="match_parent"-->
    <!--android:layout_height="wrap_content"-->
    <!--android:fillViewport="true"-->
    <!--&gt;-->

  <me.iwf.photopicker.widget.TouchImageView
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:gravity="center"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:src="@drawable/__picker_ic_photo_black_48dp"
      android:id="@+id/iv_pager"
      />

<!--</ScrollView>-->


================================================
FILE: PhotoPicker/src/main/res/layout/__picker_toolbar.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:gravity="center_vertical"
    android:minHeight="44dp"
    android:theme="?attr/actionBarTheme"
    app:popupTheme="?attr/actionBarPopupTheme"
    android:background="?attr/colorPrimary"
    android:id="@+id/toolbar">
    <!--#2B3230
    ?attr/colorPrimary-->
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/__picker_title"
        android:textSize="17sp"
        android:textColor="@android:color/white"
        android:layout_gravity="center"
        android:id="@+id/toolbar_title" />

    </android.support.v7.widget.Toolbar>

================================================
FILE: PhotoPicker/src/main/res/layout/view_titlebar.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:paddingRight="5dp"
                android:paddingLeft="5dp"
    android:layout_height="44dp"
    tools:ignore="ResourceName">
    <!--?attr/colorPrimary-->


    <ImageView
       android:scaleType="centerInside"
        android:id="@+id/iv_left"
        android:src="@drawable/arrow_back"
        android:layout_centerVertical="true"
        android:layout_width="48dp"
        android:layout_height="match_parent"/>

    <TextView
        android:id="@+id/tv_left"
        android:textColor="@android:color/white"
        android:text=""
        android:visibility="gone"
        android:gravity="center"
        android:layout_centerVertical="true"
        android:textSize="15sp"
        android:paddingLeft="10dp"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"/>

    <TextView
        android:id="@+id/tv_title"
        android:textColor="@android:color/white"
        android:layout_centerInParent="true"
        android:textSize="18sp"
        android:text=""
        android:gravity="center"
        android:paddingLeft="30dp"
        android:paddingRight="30dp"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"/>

    <TextView
        android:id="@+id/tv_right"
        android:textColor="@android:color/white"
        android:text=""
        android:gravity="center"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:textSize="15sp"
        android:paddingRight="10dp"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"/>

    <ImageView
        android:id="@+id/iv_right"
            android:visibility="gone"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
       android:scaleType="centerInside"
        android:layout_width="48dp"
        android:layout_height="44dp" />




</RelativeLayout>

================================================
FILE: PhotoPicker/src/main/res/menu/__picker_menu_picker.xml
================================================
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity"
    >
  <item
      android:id="@+id/done"
      android:title="@string/__picker_done"
      android:orderInCategory="100"
      app:showAsAction="ifRoom"
      />
</menu>


================================================
FILE: PhotoPicker/src/main/res/menu/__picker_menu_preview.xml
================================================
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".MainActivity"
    >
  <item
      android:id="@+id/delete"
      android:title="@string/__picker_delete"
      android:icon="@drawable/__picker_delete"
      android:orderInCategory="100"
      app:showAsAction="ifRoom"
      />
</menu>


================================================
FILE: PhotoPicker/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>

  <color name="__picker_pager_bg">#CA000000</color>
  <color name="__picker_selected_bg">#44000000</color>
  <color name="__picker_black_40">#282828</color>
  <color name="__picker_common_primary">#f3f3f3</color>

  <color name="__picker_text_40">#282828</color>
  <color name="__picker_text_80">#505050</color>
  <color name="__picker_text_120">#787878</color>
  <color name="__picker_item_photo_border_selected">#ff99cc00</color>
  <color name="__picker_item_photo_border_n">#33ffffff</color>

  <color name="__picker_item_selected_cover">#99000000</color><!--70%BU透明度-->

  <color name="__picker_item_unselected_center">#00000000</color><!--100%透明度-->
  <color name="__picker_item_unselected_border">#40000000</color><!--25%透明度-->

</resources>

================================================
FILE: PhotoPicker/src/main/res/values/dimen.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>

  <dimen name="__picker_iwf_actionBarSize">48dip</dimen>
  <dimen name="__picker_item_photo_size">80dip</dimen>
  <dimen name="__picker_item_camera_size">80dip</dimen>
  <dimen name="__picker_item_directory_height">80dp</dimen>

</resources>


================================================
FILE: PhotoPicker/src/main/res/values/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="__picker_title">Images</string>
  <string name="__picker_delete">Delete</string>
  <string name="__picker_done">Done</string>
  <string name="__picker_done_with_count">Done(%1$d/%2$d)</string>
  <string name="__picker_image_index">%1$d/%2$d</string>
  <string name="__picker_undo">Undo</string>
  <string name="__picker_deleted_a_photo">Deleted a photo</string>
  <string name="__picker_confirm_to_delete">Confirm to delete?</string>
  <string name="__picker_yes">Yes</string>
  <string name="__picker_cancel">Cancel</string>
  <string name="__picker_all_image">All Images</string>
  <string name="__picker_over_max_count_tips">Up to %1$d photos can be selected</string>
  <string name="__picker_image_count">%1$d</string>

  <string name="__picker_preview">preview</string>

</resources>


================================================
FILE: PhotoPicker/src/main/res/values/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <style name="__picker_AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:colorPrimary" tools:targetApi="lollipop">#5677fc</item>
        <item name="android:colorPrimaryDark" tools:targetApi="lollipop">#3b50ce</item>
    </style>
    <style name="__picker_mystyle" parent="android:Animation">
        <item name="@android:windowEnterAnimation">@anim/dialog_enter</item>  //进入时的动画
        <item name="@android:windowExitAnimation">@anim/dialog_exit</item>    //退出时的动画
    </style>

</resources>

================================================
FILE: PhotoPicker/src/main/res/values/values.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <declare-styleable name="MyTitlebar" tools:ignore="ResourceName">
        <attr name="mtb_leftTxt" format="string" />
        <attr name="mtb_left_icon" format="reference"/>
        <attr name="mtb_title" format="string" />
        <attr name="mtb_rightTxt" format="string" />
        <attr name="mtb_right_icon" format="reference"/>
    </declare-styleable>
</resources>

================================================
FILE: PhotoPicker/src/main/res/values-pt/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="__picker_title">Imagens</string>
  <string name="__picker_delete">Deletar</string>
  <string name="__picker_done">@android:string/ok</string>
  <string name="__picker_done_with_count">Ok(%1$d/%2$d)</string>
  <string name="__picker_image_index">%1$d/%2$d</string>
  <string name="__picker_undo">Desfazer</string>
  <string name="__picker_deleted_a_photo">Feletar uma imagem</string>
  <string name="__picker_confirm_to_delete">Deseja deletar?</string>
  <string name="__picker_yes">Sim</string>
  <string name="__picker_cancel">Cancelar</string>
  <string name="__picker_all_image">Todas as images</string>
  <string name="__picker_over_max_count_tips">Apenas %1$d imagens podem ser selecionadas</string>
  <string name="__picker_image_count">%1$d</string>

</resources>


================================================
FILE: PhotoPicker/src/main/res/values-v21/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="__picker_common_primary">#e1e1e1</color>
</resources>

================================================
FILE: PhotoPicker/src/main/res/values-zh/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>

  <string name="__picker_title">图片选择</string>
  <string name="__picker_delete">删除</string>
  <string name="__picker_done">完成</string>
  <string name="__picker_done_with_count">完成(%1$d/%2$d)</string>
  <string name="__picker_image_index">%1$d/%2$d</string>
  <string name="__picker_undo">撤消</string>
  <string name="__picker_deleted_a_photo">删除了一张图片</string>
  <string name="__picker_confirm_to_delete">确认删除?</string>
  <string name="__picker_yes">确定</string>
  <string name="__picker_cancel">取消</string>
  <string name="__picker_all_image">所有图片</string>
  <string name="__picker_over_max_count_tips">你最多可以选择%1$d张图片</string>
  <string name="__picker_image_count">%1$d张</string>

  <string name="__picker_preview">预览</string>


</resources>


================================================
FILE: README.md
================================================

# 微信ui版的PhotoPicker
# 注: 此项目已转移至本人主账号下:在那里继续更新
[主账号下的PhotoPicker](https://github.com/hss01248/PhotoPicker)


[![](https://jitpack.io/v/glassLake/PhotoPicker.svg)](https://jitpack.io/#glassLake/PhotoPicker)
## 注: 图片选择/拍照->裁剪->压缩 整个流程的操作已经串起到下面的库中
[PhotoOut](https://github.com/hss01248/PhotoOut)


本项目fork 自[photoPicker](https://github.com/donglua/PhotoPicker)

参考微信的图片选择ui,对原项目photoPicker进行改写。

标题栏:去除难用的toolbar,改成自定义的titlebar。高度44dp,标题居中,颜色引用activity主题设置colorPrimary.可以自己设置.

底部弹出框:原项目两边有间距,现改成铺满屏幕宽度弹出

默认图片更改成黑灰色背景,让滑动时图片闪动不会那么突兀

图片item再加一层蒙版,未选择状态时,由中间向上下浅黑透明渐变,选择状态下,颜色变黑。

选择框: 未选状态下由原来的不透明变成透明,选中状态时图标颜色使用微信的绿色。



demo apk:见项目根目录下demo.apk


# 更新:

1.0.1: 
将图片选择后显示的组件封装了一下,提供了最简化使用的api
该组件既可以用于图片选择后的显示,也可以用于单纯的多图显示,只要设置类型就行



1.0.2

单纯显示图片时,由原来的4列改成3列

修复图片预览时删到最后一张时的数组角标越界bug



---

# 效果图
 ![all](all.jpg)




文件夹切换:底部弹窗



 ![popwin](popwin.jpg)





图片预览:

 ![preview](preview.jpg)



封装好的图片显示组件:(上方是图片选择,下面是只显示图片的组件)

 ![multview](multview.png)



---

# Usage

### gradle

Add it in your root build.gradle at the end of repositories:

	allprojects {
		repositories {
			...
			maven { url "https://jitpack.io" }
		}
	}
Step 2. Add the dependency

	dependencies {
	        compile 'com.github.glassLake:PhotoPicker:1.0.3'
	}



## 使用完全封装好的组件



xml:

```
<me.iwf.photopicker.widget.MultiPickResultView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/recycler_view"/>
```

选择图片并显示图片:

```
recyclerView = (MultiPickResultView) findViewById(R.id.recycler_view);
recyclerView.init(this,MultiPickResultView.ACTION_SELECT,null);

//onActivityResult里一行代码回调
 recyclerView.onActivityResult(requestCode,resultCode,data);
```



只显示图片

```
//可以初始化时传入地址
recyclerViewShowOnly.init(this,MultiPickResultView.ACTION_ONLY_SHOW,pathslook);

//也可以后续设置地址:
 recyclerViewShowOnly.showPics(pathslook);
```



## 不使用显示组件,只使用选择图片的功能

### Pick Photo

```java
PhotoPickUtils.startPick(Activity context,boolean showGif,int photoCount,ArrayList<String> photos)
```

### 

### onActivityResult
```java
 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    PhotoPickUtils.onActivityResult(requestCode, resultCode, data, new 		PhotoPickUtils.PickHandler() {
      @Override
      public void onPickSuccess(ArrayList<String> photos) {//已经预先做了null或size为0的判断
       
      }

      @Override
      public void onPickFail(String error) {
        Toast.makeText(MainActivity.this,error,Toast.LENGTH_LONG).show();
      }

      @Override
      public void onCancle() {
        Toast.makeText(MainActivity.this,"取消选择",Toast.LENGTH_LONG).show();
      }
    });
```

### manifest
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    >
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  <application
    ...
    >
    ...
    
    <activity android:name="me.iwf.photopicker.PhotoPickerActivity"
      android:theme="@style/customTheme" 
       />

    <activity android:name="me.iwf.photopicker.PhotoPagerActivity"
      android:theme="@style/customTheme"/>
    
  </application>
</manifest>
```
### Custom style
```xml
<style name="customTheme" parent="Theme.AppCompat.Light.NoActionBar">
  <item name="colorPrimary">#FFA500</item>//标题栏背景色
  <item name="colorPrimaryDark">#CCa500</item>
</style>
```





## Proguard

```
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
}
# nineoldandroids
-keep interface com.nineoldandroids.view.** { *; }
-dontwarn com.nineoldandroids.**
-keep class com.nineoldandroids.** { *; }
# support-v7-appcompat
-keep public class android.support.v7.widget.** { *; }
-keep public class android.support.v7.internal.widget.** { *; }
-keep public class android.support.v7.internal.view.menu.** { *; }
-keep public class * extends android.support.v4.view.ActionProvider {
    public <init>(android.content.Context);
}
# support-design
-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }
```

---

# Thanks 

[Photopicker](https://github.com/donglua/PhotoPicker)



================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'

        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = "2.13"
}

================================================
FILE: circle.sh
================================================
#!/bin/bash

# Fix the CircleCI path
function getAndroidSDK(){
  export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$PATH"

  DEPS="$ANDROID_HOME/installed-dependencies"

  if [ ! -e $DEPS ]; then
    cp -r /usr/local/android-sdk-linux $ANDROID_HOME &&
    echo y | android update sdk -u -a -t android-23 &&
    echo y | android update sdk -u -a -t platform-tools &&
    echo y | android update sdk -u -a -t build-tools-23.0.3 &&
    touch $DEPS
  fi
}


================================================
FILE: circle.yml
================================================
# Build configuration file for Circle CI
# needs to be named `circle.yml` and should be in the top level dir of the repo

machine:
  environment:
    ANDROID_HOME: /home/ubuntu/android
  java:
    version: oraclejdk8

dependencies:
  pre:
    - ( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --no-ui --all --filter "tools,platform-tools,android-23,extra-google-m2repository,extra-android-m2repository,extra-android-support"
    - echo y | android update sdk --no-ui --all --filter "build-tools-23.0.3"
  cache_directories:
    - ~/.android
    - ~/android
  override:
    - (echo "Downloading Android SDK v23 now!")
    - (source circle.sh && getAndroidSDK)

test:
  pre:
    - (./gradlew build)


================================================
FILE: gradle/gradle-mvn-push.gradle
================================================

apply plugin: 'com.jfrog.bintray'

version = "0.8.5"
def siteUrl = 'https://github.com/donglua/PhotoPicker'      // Homepage URL of the library
def gitUrl  = 'https://github.com/donglua/PhotoPicker.git'  // Git repository URL
group = "me.iwf.photopicker"                                // Maven Group ID for the artifact

task sourcesJar(type: Jar) {
    from android.sourceSets.main.java.srcDirs
    classifier = 'sources'
}

task javadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}
tasks.withType(JavaCompile) { options.encoding = "UTF-8" }

artifacts {
    //  archives javadocJar
    archives sourcesJar
}

def localProperties = project.rootProject.file('local.properties')

Properties properties = new Properties()

if (localProperties.exists()) {
    def stream = localProperties.newDataInputStream()
    properties.load(stream)
}

bintray {
    user = properties.getProperty("bintray.user")
    key = properties.getProperty("bintray.apikey")
    publish = true
    configurations = ['archives']
    pkg {
        repo = "maven"
        name = "PhotoPicker"
        websiteUrl = siteUrl
        vcsUrl = gitUrl
        licenses = ["Apache-2.0"]
        publish = true
    }
}


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Thu Feb 16 09:56:02 CST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip


================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 org.gradle.parallel=true

================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
  NONSTOP* )
    nonstop=true
    ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: photopickerdemo/.gitignore
================================================
/photopickerdemo.iml
/build


================================================
FILE: photopickerdemo/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "me.iwf.PhotoPickerDemo"
        minSdkVersion 11
        targetSdkVersion 23
        versionCode 12
        versionName "0.8.4"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':PhotoPicker')

//    compile 'me.iwf.photopicker:PhotoPicker:0.8.4@aar'

//    compile 'com.android.support:appcompat-v7:23.4.0'
//    compile 'com.android.support:recyclerview-v7:23.4.0'
//    compile 'com.android.support:design:23.4.0'
//    compile 'com.nineoldandroids:library:2.4.0'
//    compile 'com.github.bumptech.glide:glide:3.7.0'
}


================================================
FILE: photopickerdemo/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.0.2/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
}
# nineoldandroids
-keep interface com.nineoldandroids.view.** { *; }
-dontwarn com.nineoldandroids.**
-keep class com.nineoldandroids.** { *; }
# support-v7-appcompat
-keep public class android.support.v7.widget.** { *; }
-keep public class android.support.v7.internal.widget.** { *; }
-keep public class android.support.v7.internal.view.menu.** { *; }
-keep public class * extends android.support.v4.view.ActionProvider {
    public <init>(android.content.Context);
}
# support-design
-dontwarn android.support.design.**
-keep class android.support.design.** { *; }
-keep interface android.support.design.** { *; }
-keep public class android.support.design.R$* { *; }

================================================
FILE: photopickerdemo/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="me.iwf.PhotoPickerDemo"
    >
    <permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.CAMERA" />

    <!--
      - Include all the "features" under the camera permission,
      - and mark them all as optional.
      -->
    <uses-feature
        android:name="android.hardware.camera"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.camera.autofocus"
        android:required="false" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        >
        <activity
            android:name="me.iwf.PhotoPickerDemo.MainActivity"
            android:label="@string/app_name"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>


        <activity
            android:theme="@style/customTheme"
            android:name="me.iwf.photopicker.PhotoPickerActivity"
            />

        <activity
            android:theme="@style/customTheme"
            android:name="me.iwf.photopicker.PhotoPagerActivity"
            />

    </application>

</manifest>


================================================
FILE: photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/MainActivity.java
================================================
package me.iwf.PhotoPickerDemo;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;

import me.iwf.photopicker.PhotoPickUtils;
import me.iwf.photopicker.PhotoPicker;
import me.iwf.photopicker.widget.MultiPickResultView;

public class MainActivity extends AppCompatActivity {

  enum RequestCode {
    Button(R.id.button),
    ButtonNoCamera(R.id.button_no_camera),
    ButtonOnePhoto(R.id.button_one_photo),
    ButtonPhotoGif(R.id.button_photo_gif),
    ButtonMultiplePicked(R.id.button_multiple_picked);

    @IdRes final int mViewId;
    RequestCode(@IdRes int viewId) {
      mViewId = viewId;
    }
  }
  MultiPickResultView recyclerView;

  MultiPickResultView recyclerViewShowOnly;
 /* PhotoAdapter photoAdapter;

  ArrayList<String> selectedPhotos = new ArrayList<>();*/

  //public final static int REQUEST_CODE = 1;

  ArrayList<String> pathslook ;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    pathslook = new ArrayList<>();

    recyclerView = (MultiPickResultView) findViewById(R.id.recycler_view);
    recyclerView.init(this,MultiPickResultView.ACTION_SELECT,null);

    recyclerViewShowOnly = (MultiPickResultView) findViewById(R.id.recycler_onlylook);
    recyclerViewShowOnly.init(this,MultiPickResultView.ACTION_ONLY_SHOW,pathslook);
    ArrayList<String> photos = new ArrayList<>();
    photos.add("https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2545179197,2573899739&fm=21&gp=0.jpg");
    photos.add("https://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1471325032244&di=71570ed352a1b823584c3b3b1b5bd57f&imgtype=jpg&src=http%3A%2F%2Ffile27.mafengwo.net%2FM00%2FB2%2F12%2FwKgB6lO0ahWAMhL8AAV1yBFJDJw20.jpeg");
    photos.add("https://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1471325032243&di=67dfaed98491c3a94965571ed4343951&imgtype=jpg&src=http%3A%2F%2Fwww.5068.com%2Fu%2Ffaceimg%2F20140725173411.jpg");
    photos.add("https://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1471325032243&di=d40f796d46782144ba0adf798253f080&imgtype=jpg&src=http%3A%2F%2Fimglf0.ph.126.net%2F1EnYPI5Vzo2fCkyy2GsJKg%3D%3D%2F2829667940890114965.jpg");
    photos.add("https://timgsa.baidu.com/timg?image&quality=80&size=b10000_10000&sec=1471325032243&di=bbb10b09ddb5338b53432af1c3789c39&imgtype=jpg&src=http%3A%2F%2Ffile25.mafengwo.net%2FM00%2F0A%2FAA%2FwKgB4lMC256AYLqGAAGklurKzyM52.rbook_comment.w1024.jpeg");


  /*  photoAdapter = new PhotoAdapter(this, selectedPhotos);

    recyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, OrientationHelper.VERTICAL));
    recyclerView.setAdapter(photoAdapter);*/


    findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        checkPermission(RequestCode.Button);
      }
    });


    findViewById(R.id.button_no_camera).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        checkPermission(RequestCode.ButtonNoCamera);
      }
    });

    findViewById(R.id.button_one_photo).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        checkPermission(RequestCode.ButtonOnePhoto);
      }
    });

    findViewById(R.id.button_photo_gif).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        checkPermission(RequestCode.ButtonPhotoGif);
      }
    });

    findViewById(R.id.button_multiple_picked).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        checkPermission(RequestCode.ButtonMultiplePicked);
      }

    });

   /* recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, new OnItemClickListener() {
      @Override public void onItemClick(View view, int position) {


        PhotoPreview.builder()
            .setPhotos(selectedPhotos)
            .setCurrentItem(position)
            .start(MainActivity.this);
      }
    }));*/
  }

  @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onAc
Download .txt
gitextract_jrq830pw/

├── .gitattributes
├── .gitignore
├── .travis.yml
├── LICENSE
├── PhotoPicker/
│   ├── .gitignore
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── me/
│           │       └── iwf/
│           │           └── photopicker/
│           │               ├── PhotoPagerActivity.java
│           │               ├── PhotoPickUtils.java
│           │               ├── PhotoPicker.java
│           │               ├── PhotoPickerActivity.java
│           │               ├── PhotoPreview.java
│           │               ├── adapter/
│           │               │   ├── PhotoGridAdapter.java
│           │               │   ├── PhotoPagerAdapter.java
│           │               │   ├── PopupDirectoryListAdapter.java
│           │               │   └── SelectableAdapter.java
│           │               ├── entity/
│           │               │   ├── Photo.java
│           │               │   └── PhotoDirectory.java
│           │               ├── event/
│           │               │   ├── OnItemCheckListener.java
│           │               │   ├── OnPhotoClickListener.java
│           │               │   └── Selectable.java
│           │               ├── fragment/
│           │               │   ├── ImagePagerFragment.java
│           │               │   └── PhotoPickerFragment.java
│           │               ├── utils/
│           │               │   ├── ExifUtils.java
│           │               │   ├── ImageCaptureManager.java
│           │               │   ├── MediaStoreHelper.java
│           │               │   ├── PhotoDirectoryLoader.java
│           │               │   └── PhotoPickerIntent.java
│           │               └── widget/
│           │                   ├── MultiPickResultView.java
│           │                   ├── PhotoAdapter.java
│           │                   ├── SquareItemLayout.java
│           │                   ├── Titlebar.java
│           │                   └── TouchImageView.java
│           └── res/
│               ├── anim/
│               │   ├── dialog_enter.xml
│               │   └── dialog_exit.xml
│               ├── drawable/
│               │   ├── __picker_bg_material_item.xml
│               │   ├── __picker_camera.xml
│               │   ├── __picker_checkbox_bg.xml
│               │   ├── __picker_default_weixin.xml
│               │   ├── __picker_delete.xml
│               │   └── __picker_photo_bg.xml
│               ├── drawable-v21/
│               │   └── __picker_bg_material_item.xml
│               ├── layout/
│               │   ├── __picker_activity_photo_pager.xml
│               │   ├── __picker_activity_photo_picker.xml
│               │   ├── __picker_fragment_photo_picker.xml
│               │   ├── __picker_item_directory.xml
│               │   ├── __picker_item_photo.xml
│               │   ├── __picker_picker_fragment_image_pager.xml
│               │   ├── __picker_picker_item_pager.xml
│               │   ├── __picker_toolbar.xml
│               │   └── view_titlebar.xml
│               ├── menu/
│               │   ├── __picker_menu_picker.xml
│               │   └── __picker_menu_preview.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimen.xml
│               │   ├── strings.xml
│               │   ├── styles.xml
│               │   └── values.xml
│               ├── values-pt/
│               │   └── strings.xml
│               ├── values-v21/
│               │   └── colors.xml
│               └── values-zh/
│                   └── strings.xml
├── PhotoPicker-release.aar
├── README.md
├── build.gradle
├── circle.sh
├── circle.yml
├── demo.apk
├── gradle/
│   ├── gradle-mvn-push.gradle
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── photopickerdemo/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── me/
│           │       └── iwf/
│           │           └── PhotoPickerDemo/
│           │               ├── MainActivity.java
│           │               ├── PicChosenListInterface.java
│           │               └── RecyclerItemClickListener.java
│           └── res/
│               ├── layout/
│               │   └── activity_main.xml
│               ├── values/
│               │   ├── color.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               └── values-zh/
│                   └── strings.xml
└── settings.gradle
Download .txt
SYMBOL INDEX (333 symbols across 29 files)

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPagerActivity.java
  class PhotoPagerActivity (line 34) | public class PhotoPagerActivity extends AppCompatActivity {
    method onCreate (line 42) | @Override protected void onCreate(Bundle savedInstanceState) {
    method centerActionBarTitle (line 109) | public static void centerActionBarTitle(Activity activity)
    method onCreateOptionsMenu (line 123) | @Override public boolean onCreateOptionsMenu(Menu menu) {
    method onBackPressed (line 131) | @Override public void onBackPressed() {
    method onOptionsItemSelected (line 142) | @Override

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPickUtils.java
  class PhotoPickUtils (line 11) | public class PhotoPickUtils {
    method onActivityResult (line 13) | public static void onActivityResult(int requestCode, int resultCode, I...
    method startPick (line 51) | public static void startPick(Activity context,boolean showGif,int phot...
    type PickHandler (line 63) | public interface  PickHandler{
      method onPickSuccess (line 64) | void onPickSuccess(ArrayList<String> photos);
      method onPreviewBack (line 65) | void onPreviewBack(ArrayList<String> photos);
      method onPickFail (line 66) | void onPickFail(String error);
      method onPickCancle (line 67) | void onPickCancle();

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPicker.java
  class PhotoPicker (line 14) | public class PhotoPicker {
    method builder (line 30) | public static PhotoPickerBuilder builder() {
    class PhotoPickerBuilder (line 34) | public static class PhotoPickerBuilder {
      method PhotoPickerBuilder (line 38) | public PhotoPickerBuilder() {
      method start (line 49) | public void start(@NonNull Activity activity, int requestCode) {
      method start (line 59) | public void start(@NonNull Context context, @NonNull android.support...
      method start (line 68) | public void start(@NonNull Context context, @NonNull android.support...
      method getIntent (line 77) | public Intent getIntent(@NonNull Context context) {
      method start (line 88) | public void start(@NonNull Activity activity) {
      method setPhotoCount (line 92) | public PhotoPickerBuilder setPhotoCount(int photoCount) {
      method setGridColumnCount (line 97) | public PhotoPickerBuilder setGridColumnCount(int columnCount) {
      method setShowGif (line 102) | public PhotoPickerBuilder setShowGif(boolean showGif) {
      method setShowCamera (line 107) | public PhotoPickerBuilder setShowCamera(boolean showCamera) {
      method setSelected (line 112) | public PhotoPickerBuilder setSelected(ArrayList<String> imagesUri) {
      method setPreviewEnabled (line 117) | public PhotoPickerBuilder setPreviewEnabled(boolean previewEnabled) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPickerActivity.java
  class PhotoPickerActivity (line 29) | public class PhotoPickerActivity extends AppCompatActivity {
    method onCreate (line 47) | @Override protected void onCreate(Bundle savedInstanceState) {
    method onBackPressed (line 149) | @Override public void onBackPressed() {
    method addImagePagerFragment (line 164) | public void addImagePagerFragment(ImagePagerFragment imagePagerFragmen...
    method getActivity (line 211) | public PhotoPickerActivity getActivity() {
    method isShowGif (line 215) | public boolean isShowGif() {
    method setShowGif (line 219) | public void setShowGif(boolean showGif) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPreview.java
  class PhotoPreview (line 14) | public class PhotoPreview {
    method builder (line 25) | public static PhotoPreviewBuilder builder() {
    class PhotoPreviewBuilder (line 30) | public static class PhotoPreviewBuilder {
      method PhotoPreviewBuilder (line 34) | public PhotoPreviewBuilder() {
      method start (line 45) | public void start(@NonNull Activity activity, int requestCode) {
      method start (line 55) | public void start(@NonNull Context context, @NonNull android.support...
      method start (line 64) | public void start(@NonNull Context context, @NonNull android.support...
      method start (line 73) | public void start(@NonNull Activity activity) {
      method getIntent (line 82) | public Intent getIntent(@NonNull Context context) {
      method setPhotos (line 88) | public PhotoPreviewBuilder setPhotos(ArrayList<String> photoPaths) {
      method setAction (line 93) | public PhotoPreviewBuilder setAction(int action) {
      method setCurrentItem (line 98) | public PhotoPreviewBuilder setCurrentItem(int currentItem) {
      method setShowDeleteButton (line 103) | public PhotoPreviewBuilder setShowDeleteButton(boolean showDeleteBut...

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoGridAdapter.java
  class PhotoGridAdapter (line 26) | public class PhotoGridAdapter extends SelectableAdapter<PhotoGridAdapter...
    method PhotoGridAdapter (line 46) | public PhotoGridAdapter(Context context, RequestManager requestManager...
    method PhotoGridAdapter (line 53) | public PhotoGridAdapter(Context context, RequestManager requestManager...
    method setOriginalPhotos (line 59) | private void setOriginalPhotos(ArrayList<String> originalPhotos){
    method setColumnNumber (line 63) | private void setColumnNumber(Context context, int columnNumber) {
    method getItemViewType (line 72) | @Override public int getItemViewType(int position) {
    method onCreateViewHolder (line 77) | @Override public PhotoViewHolder onCreateViewHolder(ViewGroup parent, ...
    method onBindViewHolder (line 96) | @Override public void onBindViewHolder(final PhotoViewHolder holder, i...
    method getItemCount (line 158) | @Override public int getItemCount() {
    class PhotoViewHolder (line 168) | public static class PhotoViewHolder extends RecyclerView.ViewHolder {
      method PhotoViewHolder (line 173) | public PhotoViewHolder(View itemView) {
    method setOnItemCheckListener (line 182) | public void setOnItemCheckListener(OnItemCheckListener onItemCheckList...
    method setOnPhotoClickListener (line 187) | public void setOnPhotoClickListener(OnPhotoClickListener onPhotoClickL...
    method setOnCameraClickListener (line 192) | public void setOnCameraClickListener(View.OnClickListener onCameraClic...
    method getSelectedPhotoPaths (line 197) | public ArrayList<String> getSelectedPhotoPaths() {
    method setShowCamera (line 208) | public void setShowCamera(boolean hasCamera) {
    method setPreviewEnable (line 212) | public void setPreviewEnable(boolean previewEnable) {
    method showCamera (line 216) | public boolean showCamera() {
    method onViewRecycled (line 220) | @Override public void onViewRecycled(PhotoViewHolder holder) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoPagerAdapter.java
  class PhotoPagerAdapter (line 21) | public class PhotoPagerAdapter extends PagerAdapter {
    method PhotoPagerAdapter (line 26) | public PhotoPagerAdapter(RequestManager glide, List<String> paths) {
    method instantiateItem (line 31) | @Override public Object instantiateItem(ViewGroup container, int posit...
    method getCount (line 70) | @Override public int getCount() {
    method isViewFromObject (line 75) | @Override public boolean isViewFromObject(View view, Object object) {
    method destroyItem (line 80) | @Override
    method getItemPosition (line 86) | @Override

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PopupDirectoryListAdapter.java
  class PopupDirectoryListAdapter (line 18) | public class PopupDirectoryListAdapter extends BaseAdapter {
    method PopupDirectoryListAdapter (line 24) | public PopupDirectoryListAdapter(RequestManager glide, List<PhotoDirec...
    method getCount (line 30) | @Override public int getCount() {
    method getItem (line 35) | @Override public PhotoDirectory getItem(int position) {
    method getItemId (line 40) | @Override public long getItemId(int position) {
    method getView (line 45) | @Override public View getView(int position, View convertView, ViewGrou...
    class ViewHolder (line 61) | private class ViewHolder {
      method ViewHolder (line 67) | public ViewHolder(View rootView) {
      method bindData (line 73) | public void bindData(PhotoDirectory directory) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/adapter/SelectableAdapter.java
  class SelectableAdapter (line 12) | public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder>
    method SelectableAdapter (line 25) | public SelectableAdapter() {
    method isSelected (line 37) | @Override public boolean isSelected(Photo photo) {
    method toggleSelection (line 50) | @Override public void toggleSelection(Photo photo) {
    method clearSelection (line 65) | @Override public void clearSelection() {
    method getSelectedItemCount (line 75) | @Override public int getSelectedItemCount() {
    method setCurrentDirectoryIndex (line 80) | public void setCurrentDirectoryIndex(int currentDirectoryIndex) {
    method getCurrentPhotos (line 85) | public List<Photo> getCurrentPhotos() {
    method getCurrentPhotoPaths (line 90) | public List<String> getCurrentPhotoPaths() {
    method getSelectedPhotos (line 99) | public List<Photo> getSelectedPhotos() {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/entity/Photo.java
  class Photo (line 6) | public class Photo {
    method Photo (line 11) | public Photo(int id, String path) {
    method Photo (line 16) | public Photo() {
    method equals (line 19) | @Override public boolean equals(Object o) {
    method hashCode (line 28) | @Override public int hashCode() {
    method getPath (line 32) | public String getPath() {
    method setPath (line 36) | public void setPath(String path) {
    method getId (line 40) | public int getId() {
    method setId (line 44) | public void setId(int id) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/entity/PhotoDirectory.java
  class PhotoDirectory (line 11) | public class PhotoDirectory {
    method equals (line 19) | @Override public boolean equals(Object o) {
    method hashCode (line 39) | @Override public int hashCode() {
    method getId (line 58) | public String getId() {
    method setId (line 62) | public void setId(String id) {
    method getCoverPath (line 66) | public String getCoverPath() {
    method setCoverPath (line 70) | public void setCoverPath(String coverPath) {
    method getName (line 74) | public String getName() {
    method setName (line 78) | public void setName(String name) {
    method getDateAdded (line 82) | public long getDateAdded() {
    method setDateAdded (line 86) | public void setDateAdded(long dateAdded) {
    method getPhotos (line 90) | public List<Photo> getPhotos() {
    method setPhotos (line 94) | public void setPhotos(List<Photo> photos) {
    method getPhotoPaths (line 98) | public List<String> getPhotoPaths() {
    method addPhoto (line 106) | public void addPhoto(int id, String path) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/event/OnItemCheckListener.java
  type OnItemCheckListener (line 8) | public interface OnItemCheckListener {
    method OnItemCheck (line 18) | boolean OnItemCheck(int position, Photo path, boolean isCheck, int sel...

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/event/OnPhotoClickListener.java
  type OnPhotoClickListener (line 16) | public interface OnPhotoClickListener {
    method onClick (line 18) | void onClick(View v, int position, boolean showCamera);

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/event/Selectable.java
  type Selectable (line 8) | public interface Selectable {
    method isSelected (line 17) | boolean isSelected(Photo photo);
    method toggleSelection (line 24) | void toggleSelection(Photo photo);
    method clearSelection (line 29) | void clearSelection();
    method getSelectedItemCount (line 36) | int getSelectedItemCount();

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/fragment/ImagePagerFragment.java
  class ImagePagerFragment (line 29) | public class ImagePagerFragment extends Fragment {
    method newInstance (line 58) | public static ImagePagerFragment newInstance(List<String> paths, int c...
    method newInstance (line 73) | public static ImagePagerFragment newInstance(List<String> paths, int c...
    method setPhotos (line 87) | public void setPhotos(List<String> paths, int currentItem) {
    method onCreate (line 97) | @Override public void onCreate(Bundle savedInstanceState) {
    method onCreateView (line 124) | @Nullable @Override public View onCreateView(LayoutInflater inflater, ...
    method runEnterAnimation (line 184) | private void runEnterAnimation() {
    method runExitAnimation (line 229) | public void runExitAnimation(final Runnable endAction) {
    method setSaturation (line 277) | public void setSaturation(float value) {
    method getViewPager (line 284) | public ViewPager getViewPager() {
    method getPaths (line 289) | public ArrayList<String> getPaths() {
    method getCurrentItem (line 294) | public int getCurrentItem() {
    method onDestroy (line 298) | @Override public void onDestroy() {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/fragment/PhotoPickerFragment.java
  class PhotoPickerFragment (line 52) | public class PhotoPickerFragment extends Fragment {
    method newInstance (line 78) | public static PhotoPickerFragment newInstance(boolean showCamera, bool...
    method onAttach (line 92) | @Override public void onAttach(Context context) {
    method onCreate (line 97) | @Override public void onCreate(Bundle savedInstanceState) {
    method onCreateView (line 134) | @Override public View onCreateView(LayoutInflater inflater, ViewGroup ...
    method onActivityResult (line 262) | @Override public void onActivityResult(int requestCode, int resultCode...
    method getPhotoGridAdapter (line 276) | public PhotoGridAdapter getPhotoGridAdapter() {
    method onSaveInstanceState (line 281) | @Override public void onSaveInstanceState(Bundle outState) {
    method onViewStateRestored (line 287) | @Override public void onViewStateRestored(Bundle savedInstanceState) {
    method getSelectedPhotoPaths (line 292) | public ArrayList<String> getSelectedPhotoPaths() {
    method adjustHeight (line 296) | public void adjustHeight() {
    method onDestroy (line 305) | @Override public void onDestroy() {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/ExifUtils.java
  class ExifUtils (line 10) | public class ExifUtils {
    method clearSensitiveInfo (line 12) | public static void clearSensitiveInfo(String filePath){

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/ImageCaptureManager.java
  class ImageCaptureManager (line 23) | public class ImageCaptureManager {
    method ImageCaptureManager (line 31) | public ImageCaptureManager(Context mContext) {
    method createImageFile (line 35) | private File createImageFile() throws IOException {
    method dispatchTakePictureIntent (line 61) | public Intent dispatchTakePictureIntent() throws IOException {
    method galleryAddPic (line 77) | public void galleryAddPic() {
    method getCurrentPhotoPath (line 91) | public String getCurrentPhotoPath() {
    method onSaveInstanceState (line 96) | public void onSaveInstanceState(Bundle savedInstanceState) {
    method onRestoreInstanceState (line 102) | public void onRestoreInstanceState(Bundle savedInstanceState) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/MediaStoreHelper.java
  class MediaStoreHelper (line 25) | public class MediaStoreHelper {
    method getPhotoDirs (line 30) | public static void getPhotoDirs(FragmentActivity activity, Bundle args...
    class PhotoDirLoaderCallbacks (line 35) | static class PhotoDirLoaderCallbacks implements LoaderManager.LoaderCa...
      method PhotoDirLoaderCallbacks (line 40) | public PhotoDirLoaderCallbacks(Context context, PhotosResultCallback...
      method onCreateLoader (line 45) | @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) {
      method onLoadFinished (line 49) | @Override public void onLoadFinished(Loader<Cursor> loader, Cursor d...
      method onLoaderReset (line 88) | @Override public void onLoaderReset(Loader<Cursor> loader) {
    type PhotosResultCallback (line 94) | public interface PhotosResultCallback {
      method onResultCallback (line 95) | void onResultCallback(List<PhotoDirectory> directories);

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/PhotoDirectoryLoader.java
  class PhotoDirectoryLoader (line 13) | public class PhotoDirectoryLoader extends CursorLoader {
    method PhotoDirectoryLoader (line 23) | public PhotoDirectoryLoader(Context context, boolean showGif) {
    method PhotoDirectoryLoader (line 42) | private PhotoDirectoryLoader(Context context, Uri uri, String[] projec...

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/utils/PhotoPickerIntent.java
  class PhotoPickerIntent (line 15) | @Deprecated
    method setPhotoCount (line 17) | public static void setPhotoCount(Intent intent, int photoCount) {
    method setShowCamera (line 21) | public static void setShowCamera(Intent intent, boolean showCamera) {
    method setShowGif (line 25) | public static void setShowGif(Intent intent, boolean showGif) {
    method setColumn (line 29) | public static void setColumn(Intent intent, int column) {
    method setSelected (line 38) | public static void setSelected(Intent intent, ArrayList<String> images...

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/MultiPickResultView.java
  class MultiPickResultView (line 25) | public class MultiPickResultView extends FrameLayout {
    method MultiPickResultView (line 49) | public MultiPickResultView(Context context) {
    method MultiPickResultView (line 53) | public MultiPickResultView(Context context, AttributeSet attrs) {
    method MultiPickResultView (line 57) | public MultiPickResultView(Context context, AttributeSet attrs, int de...
    method initEvent (line 64) | private void initEvent(Context context, AttributeSet attrs) {
    method initData (line 68) | private void initData(Context context, AttributeSet attrs) {
    method initView (line 72) | private void initView(Context context, AttributeSet attrs) {
    method MultiPickResultView (line 80) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    method init (line 85) | public void init(Activity context,@MultiPicAction  int action, ArrayLi...
    method showPics (line 106) | public void showPics(List<String> paths){
    method onActivityResult (line 122) | public  void onActivityResult(int requestCode, int resultCode, Intent ...
    method getPhotos (line 152) | public ArrayList<String> getPhotos() {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/PhotoAdapter.java
  class PhotoAdapter (line 26) | public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.Phot...
    method setAction (line 34) | public void setAction(@MultiPickResultView.MultiPicAction int action) {
    method PhotoAdapter (line 43) | public PhotoAdapter(Context mContext, ArrayList<String> photoPaths) {
    method add (line 51) | public void add(ArrayList<String> photoPaths){
    method refresh (line 59) | public void refresh(ArrayList<String> photoPaths){
    method onCreateViewHolder (line 68) | @Override public PhotoViewHolder onCreateViewHolder(ViewGroup parent, ...
    method dip2Px (line 73) | public  int dip2Px(int dip) {
    method onBindViewHolder (line 81) | @Override
    method getItemCount (line 179) | @Override public int getItemCount() {
    class PhotoViewHolder (line 184) | public static class PhotoViewHolder extends RecyclerView.ViewHolder {
      method PhotoViewHolder (line 189) | public PhotoViewHolder(View itemView) {

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/SquareItemLayout.java
  class SquareItemLayout (line 10) | public class SquareItemLayout extends RelativeLayout {
    method SquareItemLayout (line 11) | public SquareItemLayout(Context context, AttributeSet attrs, int defSt...
    method SquareItemLayout (line 15) | public SquareItemLayout(Context context, AttributeSet attrs) {
    method SquareItemLayout (line 19) | public SquareItemLayout(Context context) {
    method onMeasure (line 23) | @Override protected void onMeasure(int widthMeasureSpec, int heightMea...

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/Titlebar.java
  class Titlebar (line 22) | public class Titlebar extends FrameLayout {
    method getTvTitle (line 27) | public TextView getTvTitle() {
    method getIvLeft (line 31) | public ImageView getIvLeft() {
    method getTvLeft (line 35) | public TextView getTvLeft() {
    method getTvRight (line 39) | public TextView getTvRight() {
    method getIvRight (line 43) | public ImageView getIvRight() {
    method getRootView (line 47) | @Override
    method Titlebar (line 61) | public Titlebar(Context context) {
    method Titlebar (line 65) | public Titlebar(Context context, AttributeSet attrs) {
    method Titlebar (line 69) | public Titlebar(Context context, AttributeSet attrs, int defStyleAttr) {
    method init (line 76) | public void init(Activity activity){
    method initEvent (line 88) | private void initEvent(Context context, AttributeSet attrs, int defSty...
    method setLeftOnclickListener (line 103) | public void setLeftOnclickListener(OnClickListener listener){
    method setRightOnclickListener (line 112) | public void setRightOnclickListener(OnClickListener listener){
    method setTitle (line 120) | public void setTitle(String title){
    method setLeft (line 127) | public void setLeft(Drawable leftDrawable,String leftTxt,OnClickListen...
    method setRitht (line 149) | public void setRitht(Drawable rightDrawable,String rightTxt,OnClickLis...
    method initData (line 176) | private void initData(Context context, AttributeSet attrs, int defStyl...
    method initView (line 207) | private void initView(Context context) {
    method Titlebar (line 220) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)

FILE: PhotoPicker/src/main/java/me/iwf/photopicker/widget/TouchImageView.java
  class TouchImageView (line 41) | public class TouchImageView extends ImageView {
    type State (line 66) | private enum State {NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM}
    method TouchImageView (line 103) | public TouchImageView(Context context) {
    method TouchImageView (line 108) | public TouchImageView(Context context, AttributeSet attrs) {
    method TouchImageView (line 113) | public TouchImageView(Context context, AttributeSet attrs, int defStyl...
    method sharedConstructing (line 118) | private void sharedConstructing(Context context) {
    method setOnTouchListener (line 141) | @Override public void setOnTouchListener(View.OnTouchListener l) {
    method setOnTouchImageViewListener (line 145) | public void setOnTouchImageViewListener(OnTouchImageViewListener l) {
    method setOnDoubleTapListener (line 149) | public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener...
    method setImageResource (line 153) | @Override public void setImageResource(int resId) {
    method setImageBitmap (line 159) | @Override public void setImageBitmap(Bitmap bm) {
    method setImageDrawable (line 165) | @Override public void setImageDrawable(Drawable drawable) {
    method setImageURI (line 171) | @Override public void setImageURI(Uri uri) {
    method setScaleType (line 177) | @Override public void setScaleType(ScaleType type) {
    method getScaleType (line 196) | @Override public ScaleType getScaleType() {
    method isZoomed (line 205) | public boolean isZoomed() {
    method getZoomedRect (line 214) | public RectF getZoomedRect() {
    method savePreviousImageValues (line 230) | private void savePreviousImageValues() {
    method onSaveInstanceState (line 241) | @Override public Parcelable onSaveInstanceState() {
    method onRestoreInstanceState (line 255) | @Override public void onRestoreInstanceState(Parcelable state) {
    method onDraw (line 273) | @Override protected void onDraw(Canvas canvas) {
    method onConfigurationChanged (line 284) | @Override public void onConfigurationChanged(Configuration newConfig) {
    method getMaxZoom (line 294) | public float getMaxZoom() {
    method setMaxZoom (line 303) | public void setMaxZoom(float max) {
    method getMinZoom (line 313) | public float getMinZoom() {
    method getCurrentZoom (line 323) | public float getCurrentZoom() {
    method setMinZoom (line 332) | public void setMinZoom(float min) {
    method resetZoom (line 340) | public void resetZoom() {
    method setZoom (line 348) | public void setZoom(float scale) {
    method setZoom (line 358) | public void setZoom(float scale, float focusX, float focusY) {
    method setZoom (line 368) | public void setZoom(float scale, float focusX, float focusY, ScaleType...
    method setZoom (line 396) | public void setZoom(TouchImageView img) {
    method getScrollPosition (line 409) | public PointF getScrollPosition() {
    method setScrollPosition (line 427) | public void setScrollPosition(float focusX, float focusY) {
    method fixTrans (line 435) | private void fixTrans() {
    method fixScaleTrans (line 455) | private void fixScaleTrans() {
    method getFixTrans (line 468) | private float getFixTrans(float trans, float viewSize, float contentSi...
    method getFixDragTrans (line 484) | private float getFixDragTrans(float delta, float viewSize, float conte...
    method getImageWidth (line 491) | private float getImageWidth() {
    method getImageHeight (line 495) | private float getImageHeight() {
    method onMeasure (line 499) | @Override protected void onMeasure(int widthMeasureSpec, int heightMea...
    method fitImageToView (line 532) | private void fitImageToView() {
    method setViewSize (line 644) | private int setViewSize(int mode, int size, int drawableWidth) {
    method translateMatrixAfterRotate (line 679) | private void translateMatrixAfterRotate(int axis, float trans, float p...
    method setState (line 702) | private void setState(State state) {
    method canScrollHorizontallyFroyo (line 706) | public boolean canScrollHorizontallyFroyo(int direction) {
    method canScrollHorizontally (line 710) | @Override public boolean canScrollHorizontally(int direction) {
    class GestureListener (line 731) | private class GestureListener extends GestureDetector.SimpleOnGestureL...
      method onSingleTapConfirmed (line 733) | @Override public boolean onSingleTapConfirmed(MotionEvent e) {
      method onLongPress (line 740) | @Override public void onLongPress(MotionEvent e) {
      method onFling (line 744) | @Override
      method onDoubleTap (line 758) | @Override public boolean onDoubleTap(MotionEvent e) {
      method onDoubleTapEvent (line 772) | @Override public boolean onDoubleTapEvent(MotionEvent e) {
    type OnTouchImageViewListener (line 780) | public interface OnTouchImageViewListener {
      method onMove (line 781) | public void onMove();
    class PrivateOnTouchListener (line 790) | private class PrivateOnTouchListener implements OnTouchListener {
      method onTouch (line 797) | @Override public boolean onTouch(View v, MotionEvent event) {
    class ScaleListener (line 857) | private class ScaleListener extends ScaleGestureDetector.SimpleOnScale...
      method onScaleBegin (line 858) | @Override public boolean onScaleBegin(ScaleGestureDetector detector) {
      method onScale (line 863) | @Override public boolean onScale(ScaleGestureDetector detector) {
      method onScaleEnd (line 875) | @Override public void onScaleEnd(ScaleGestureDetector detector) {
    method scaleImage (line 896) | private void scaleImage(double deltaScale, float focusX, float focusY,
    class DoubleTapZoom (line 928) | private class DoubleTapZoom implements Runnable {
      method DoubleTapZoom (line 939) | DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean ...
      method run (line 956) | @Override public void run() {
      method translateImageToCenterTouchPosition (line 990) | private void translateImageToCenterTouchPosition(float t) {
      method interpolate (line 1000) | private float interpolate() {
      method calculateDeltaScale (line 1011) | private double calculateDeltaScale(float t) {
    method transformCoordTouchToBitmap (line 1028) | private PointF transformCoordTouchToBitmap(float x, float y, boolean c...
    method transformCoordBitmapToTouch (line 1053) | private PointF transformCoordBitmapToTouch(float bx, float by) {
    class Fling (line 1071) | private class Fling implements Runnable {
      method Fling (line 1076) | Fling(int velocityX, int velocityY) {
      method cancelFling (line 1104) | public void cancelFling() {
      method run (line 1111) | @Override public void run() {
    class CompatScroller (line 1141) | @TargetApi(Build.VERSION_CODES.GINGERBREAD) private class CompatScroll...
      method CompatScroller (line 1146) | public CompatScroller(Context context) {
      method fling (line 1156) | public void fling(int startX, int startY, int velocityX, int velocit...
      method forceFinished (line 1165) | public void forceFinished(boolean finished) {
      method isFinished (line 1173) | public boolean isFinished() {
      method computeScrollOffset (line 1181) | public boolean computeScrollOffset() {
      method getCurrX (line 1190) | public int getCurrX() {
      method getCurrY (line 1198) | public int getCurrY() {
    method compatPostOnAnimation (line 1207) | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void compatPostOnAn...
    class ZoomVariables (line 1215) | private class ZoomVariables {
      method ZoomVariables (line 1221) | public ZoomVariables(float scale, float focusX, float focusY, ScaleT...
    method printMatrixInfo (line 1229) | private void printMatrixInfo() {

FILE: photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/MainActivity.java
  class MainActivity (line 21) | public class MainActivity extends AppCompatActivity {
    type RequestCode (line 23) | enum RequestCode {
      method RequestCode (line 31) | RequestCode(@IdRes int viewId) {
    method onCreate (line 46) | @Override protected void onCreate(Bundle savedInstanceState) {
    method onActivityResult (line 119) | @Override protected void onActivityResult(int requestCode, int resultC...
    method onRequestPermissionsResult (line 175) | @Override
    method shouldShowRequestPermissionRationale (line 193) | @Override
    method checkPermission (line 205) | private void checkPermission(@NonNull RequestCode requestCode) {
    method onClick (line 247) | private void onClick(@IdRes int viewId) {

FILE: photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/PicChosenListInterface.java
  type PicChosenListInterface (line 10) | public interface PicChosenListInterface {
    method onActivityResult (line 14) | void onActivityResult(int requestCode, int resultCode, Intent data);
    method getPhotos (line 16) | ArrayList<String> getPhotos();

FILE: photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/RecyclerItemClickListener.java
  class RecyclerItemClickListener (line 9) | public class RecyclerItemClickListener implements RecyclerView.OnItemTou...
    type OnItemClickListener (line 12) | public interface OnItemClickListener {
      method onItemClick (line 13) | void onItemClick(View view, int position);
    method RecyclerItemClickListener (line 18) | public RecyclerItemClickListener(Context context, OnItemClickListener ...
    method onInterceptTouchEvent (line 28) | @Override
    method onTouchEvent (line 38) | @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) {
    method onRequestDisallowInterceptTouchEvent (line 41) | @Override public void onRequestDisallowInterceptTouchEvent(boolean dis...
Condensed preview — 87 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (218K chars).
[
  {
    "path": ".gitattributes",
    "chars": 67,
    "preview": "\n# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".gitignore",
    "chars": 400,
    "preview": ".idea/**\n.gradle\n/local.properties\n.DS_Store\n/build\n/captures\n\n# Built application files\n\n\n# Files for the Dalvik VM\n*.d"
  },
  {
    "path": ".travis.yml",
    "chars": 255,
    "preview": "language: android\n\nbefore_install:\n - chmod +x gradlew\n\nandroid:\n  components:\n    - tools\n    - platform-tools\n    - bu"
  },
  {
    "path": "LICENSE",
    "chars": 11343,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "PhotoPicker/.gitignore",
    "chars": 34,
    "preview": "/build\nPhotoPicker-PhotoPicker.iml"
  },
  {
    "path": "PhotoPicker/build.gradle",
    "chars": 789,
    "preview": "apply plugin: 'com.android.library'\n\nandroid {\n  compileSdkVersion 23\n  buildToolsVersion \"23.0.3\"\n  resourcePrefix \"__p"
  },
  {
    "path": "PhotoPicker/src/main/AndroidManifest.xml",
    "chars": 92,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"me.iwf.photopicker\">\n\n</manifest>\n"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPagerActivity.java",
    "chars": 7179,
    "preview": "package me.iwf.photopicker;\n\nimport android.app.Activity;\nimport android.content.DialogInterface;\nimport android.content"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPickUtils.java",
    "chars": 2223,
    "preview": "package me.iwf.photopicker;\n\nimport android.app.Activity;\nimport android.content.Intent;\n\nimport java.util.ArrayList;\n\n/"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPicker.java",
    "chars": 3872,
    "preview": "package me.iwf.photopicker;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPickerActivity.java",
    "chars": 7264,
    "preview": "package me.iwf.photopicker;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppC"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/PhotoPreview.java",
    "chars": 3205,
    "preview": "package me.iwf.photopicker;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoGridAdapter.java",
    "chars": 6960,
    "preview": "package me.iwf.photopicker.adapter;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimpo"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PhotoPagerAdapter.java",
    "chars": 2359,
    "preview": "package me.iwf.photopicker.adapter;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.net.Uri"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/adapter/PopupDirectoryListAdapter.java",
    "chars": 2301,
    "preview": "package me.iwf.photopicker.adapter;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.V"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/adapter/SelectableAdapter.java",
    "chars": 2632,
    "preview": "package me.iwf.photopicker.adapter;\n\nimport android.support.v7.widget.RecyclerView;\n\nimport java.util.ArrayList;\nimport "
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/entity/Photo.java",
    "chars": 702,
    "preview": "package me.iwf.photopicker.entity;\n\n/**\n * Created by donglua on 15/6/30.\n */\npublic class Photo {\n\n  private int id;\n  "
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/entity/PhotoDirectory.java",
    "chars": 2080,
    "preview": "package me.iwf.photopicker.entity;\n\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/event/OnItemCheckListener.java",
    "chars": 413,
    "preview": "package me.iwf.photopicker.event;\n\nimport me.iwf.photopicker.entity.Photo;\n\n/**\n * Created by donglua on 15/6/20.\n */\npu"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/event/OnPhotoClickListener.java",
    "chars": 602,
    "preview": "/*\n * Copyright (c) 2015. Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n * Morbi non lorem porttitor neque fe"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/event/Selectable.java",
    "chars": 756,
    "preview": "package me.iwf.photopicker.event;\n\nimport me.iwf.photopicker.entity.Photo;\n\n/**\n * Created by donglua on 15/6/30.\n */\npu"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/fragment/ImagePagerFragment.java",
    "chars": 10050,
    "preview": "package me.iwf.photopicker.fragment;\n\nimport android.graphics.ColorMatrix;\nimport android.graphics.ColorMatrixColorFilte"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/fragment/PhotoPickerFragment.java",
    "chars": 11506,
    "preview": "package me.iwf.photopicker.fragment;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.grap"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/utils/ExifUtils.java",
    "chars": 1964,
    "preview": "package me.iwf.photopicker.utils;\n\nimport android.media.ExifInterface;\n\nimport java.io.IOException;\n\n/**\n * Created by A"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/utils/ImageCaptureManager.java",
    "chars": 3265,
    "preview": "package me.iwf.photopicker.utils;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/utils/MediaStoreHelper.java",
    "chars": 3538,
    "preview": "package me.iwf.photopicker.utils;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bun"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/utils/PhotoDirectoryLoader.java",
    "chars": 1365,
    "preview": "package me.iwf.photopicker.utils;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.provider.Media"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/utils/PhotoPickerIntent.java",
    "chars": 1249,
    "preview": "package me.iwf.photopicker.utils;\n\nimport android.content.Intent;\nimport java.util.ArrayList;\n\nimport static me.iwf.phot"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/widget/MultiPickResultView.java",
    "chars": 4424,
    "preview": "package me.iwf.photopicker.widget;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.con"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/widget/PhotoAdapter.java",
    "chars": 6044,
    "preview": "package me.iwf.photopicker.widget;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.net.Uri;"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/widget/SquareItemLayout.java",
    "chars": 937,
    "preview": "package me.iwf.photopicker.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.wid"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/widget/Titlebar.java",
    "chars": 6467,
    "preview": "package me.iwf.photopicker.widget;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.con"
  },
  {
    "path": "PhotoPicker/src/main/java/me/iwf/photopicker/widget/TouchImageView.java",
    "chars": 37624,
    "preview": "/*\n * TouchImageView.java\n * By: Michael Ortiz\n * Updated By: Patrick Lackemacher\n * Updated By: Babay88\n * Updated By: "
  },
  {
    "path": "PhotoPicker/src/main/res/anim/dialog_enter.xml",
    "chars": 286,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://sch"
  },
  {
    "path": "PhotoPicker/src/main/res/anim/dialog_exit.xml",
    "chars": 283,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://sch"
  },
  {
    "path": "PhotoPicker/src/main/res/drawable/__picker_bg_material_item.xml",
    "chars": 265,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "PhotoPicker/src/main/res/drawable/__picker_camera.xml",
    "chars": 273,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <item an"
  },
  {
    "path": "PhotoPicker/src/main/res/drawable/__picker_checkbox_bg.xml",
    "chars": 1109,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <item an"
  },
  {
    "path": "PhotoPicker/src/main/res/drawable/__picker_default_weixin.xml",
    "chars": 329,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "PhotoPicker/src/main/res/drawable/__picker_delete.xml",
    "chars": 273,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n  <item an"
  },
  {
    "path": "PhotoPicker/src/main/res/drawable/__picker_photo_bg.xml",
    "chars": 717,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n<!--中间蒙版层,为"
  },
  {
    "path": "PhotoPicker/src/main/res/drawable-v21/__picker_bg_material_item.xml",
    "chars": 222,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:co"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_activity_photo_pager.xml",
    "chars": 1114,
    "preview": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/too"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_activity_photo_picker.xml",
    "chars": 797,
    "preview": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/too"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_fragment_photo_picker.xml",
    "chars": 1680,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    an"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_item_directory.xml",
    "chars": 1220,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_item_photo.xml",
    "chars": 1374,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<me.iwf.photopicker.widget.SquareItemLayout\n    xmlns:android=\"http://schemas.and"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_picker_fragment_image_pager.xml",
    "chars": 475,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_picker_item_pager.xml",
    "chars": 636,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--<ScrollView -->\n    <!--android:orientation=\"vertical\"-->\n    <!--android:gra"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/__picker_toolbar.xml",
    "chars": 892,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.Toolbar\n    xmlns:android=\"http://schemas.android.com/"
  },
  {
    "path": "PhotoPicker/src/main/res/layout/view_titlebar.xml",
    "chars": 2149,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\n    x"
  },
  {
    "path": "PhotoPicker/src/main/res/menu/__picker_menu_picker.xml",
    "chars": 378,
    "preview": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\""
  },
  {
    "path": "PhotoPicker/src/main/res/menu/__picker_menu_preview.xml",
    "chars": 429,
    "preview": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\""
  },
  {
    "path": "PhotoPicker/src/main/res/values/colors.xml",
    "chars": 799,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n  <color name=\"__picker_pager_bg\">#CA000000</color>\n  <color name=\"_"
  },
  {
    "path": "PhotoPicker/src/main/res/values/dimen.xml",
    "chars": 294,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n  <dimen name=\"__picker_iwf_actionBarSize\">48dip</dimen>\n  <dimen na"
  },
  {
    "path": "PhotoPicker/src/main/res/values/strings.xml",
    "chars": 856,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <string name=\"__picker_title\">Images</string>\n  <string name=\"__pic"
  },
  {
    "path": "PhotoPicker/src/main/res/values/styles.xml",
    "chars": 626,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <style name=\"__pic"
  },
  {
    "path": "PhotoPicker/src/main/res/values/values.xml",
    "chars": 473,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <declare-styleable"
  },
  {
    "path": "PhotoPicker/src/main/res/values-pt/strings.xml",
    "chars": 838,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n  <string name=\"__picker_title\">Imagens</string>\n  <string name=\"__pi"
  },
  {
    "path": "PhotoPicker/src/main/res/values-v21/colors.xml",
    "chars": 121,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"__picker_common_primary\">#e1e1e1</color>\n</resources"
  },
  {
    "path": "PhotoPicker/src/main/res/values-zh/strings.xml",
    "chars": 791,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n  <string name=\"__picker_title\">图片选择</string>\n  <string name=\"__pick"
  },
  {
    "path": "README.md",
    "chars": 4350,
    "preview": "\n# 微信ui版的PhotoPicker\n# 注: 此项目已转移至本人主账号下:在那里继续更新\n[主账号下的PhotoPicker](https://github.com/hss01248/PhotoPicker)\n\n\n[![](https"
  },
  {
    "path": "build.gradle",
    "chars": 433,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "circle.sh",
    "chars": 464,
    "preview": "#!/bin/bash\n\n# Fix the CircleCI path\nfunction getAndroidSDK(){\n  export PATH=\"$ANDROID_HOME/platform-tools:$ANDROID_HOME"
  },
  {
    "path": "circle.yml",
    "chars": 723,
    "preview": "# Build configuration file for Circle CI\n# needs to be named `circle.yml` and should be in the top level dir of the repo"
  },
  {
    "path": "gradle/gradle-mvn-push.gradle",
    "chars": 1403,
    "preview": "\napply plugin: 'com.jfrog.bintray'\n\nversion = \"0.8.5\"\ndef siteUrl = 'https://github.com/donglua/PhotoPicker'      // Hom"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 233,
    "preview": "#Thu Feb 16 09:56:02 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 854,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
  },
  {
    "path": "gradlew",
    "chars": 5046,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "photopickerdemo/.gitignore",
    "chars": 28,
    "preview": "/photopickerdemo.iml\n/build\n"
  },
  {
    "path": "photopickerdemo/build.gradle",
    "chars": 900,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.3\"\n\n    defaultC"
  },
  {
    "path": "photopickerdemo/proguard-rules.pro",
    "chars": 1528,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /u"
  },
  {
    "path": "photopickerdemo/src/main/AndroidManifest.xml",
    "chars": 1639,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/MainActivity.java",
    "chars": 11150,
    "preview": "package me.iwf.PhotoPickerDemo;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.content.pm.Packa"
  },
  {
    "path": "photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/PicChosenListInterface.java",
    "chars": 306,
    "preview": "package me.iwf.PhotoPickerDemo;\n\nimport android.content.Intent;\n\nimport java.util.ArrayList;\n\n/**\n * Created by Administ"
  },
  {
    "path": "photopickerdemo/src/main/java/me/iwf/PhotoPickerDemo/RecyclerItemClickListener.java",
    "chars": 1420,
    "preview": "package me.iwf.PhotoPickerDemo;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport a"
  },
  {
    "path": "photopickerdemo/src/main/res/layout/activity_main.xml",
    "chars": 3082,
    "preview": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/too"
  },
  {
    "path": "photopickerdemo/src/main/res/values/color.xml",
    "chars": 161,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#5677fc</color>\n    <color name=\"color"
  },
  {
    "path": "photopickerdemo/src/main/res/values/dimens.xml",
    "chars": 108,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n  <dimen name=\"actionBarSize\">44dip</dimen>\n</resources>"
  },
  {
    "path": "photopickerdemo/src/main/res/values/strings.xml",
    "chars": 432,
    "preview": "<resources>\n    <string name=\"app_name\">PhotoPicker Demo</string>\n    <string name=\"pick_photo\">Pick Photo</string>\n    "
  },
  {
    "path": "photopickerdemo/src/main/res/values/styles.xml",
    "chars": 692,
    "preview": "<resources>\n\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n    </style>\n\n    <style name=\"act"
  },
  {
    "path": "photopickerdemo/src/main/res/values-zh/strings.xml",
    "chars": 366,
    "preview": "<resources>\n    <string name=\"app_name\">PhotoPickerDemo</string>\n    <string name=\"pick_photo\">选择图片</string>\n    <string"
  },
  {
    "path": "settings.gradle",
    "chars": 43,
    "preview": "include ':PhotoPicker', ':photopickerdemo'\n"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the glassLake/PhotoPicker GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 87 files (196.6 KB), approximately 50.2k tokens, and a symbol index with 333 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!