[
  {
    "path": ".gitignore",
    "content": "#built application files\n*.apk\n*.ap_\n\n# files for the dex VM\n*.dex\n\n# Java class files\n*.class\n\n# generated files\nbin/\ngen/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Windows thumbnail db\nThumbs.db\n\n# OSX files\n.DS_Store\n\n# Eclipse project files\n.classpath\n.project\n\n# Android Studio\n.idea\n#.idea/workspace.xml - remove # and delete .idea if it better suit your needs.\n.gradle\nbuild/\n\n/*/out\n/*/build\n/*/*/build\n/*/*/production\n*.iws\n*.ipr\n*~\n*.swp\n*.iml\n# gradle.properties\napp/mapping.txt\nproguard/lib/proguard.jar\n"
  },
  {
    "path": "README.md",
    "content": "# AndroidPicturePicker\n\n\n##Thanks for :    \n[Laevatein](https://github.com/nohana/Laevatein):Photo image selection activity set library. Currently under development.    \n[Picasso](https://github.com/square/picasso):A powerful image downloading and caching library for Android    \n[Glide](https://github.com/bumptech/glide):An image loading and caching library for Android focused on smooth scrolling    \n[Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader):Powerful and flexible library for loading, caching and displaying images on Android.  \n\n##Screen Shot\n![gallery](http://7sby47.com5.z0.glb.clouddn.com/screenshot1.jpg-hdpi)\n![gallery2](http://7sby47.com5.z0.glb.clouddn.com/screenshot2.jpg-hdpi)\n\n\n## Usage    \n\nCall photo image selection activity by the following code snipet.    \n```java\npublic void onClickButton(View view) {\n        Picker.from(this)\n                .count(3)\n                .enableCamera(true)\n                .setEngine(new GlideEngine())\n                .forResult(REQUEST_CODE_CHOOSE);\n    }\n```    \nYou can use different Image Loader, Picker provide 3 default Loader Engine:    \n1.GlideEngine    \n2.PicassoEngine    \n3.ImageLoaderEngine    \n\nor you can use custom engine , just like  \n\n```java\n      public static class CustomEngine implements LoadEngine {\n  \n     @Override\n       public void displayImage(String path, ImageView imageView) {\n        Log.i(\"picture\", path);\n        }\n   \n        @Override\n        public void displayCameraItem(ImageView imageView) {\n\n        }\n\n        @Override\n        public void scrolling(GridView view) {\n\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n        }\n\n        public CustomEngine() {\n\n        }\n\n        protected CustomEngine(Parcel in) {\n        }\n\n        public static final Creator<CustomEngine> CREATOR = new Creator<CustomEngine>() {\n            public CustomEngine createFromParcel(Parcel source) {\n                return new CustomEngine(source);\n            }\n\n            public CustomEngine[] newArray(int size) {\n                return new CustomEngine[size];\n            }\n        };\n    }\n    \n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) {\n            mSelected = PicturePickerUtils.obtainResult(data);\n            for (Uri u : mSelected) {\n                Log.i(\"picture\", u.getPath());\n            }\n        }\n    }\n```\n\n\nPlease note that LoadEngine is extends Parcelable.    \n\n##Download\nGradle    \n```gradle\n   repositories {\n    \tmaven { url \"https://jitpack.io\" }\n   }  \n  \n  \n  dependencies {\n\t\tcompile 'com.github.valuesfeng:androidpicturepicker:1.0.0'\n\t}  \n```\n\n##wait achieve\n1. Iamge quality ([quality](https://github.com/ValuesFeng/AndroidPicturePicker/blob/master/gallery%2Fsrc%2Fmain%2Fjava%2Fio%2Fvaluesfeng%2Fpicker%2FPicker.java));    \n2. Select Type  ([MimeType](https://github.com/ValuesFeng/AndroidPicturePicker/blob/master/gallery%2Fsrc%2Fmain%2Fjava%2Fio%2Fvaluesfeng%2Fpicker%2FMimeType.java));\n\n\nhelp me……    \n##License\n\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n\n  \n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.2\"\n\n    defaultConfig {\n        applicationId \"io.valuesfeng.demo\"\n        minSdkVersion 11\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    repositories {\n        flatDir {\n            dirs 'libs' //this way we can find the .aar file in libs folder\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'com.android.support:appcompat-v7:23.1.1'\n    compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'\n    compile 'com.github.bumptech.glide:glide:3.6.1'\n    compile 'com.squareup.picasso:picasso:2.5.2'\n//    compile(name: 'gallery-release', ext: 'aar')\n    compile project(':gallery')\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\DevelopmentTools\\Android\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"io.valuesfeng.demo\" >\n\n    <uses-permission android:name=\"android.permission.CAMERA\"></uses-permission>\n\n    <uses-feature android:name=\"android.hardware.camera\" />\n    <uses-feature android:name=\"android.hardware.camera.autofocus\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:name=\".MainApp\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\" >\n        <activity\n            android:name=\".MainActivity\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/io/valuesfeng/demo/MainActivity.java",
    "content": "package io.valuesfeng.demo;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.support.v4.app.FragmentActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.GridView;\nimport android.widget.ImageView;\n\nimport java.util.List;\n\nimport io.valuesfeng.picker.MimeType;\nimport io.valuesfeng.picker.Picker;\nimport io.valuesfeng.picker.engine.LoadEngine;\nimport io.valuesfeng.picker.engine.GlideEngine;\nimport io.valuesfeng.picker.utils.PicturePickerUtils;\n\npublic class MainActivity extends FragmentActivity {\n    public static final int REQUEST_CODE_CHOOSE = 1;\n    private List<Uri> mSelected;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == REQUEST_CODE_CHOOSE && resultCode == RESULT_OK) {\n            mSelected = PicturePickerUtils.obtainResult(data);\n            for (Uri u : mSelected) {\n                Log.i(\"picture\", u.getPath());\n            }\n        }\n    }\n\n    public void onClickButton(View view) {\n        Picker.from(this)\n                .count(3)\n                .enableCamera(true)\n                .setEngine(new GlideEngine())\n//                .setEngine(new PicassoEngine())\n//                .setEngine(new ImageLoaderEngine())\n//                .setEngine(new CustomEngine())\n                .forResult(REQUEST_CODE_CHOOSE);\n    }\n\n    static class CustomEngine implements LoadEngine {\n        @Override\n        public void displayImage(String path, ImageView imageView) {\n            Log.i(\"picture\", path);\n        }\n\n        @Override\n        public void displayCameraItem(ImageView imageView) {\n\n        }\n\n        @Override\n        public void scrolling(GridView view) {\n\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n        }\n\n        public CustomEngine() {\n\n        }\n\n        protected CustomEngine(Parcel in) {\n        }\n\n        public static final Creator<CustomEngine> CREATOR = new Creator<CustomEngine>() {\n            public CustomEngine createFromParcel(Parcel source) {\n                return new CustomEngine(source);\n            }\n\n            public CustomEngine[] newArray(int size) {\n                return new CustomEngine[size];\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/valuesfeng/demo/MainApp.java",
    "content": "package io.valuesfeng.demo;\n\nimport android.app.Application;\nimport android.graphics.Bitmap;\n\nimport com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;\nimport com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.ImageLoaderConfiguration;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\n\n/**\n * Created by laputan on 15-6-8.\n */\npublic class MainApp extends Application {\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n\n        DisplayImageOptions userOptions = new DisplayImageOptions.Builder()\n                .cacheInMemory(true).cacheOnDisk(true).\n                        showImageForEmptyUri(R.drawable.image_not_exist).\n                        showImageOnLoading(R.drawable.image_not_exist).\n                        showImageOnFail(R.drawable.image_not_exist).\n                        imageScaleType(ImageScaleType.EXACTLY).\n                        bitmapConfig(Bitmap.Config.RGB_565).\n                        considerExifParams(true)\n                .build();\n\n\n        ImageLoaderConfiguration config =\n                new ImageLoaderConfiguration\n                        .Builder(getApplicationContext())\n                        .diskCacheFileCount(200)\n                        .threadPoolSize(Thread.NORM_PRIORITY)\n//                        .denyCacheImageMultipleSizesInMemory()\n//                        .memoryCacheSize(10 * 1024 * 1024)\n                        .defaultDisplayImageOptions(userOptions)\n                        .build();\n\n        ImageLoader.getInstance().init(config);\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\" tools:context=\".MainActivity\">\n\n    <Button\n        android:layout_marginTop=\"20dip\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"choose\"\n        android:onClick=\"onClickButton\"/>\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/menu/menu_main.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\" tools:context=\".MainActivity\">\n    <item android:id=\"@+id/action_settings\" android:title=\"@string/action_settings\"\n        android:orderInCategory=\"100\" app:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">FotoplaceGallery</string>\n\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.2.3'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n"
  },
  {
    "path": "gallery/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "gallery/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.2\"\n\n    defaultConfig {\n        minSdkVersion 11\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:23.1.1'\n    compile 'com.android.support:recyclerview-v7:23.1.1'\n    compile 'com.android.support:support-v4:23.1.1'\n    provided 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'\n    provided 'com.squareup.picasso:picasso:2.5.2'\n    provided 'com.github.bumptech.glide:glide:3.6.1'\n}\n"
  },
  {
    "path": "gallery/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\DevelopmentTools\\Android\\sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "gallery/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"io.valuesfeng.picker\" >\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>\n    <application android:allowBackup=\"true\">\n        <activity android:name=\".ImageSelectActivity\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/ImageSelectActivity.java",
    "content": "package io.valuesfeng.picker;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.Parcelable;\nimport android.support.v4.app.FragmentActivity;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.AnimationUtils;\nimport android.widget.Button;\nimport android.widget.GridView;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.ListView;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.ArrayList;\n\nimport io.valuesfeng.picker.control.PictureCollection;\nimport io.valuesfeng.picker.control.AlbumCollection;\nimport io.valuesfeng.picker.model.Album;\nimport io.valuesfeng.picker.control.SelectedUriCollection;\nimport io.valuesfeng.picker.model.SelectionSpec;\nimport io.valuesfeng.picker.utils.BundleUtils;\nimport io.valuesfeng.picker.utils.MediaStoreCompat;\n\n\npublic class ImageSelectActivity extends FragmentActivity implements AlbumCollection.OnDirectorySelectListener {\n\n    public static final String EXTRA_RESULT_SELECTION = BundleUtils.buildKey(ImageSelectActivity.class, \"EXTRA_RESULT_SELECTION\");\n    public static final String EXTRA_SELECTION_SPEC = BundleUtils.buildKey(ImageSelectActivity.class, \"EXTRA_SELECTION_SPEC\");\n    public static final String EXTRA_RESUME_LIST = BundleUtils.buildKey(ImageSelectActivity.class, \"EXTRA_RESUME_LIST\");\n//    public static final String EXTRA_ENGINE = BundleUtils.buildKey(ImageSelectActivity.class, \"EXTRA_ENGINE\");\n\n    public static final String STATE_CAPTURE_PHOTO_URI = BundleUtils.buildKey(ImageSelectActivity.class, \"STATE_CAPTURE_PHOTO_URI\");\n\n    private RelativeLayout rlTop;\n    private TextView mFoldName;\n    private View mListViewGroup;\n    private ListView mListView;\n    private GridView mGridView;\n    public static final int REQUEST_CODE_CAPTURE = 3;\n    private MediaStoreCompat mMediaStoreCompat;\n    private Button commit;\n    private ImageView galleryTip;\n    private SelectionSpec selectionSpec;\n    private ImageView btnBack;\n    private AlbumCollection albumCollection =new AlbumCollection();\n    private final PictureCollection mPhotoCollection = new PictureCollection();\n    private final SelectedUriCollection mCollection = new SelectedUriCollection(this);\n    private String mCapturePhotoUriHolder;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_image_select);\n        mCapturePhotoUriHolder = savedInstanceState != null ? savedInstanceState.getString(STATE_CAPTURE_PHOTO_URI) : \"\";\n        selectionSpec = getIntent().getParcelableExtra(ImageSelectActivity.EXTRA_SELECTION_SPEC);\n        mMediaStoreCompat = new MediaStoreCompat(this, new Handler(Looper.getMainLooper()));\n\n        mCollection.onCreate(savedInstanceState);\n        mCollection.prepareSelectionSpec(selectionSpec);\n        mCollection.setDefaultSelection(getIntent().<Uri>getParcelableArrayListExtra(EXTRA_RESUME_LIST));\n        mCollection.setOnSelectionChange(new SelectedUriCollection.OnSelectionChange() {\n            @Override\n            public void onChange(int maxCount, int selectCount) {\n                commit.setText(getString(R.string.l_album_name_confirm) + \"(\" + selectCount+\"/\"+maxCount+\")\");\n            }\n        });\n\n        mGridView = (GridView) findViewById(R.id.gridView);\n\n        mListView = (ListView) findViewById(R.id.listView);\n        btnBack = (ImageView) findViewById(R.id.btn_back);\n        mListViewGroup = findViewById(R.id.listViewParent);\n        mListViewGroup.setOnClickListener(mOnClickFoldName);\n        mFoldName = (TextView) findViewById(R.id.foldName);\n        galleryTip = (ImageView) findViewById(R.id.gallery_tip);\n        LinearLayout selectFold = (LinearLayout) findViewById(R.id.selectFold);\n        commit = (Button) findViewById(R.id.commit);\n        commit.setText(getString(R.string.l_album_name_confirm) + \"(0/\" + selectionSpec.getMaxSelectable()+\")\");\n        if (selectionSpec.isSingleChoose()){\n            commit.setVisibility(View.GONE);\n        }\n        mFoldName.setText(R.string.l_album_name_all);\n        selectFold.setOnClickListener(mOnClickFoldName);\n\n        albumCollection.onCreate(ImageSelectActivity.this,this,selectionSpec,mListView);\n        albumCollection.loadAlbums();\n        mPhotoCollection.onCreate(ImageSelectActivity.this,mGridView,mCollection,selectionSpec);\n        mPhotoCollection.loadAllPhoto();\n\n        commit.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (mCollection.isEmpty()) {\n                    Toast.makeText(getApplicationContext(), getString(R.string.l_album_name_unselected_picture) ,Toast.LENGTH_LONG).show();\n                }else{\n                    setResult();\n                }\n            }\n        });\n        btnBack.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                finish();\n            }\n        });\n\n        if (selectionSpec.willStartCamera()) showCameraAction();\n    }\n\n    public void setResult() {\n        Intent intent = new Intent();\n        intent.putParcelableArrayListExtra(ImageSelectActivity.EXTRA_RESULT_SELECTION,\n                (ArrayList<? extends Parcelable>) mCollection.asList());\n        setResult(Activity.RESULT_OK, intent);\n        finish();\n    }\n\n    View.OnClickListener mOnClickFoldName = new View.OnClickListener() {\n        @Override\n        public void onClick(View v) {\n            if (mListViewGroup.getVisibility() == View.VISIBLE) {\n                hideFolderList();\n            } else {\n                showFolderList();\n            }\n        }\n    };\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        mCollection.onSaveInstanceState(outState);\n        albumCollection.onSaveInstanceState(outState);\n        outState.putString(STATE_CAPTURE_PHOTO_URI, mCapturePhotoUriHolder);\n        super.onSaveInstanceState(outState);\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Bundle savedInstanceState) {\n        super.onRestoreInstanceState(savedInstanceState);\n        albumCollection.onRestoreInstanceState(savedInstanceState);\n    }\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (requestCode == REQUEST_CODE_CAPTURE && resultCode == Activity.RESULT_OK) {\n            Uri captured = mMediaStoreCompat.getCapturedPhotoUri(data, mCapturePhotoUriHolder);\n            if (captured != null) {\n                mCollection.add(captured);\n                mMediaStoreCompat.cleanUp(mCapturePhotoUriHolder);\n                if(mCollection.isSingleChoose()){\n                    setResult();\n                }\n            }\n        }\n    }\n\n    public void prepareCapture(String uri) {\n        mCapturePhotoUriHolder = uri;\n    }\n\n    private void showFolderList() {\n        galleryTip.setImageResource(R.drawable.gallery_up);\n        mListViewGroup.setVisibility(View.VISIBLE);\n        mListView.setVisibility(View.VISIBLE);\n        Animation animation = AnimationUtils.loadAnimation(this, R.anim.listview_up);\n        Animation fadeIn = AnimationUtils.loadAnimation(this, R.anim.listview_fade_in);\n\n        mListView.startAnimation(animation);\n        mListViewGroup.startAnimation(fadeIn);\n        //mListViewGroup.setVisibility(View.VISIBLE);\n    }\n\n    private void hideFolderList() {\n        galleryTip.setImageResource(R.drawable.gallery_down);\n        Animation animation = AnimationUtils.loadAnimation(ImageSelectActivity.this, R.anim.listview_down);\n        Animation fadeOut = AnimationUtils.loadAnimation(ImageSelectActivity.this, R.anim.listview_fade_out);\n        animation.setAnimationListener(new Animation.AnimationListener() {\n            @Override\n            public void onAnimationStart(Animation animation) {\n            }\n\n            @Override\n            public void onAnimationEnd(Animation animation) {\n                mListViewGroup.setVisibility(View.INVISIBLE);\n            }\n\n            @Override\n            public void onAnimationRepeat(Animation animation) {\n            }\n        });\n\n        mListView.startAnimation(animation);\n        mListViewGroup.startAnimation(fadeOut);\n    }\n\n    public MediaStoreCompat getMediaStoreCompat() {\n        return mMediaStoreCompat;\n    }\n\n    @Override\n    protected void onDestroy() {\n        mMediaStoreCompat.destroy();\n        albumCollection.onDestroy();\n        mPhotoCollection.onDestroy();\n        super.onDestroy();\n    }\n    @Override\n    public void onBackPressed() {\n        if (mCollection.isEmpty()) {\n            setResult(Activity.RESULT_CANCELED);\n            super.onBackPressed();\n        }\n    }\n    /**\n     * 选择相机\n     */\n    public void showCameraAction() {\n        mCapturePhotoUriHolder = mMediaStoreCompat.invokeCameraCapture(this, ImageSelectActivity.REQUEST_CODE_CAPTURE);\n    }\n\n    @Override\n    public void onSelect(Album album) {\n        hideFolderList();\n        mFoldName.setText(album.getDisplayName(this));\n        mPhotoCollection.resetLoad(album);\n    }\n\n    @Override\n    public void onReset(Album album) {\n        mPhotoCollection.load(album);\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/MimeType.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker;\n\nimport android.content.ContentResolver;\nimport android.net.Uri;\nimport android.webkit.MimeTypeMap;\n\n\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport io.valuesfeng.picker.utils.PhotoMetadataUtils;\n\n/**\n * MIME Type enumeration to restrict selectable photo on the selection activity.\n * @author KeithYokoma\n * @since 2014/03/19\n * @version 1.0.0\n */\n@SuppressWarnings(\"unused\") // public APIs\npublic enum MimeType {\n    JPEG(\"image/jpeg\", new HashSet<String>() {{ add(\"jpg\"); add(\"jpeg\"); }}),\n    PNG(\"image/png\", new HashSet<String>() {{ add(\"png\"); }}),\n    GIF(\"image/gif\", new HashSet<String>() {{ add(\"gif\"); }});\n\n    private final String mMimeTypeName;\n    private final Set<String> mExtensions;\n\n    MimeType(String mimeTypeName, Set<String> extensions) {\n        mMimeTypeName = mimeTypeName;\n        mExtensions = extensions;\n    }\n\n    public static Set<MimeType> allOf() {\n        return EnumSet.allOf(MimeType.class);\n    }\n\n    public static Set<MimeType> of(MimeType type) {\n        return EnumSet.of(type);\n    }\n\n    public static Set<MimeType> of(MimeType type, MimeType... rest) {\n        return EnumSet.of(type, rest);\n    }\n\n    @Override\n    public String toString() {\n        return mMimeTypeName;\n    }\n\n    public boolean checkType(ContentResolver resolver, Uri uri) {\n        MimeTypeMap map = MimeTypeMap.getSingleton();\n        if (uri == null) {\n            return false;\n        }\n        String type = map.getExtensionFromMimeType(resolver.getType(uri));\n        for (String extension : mExtensions) {\n            if (extension.equals(type)) {\n                return true;\n            }\n            String path = PhotoMetadataUtils.getPath(resolver, uri);\n            if (path != null && path.toLowerCase(Locale.US).endsWith(extension)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/Picker.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.Fragment;\n\n\nimport com.bumptech.glide.Glide;\nimport com.squareup.picasso.Picasso;\n\nimport java.io.Serializable;\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\nimport io.valuesfeng.picker.engine.LoadEngine;\nimport io.valuesfeng.picker.model.SelectionSpec;\n\n/**\n *\n * thanks for:\n *\n * https://github.com/nohana/Laevatein\n */\npublic final class Picker {\n    private static final String INITIALIZE_PICKER_ERROR = \"Try to initialize Picker which had already been initialized before\";\n    private static boolean hasInitPicker;\n    private final WeakReference<Activity> mContext;\n    private final WeakReference<Fragment> mFragment;\n    private final Set<MimeType> mMimeType;\n    private final SelectionSpec mSelectionSpec;\n    private LoadEngine engine;      //图片加载器 glide  imageloder picasso\n    private List<Uri> mResumeList;\n\n    Picker(Activity activity, Fragment fragment, Set<MimeType> mimeType) {\n        mContext = new WeakReference<>(activity);\n        if (fragment != null)\n            mFragment = new WeakReference<>(fragment);\n        else\n            mFragment = null;\n        mMimeType = mimeType;\n        mSelectionSpec = new SelectionSpec();\n        mResumeList = new ArrayList<>();\n    }\n\n    Picker(Activity activity, Fragment fragment) {\n        mContext = new WeakReference<>(activity);\n        if (fragment != null)\n            mFragment = new WeakReference<>(fragment);\n        else\n            mFragment = null;\n        mMimeType = MimeType.allOf();\n        mSelectionSpec = new SelectionSpec();\n        mResumeList = new ArrayList<>();\n    }\n\n\n    /**\n     * set iamge  load engine\n     *\n     * @param engine\n     * @return\n     */\n    public Picker setEngine(LoadEngine engine) {\n        this.engine = engine;\n        return this;\n    }\n\n    /**\n     * set the first item open camera\n     *\n     * @param mEnableCamera\n     * @return\n     */\n    public Picker enableCamera(boolean mEnableCamera) {\n        mSelectionSpec.setmEnableCamera(mEnableCamera);\n        return this;\n    }\n\n    /**\n     * set if should start the camera by default\n     *\n     * @param mStartWithCamera\n     * @return\n     */\n    public Picker startCamera(boolean mStartWithCamera) {\n        mSelectionSpec.startWithCamera(mStartWithCamera);\n        return this;\n    }\n\n    /**\n     * Sets the limitation of a selectable count within the specified range.\n     *\n     * @param min minimum value to select.\n     * @param max maximum value to select.\n     * @return the specification builder context.\n     */\n    public Picker count(int min, int max) {\n        mSelectionSpec.setMinSelectable(min);\n        mSelectionSpec.setMaxSelectable(max);\n        return this;\n    }\n\n    /**\n     * Sets the limitation of a selectable count within the specified range.\n     *\n     * @param max maximum value to select.\n     * @return the specification builder context.\n     */\n    public Picker count(int max) {\n        mSelectionSpec.setMinSelectable(0);\n        mSelectionSpec.setMaxSelectable(max);\n        return this;\n    }\n\n    public Picker singleChoice() {\n        count(0, 1);\n        return this;\n    }\n\n    //TODO : Wait achieve\n    /**\n     * Sets the limitation of a selectable image quality by pixel count within the specified range.\n     *\n     * @param minPixel minimum value to select.\n     * @param maxPixel maximum value to select.\n     * @return the specification builder context.\n     */\n    public Picker quality(int minPixel, int maxPixel) {\n        mSelectionSpec.setMinPixels(minPixel);\n        mSelectionSpec.setMaxPixels(maxPixel);\n        return this;\n    }\n\n    /**\n     * Sets the default selection to resume photo picking activity.\n     *\n     * @param uriList to set selected as default.\n     * @return the specification builder context.\n     */\n    public Picker resume(List<Uri> uriList) {\n        if (uriList == null) { // nothing to do.\n            return this;\n        }\n        mResumeList.addAll(uriList);\n        return this;\n    }\n\n    /**\n     * Start to select photo.\n     *\n     * @param requestCode identity of the requester activity.\n     */\n    public void forResult(int requestCode) {\n        if (engine == null)\n            throw new ExceptionInInitializerError(LoadEngine.INITIALIZE_ENGINE_ERROR);\n\n        Activity activity = getActivity();\n        if (activity == null) {\n            return; // cannot continue;\n        }\n        mSelectionSpec.setMimeTypeSet(mMimeType);\n        mSelectionSpec.setEngine(engine);\n        Intent intent = new Intent(activity, ImageSelectActivity.class);\n        intent.putExtra(ImageSelectActivity.EXTRA_SELECTION_SPEC, mSelectionSpec);\n//        intent.putExtra(ImageSelectActivity.EXTRA_ENGINE, (Serializable) engine);\n        intent.putParcelableArrayListExtra(ImageSelectActivity.EXTRA_RESUME_LIST, (ArrayList<? extends android.os.Parcelable>) mResumeList);\n\n        Fragment fragment = getFragment();\n        if (fragment != null) {\n            fragment.startActivityForResult(intent, requestCode);\n        } else {\n            activity.startActivityForResult(intent, requestCode);\n        }\n        hasInitPicker = false;\n    }\n\n    public static Picker from(Activity activity) {\n        if (hasInitPicker)\n            throw new ExceptionInInitializerError(INITIALIZE_PICKER_ERROR);\n        hasInitPicker = true;\n        return new Picker(activity, null);\n    }\n\n    public static Picker from(Activity activity, Set<MimeType> mimeType) {\n        if (hasInitPicker)\n            throw new ExceptionInInitializerError(INITIALIZE_PICKER_ERROR);\n        hasInitPicker = true;\n        return new Picker(activity, null, mimeType);\n    }\n\n    public static Picker from(Fragment fragment) {\n        if (hasInitPicker)\n            throw new ExceptionInInitializerError(INITIALIZE_PICKER_ERROR);\n        hasInitPicker = true;\n        return new Picker(fragment.getActivity(), fragment);\n    }\n\n    public static Picker from(Fragment fragment, Set<MimeType> mimeType) {\n        if (hasInitPicker)\n            throw new ExceptionInInitializerError(INITIALIZE_PICKER_ERROR);\n        hasInitPicker = true;\n        return new Picker(fragment.getActivity(), fragment, mimeType);\n    }\n\n    /**\n     * @return the actual requester context.\n     */\n    @Nullable\n    Activity getActivity() {\n        return mContext.get();\n    }\n\n    /**\n     * @return the fragment that is responsible for result handling.\n     */\n    @Nullable\n    Fragment getFragment() {\n        return mFragment != null ? mFragment.get() : null;\n    }\n\n}"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/adapter/AlbumAdapter.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.adapter;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.support.v4.widget.CursorAdapter;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.utils.L;\n\nimport io.valuesfeng.picker.R;\nimport io.valuesfeng.picker.model.Album;\n\n\n/**\n */\npublic class AlbumAdapter extends CursorAdapter {\n    LayoutInflater mInflater;\n    ViewHolder viewHolder;\n\n    public AlbumAdapter(Context context, Cursor c) {\n        super(context, c, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);\n        mInflater = LayoutInflater.from(context);\n    }\n\n    @Override\n    public View newView(Context context, Cursor cursor, ViewGroup parent) {\n        View convertView = mInflater.inflate(R.layout.photopick_list_item, parent, false);\n        viewHolder = new ViewHolder();\n        viewHolder.textView =(TextView) convertView.findViewById(R.id.foldName);\n        viewHolder.photoCount =(TextView) convertView.findViewById(R.id.photoCount);\n        convertView.setTag(viewHolder);\n        return convertView;\n    }\n\n    @Override\n    public void bindView(View view, Context context, Cursor cursor) {\n        viewHolder = (ViewHolder) view.getTag();\n        Album album = Album.valueOf(cursor);\n        viewHolder.textView.setText(album.getDisplayName(context));\n        viewHolder.photoCount.setText(\"( \"+album.getCount()+\" )\");\n    }\n\n    static class ViewHolder{\n        TextView textView;\n        TextView photoCount;\n    }\n}"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/adapter/PictureAdapter.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.adapter;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.support.v4.widget.CursorAdapter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport java.util.Map;\n\nimport io.valuesfeng.picker.R;\nimport io.valuesfeng.picker.model.Picture;\nimport io.valuesfeng.picker.control.SelectedUriCollection;\nimport io.valuesfeng.picker.widget.GridViewItemRelativeLayout;\n\n/**\n */\npublic class PictureAdapter extends CursorAdapter {\n    LayoutInflater mInflater;\n    SelectedUriCollection mCollection;\n\n    public PictureAdapter(Context context, Cursor c, SelectedUriCollection mCollection) {\n        super(context, c, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);\n        mInflater = LayoutInflater.from(context);\n        this.mCollection = mCollection;\n    }\n\n    private ViewHolder viewHolder;\n\n    @Override\n    public View newView(Context context, Cursor cursor, ViewGroup parent) {\n        View convertView = mInflater.inflate(R.layout.photopick_gridlist_item, parent, false);\n        viewHolder = new ViewHolder(convertView, mCollection);\n        return convertView;\n    }\n\n    @Override\n    public void bindView(View view, final Context context, Cursor cursor) {\n        viewHolder = (ViewHolder) view.getTag();\n        viewHolder.itemView.setItem(Picture.valueOf(cursor));\n    }\n\n    static class ViewHolder {\n        GridViewItemRelativeLayout itemView;\n\n        public ViewHolder(View convertView, SelectedUriCollection mCollection) {\n            itemView = (GridViewItemRelativeLayout) convertView;\n            itemView.setImageView((ImageView) convertView.findViewById(R.id.thumbnail)\n                    , (ImageView) convertView.findViewById(R.id.check)\n                    , mCollection);\n            convertView.setTag(this);\n        }\n    }\n}"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/control/AlbumCollection.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.control;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.Loader;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.ListView;\n\n\nimport java.lang.ref.WeakReference;\n\nimport io.valuesfeng.picker.adapter.AlbumAdapter;\nimport io.valuesfeng.picker.loader.AlbumLoader;\nimport io.valuesfeng.picker.model.Album;\nimport io.valuesfeng.picker.model.SelectionSpec;\nimport io.valuesfeng.picker.utils.BundleUtils;\nimport io.valuesfeng.picker.utils.HandlerUtils;\n\n/**\n * @version 1.0.0\n * @hide\n */\npublic class AlbumCollection implements LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemClickListener {\n    private static final int LOADER_ID = 1;\n    private static final String STATE_CURRENT_SELECTION = BundleUtils.buildKey(AlbumCollection.class, \"STATE_CURRENT_SELECTION\");\n    private WeakReference<Context> mContext;\n    private LoaderManager mLoaderManager;\n    private OnDirectorySelectListener directorySelectListener;\n    private int mCurrentSelection;\n    private SelectionSpec selectionSpec;\n    private AlbumAdapter albumAdapter;\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle args) {\n        Context context = mContext.get();\n        if (context == null) {\n            return null;\n        }\n        return AlbumLoader.newInstance(context, selectionSpec);\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, final Cursor data) {\n        Context context = mContext.get();\n        if (context == null) {\n            return;\n        }\n        albumAdapter.swapCursor(data);\n        HandlerUtils.getMainHandler().post(new Runnable() {\n            @Override\n            public void run() {\n                if (data.getCount() > 0) {\n                    data.moveToFirst();\n                    Album currentAlbum = Album.valueOf(data);\n                    if (directorySelectListener != null) {\n                        directorySelectListener.onReset(currentAlbum);\n                    }\n                }\n            }\n        });\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        Context context = mContext.get();\n        if (context == null) {\n            return;\n        }\n        albumAdapter.swapCursor(null);\n    }\n\n    public void onCreate(FragmentActivity activity, OnDirectorySelectListener directorySelectListener, SelectionSpec selectionSpec, ListView listView) {\n        mContext = new WeakReference<Context>(activity);\n        mLoaderManager = activity.getSupportLoaderManager();\n        this.directorySelectListener = directorySelectListener;\n        this.selectionSpec = selectionSpec;\n        albumAdapter = new AlbumAdapter(activity, null);\n        listView.setAdapter(albumAdapter);\n        listView.setOnItemClickListener(this);\n    }\n\n    public void onRestoreInstanceState(Bundle savedInstanceState) {\n        if (savedInstanceState == null) {\n            return;\n        }\n        mCurrentSelection = savedInstanceState.getInt(STATE_CURRENT_SELECTION);\n    }\n\n    public void onSaveInstanceState(Bundle outState) {\n        outState.putInt(STATE_CURRENT_SELECTION, mCurrentSelection);\n    }\n\n    public void onDestroy() {\n        mLoaderManager.destroyLoader(LOADER_ID);\n        directorySelectListener = null;\n    }\n\n    public void loadAlbums() {\n        mLoaderManager.initLoader(LOADER_ID, null, this);\n    }\n\n    public void resetLoadAlbums() {\n        mLoaderManager.restartLoader(LOADER_ID, null, this);\n    }\n\n\n    public int getCurrentSelection() {\n        return mCurrentSelection;\n    }\n\n    public void setStateCurrentSelection(int currentSelection) {\n        mCurrentSelection = currentSelection;\n    }\n\n    @Override\n    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n        if (directorySelectListener != null) {\n            Cursor cursor = (Cursor) parent.getItemAtPosition(position);\n            Album album = Album.valueOf(cursor);\n            directorySelectListener.onSelect(album);\n        }\n    }\n\n    public interface OnDirectorySelectListener {\n        void onSelect(Album album);\n\n        void onReset(Album album);\n    }\n\n\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/control/PictureCollection.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.control;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.Loader;\nimport android.widget.GridView;\n\nimport java.lang.ref.WeakReference;\n\nimport io.valuesfeng.picker.adapter.PictureAdapter;\nimport io.valuesfeng.picker.loader.PictureLoader;\nimport io.valuesfeng.picker.model.Album;\nimport io.valuesfeng.picker.model.SelectionSpec;\nimport io.valuesfeng.picker.utils.BundleUtils;\n\n/**\n */\npublic class PictureCollection implements LoaderManager.LoaderCallbacks<Cursor> {\n    private static final int LOADER_ID = 2;\n    private static final String ARGS_ALBUM = BundleUtils.buildKey(PictureCollection.class, \"ARGS_ALBUM\");\n    private WeakReference<Context> mContext;\n    private LoaderManager mLoaderManager;\n    private PictureAdapter albumPhotoAdapter;\n    private SelectionSpec selectionSpec;\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle args) {\n        Context context = mContext.get();\n        if (context == null) {\n            return null;\n        }\n        Album album = args.getParcelable(ARGS_ALBUM);\n        if (album == null) {\n            return null;\n        }\n        return PictureLoader.newInstance(context, album, selectionSpec);\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        Context context = mContext.get();\n        if (context == null) {\n            return;\n        }\n        albumPhotoAdapter.swapCursor(data);\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        Context context = mContext.get();\n        if (context == null) {\n            return;\n        }\n        albumPhotoAdapter.swapCursor(null);\n    }\n\n    public void onCreate(@NonNull FragmentActivity context, @NonNull GridView gridView, SelectedUriCollection mCollection, SelectionSpec selectionSpec) {\n        mContext = new WeakReference<Context>(context);\n        mLoaderManager = context.getSupportLoaderManager();\n        this.selectionSpec = selectionSpec;\n        albumPhotoAdapter = new PictureAdapter(context, null, mCollection);\n        mCollection.getEngine().scrolling(gridView);\n        gridView.setAdapter(albumPhotoAdapter);\n    }\n\n    public void onDestroy() {\n        mLoaderManager.destroyLoader(LOADER_ID);\n    }\n\n    public void loadAllPhoto() {\n        Album album = new Album(Album.ALBUM_ID_ALL, -1, Album.ALBUM_NAME_ALL, \"\");\n        load(album);\n    }\n\n    public void load(@Nullable Album target) {\n        Bundle args = new Bundle();\n        args.putParcelable(ARGS_ALBUM, target);\n        mLoaderManager.initLoader(LOADER_ID, args, this);\n    }\n\n    public void resetLoad(@Nullable Album target) {\n        Bundle args = new Bundle();\n        args.putParcelable(ARGS_ALBUM, target);\n        mLoaderManager.restartLoader(LOADER_ID, args, this);\n    }\n\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/control/SelectedUriCollection.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.control;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Bundle;\n\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport io.valuesfeng.picker.engine.LoadEngine;\nimport io.valuesfeng.picker.model.SelectionSpec;\nimport io.valuesfeng.picker.utils.BundleUtils;\n\n/**\n */\npublic class SelectedUriCollection {\n    private static final String STATE_SELECTION = BundleUtils.buildKey(SelectedUriCollection.class, \"STATE_SELECTION\");\n    private static final String STATE_SELECTION_POSITION = BundleUtils.buildKey(SelectedUriCollection.class, \"STATE_SELECTION_POSITION\");\n    private final WeakReference<Context> mContext;\n    private Set<Uri> mUris;\n    private SelectionSpec mSpec;\n    private OnSelectionChange onSelectionChange;\n\n    public SelectedUriCollection(Context context) {\n        mContext = new WeakReference<>(context);\n    }\n\n    public void onCreate(Bundle savedInstanceState) {\n        if (savedInstanceState == null) {\n            mUris = new LinkedHashSet<>();\n        } else {\n            List<Uri> saved = savedInstanceState.getParcelableArrayList(STATE_SELECTION);\n            mUris = new LinkedHashSet<>(saved);\n        }\n    }\n\n    public void prepareSelectionSpec(SelectionSpec spec) {\n        mSpec = spec;\n    }\n\n    public void setDefaultSelection(List<Uri> uris) {\n        mUris.addAll(uris);\n    }\n\n    public void onSaveInstanceState(Bundle outState) {\n        outState.putParcelableArrayList(STATE_SELECTION, new ArrayList<>(mUris));\n    }\n\n    public boolean add(Uri uri) {\n        if (onSelectionChange!=null)\n            onSelectionChange.onChange(maxCount(),count()+1);\n        return mUris.add(uri);\n    }\n\n    public boolean remove(Uri uri) {\n        if (onSelectionChange!=null)\n            onSelectionChange.onChange(maxCount(),count()-1);\n        return mUris.remove(uri);\n    }\n\n    public List<Uri> asList() {\n        return new ArrayList<Uri>(mUris);\n    }\n\n    public boolean isEmpty() {\n        return mUris == null || mUris.isEmpty();\n    }\n\n    public boolean isSelected(Uri uri) {\n        return mUris.contains(uri);\n    }\n\n    public boolean isCountInRange() {\n        return mSpec.getMinSelectable() <= mUris.size() && mUris.size() <= mSpec.getMaxSelectable();\n    }\n\n    public boolean isCountOver() {\n        return mUris.size() >= mSpec.getMaxSelectable();\n    }\n\n    public int count() {\n        return mUris.size();\n    }\n\n    public int maxCount() {\n        return mSpec.getMaxSelectable();\n    }\n\n    public boolean isSingleChoose() {\n        return mSpec.isSingleChoose();\n    }\n\n    public LoadEngine getEngine(){\n        return mSpec.getEngine();\n    }\n\n    public void setOnSelectionChange(OnSelectionChange onSelectionChange) {\n        this.onSelectionChange = onSelectionChange;\n    }\n\n    public interface OnSelectionChange{\n        void onChange(int maxCount,int selectCount);\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/engine/GlideEngine.java",
    "content": "package io.valuesfeng.picker.engine;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.widget.GridView;\nimport android.widget.ImageView;\n\nimport com.bumptech.glide.Glide;\n\nimport io.valuesfeng.picker.R;\n\n/**\n * Author:    valuesfeng\n * Version    V1.0\n * Date:      16/1/1\n * Description:\n * Modification  History:\n * Date         \tAuthor        \t\tVersion        \tDescription\n * -----------------------------------------------------------------------------------\n * 16/1/1          valuesfeng              1.0                    1.0\n * Why & What is modified:\n */\npublic class GlideEngine implements LoadEngine {\n\n    private int img_loading;\n    private int img_camera;\n\n    public GlideEngine() {\n        this(0, 0);\n    }\n\n    public GlideEngine(int img_loading) {\n        this(img_loading, 0);\n    }\n\n    public GlideEngine(int img_camera, int img_loading) {\n        if (img_loading == 0)\n            this.img_loading = R.drawable.image_not_exist;\n        else\n            this.img_loading = img_loading;\n        if (img_camera == 0)\n            this.img_camera = R.drawable.ic_camera;\n        else\n            this.img_camera = img_camera;\n    }\n\n    @Override\n    public void displayImage(String path, ImageView imageView) {\n        chargeInit(imageView.getContext());\n        Glide.with(imageView.getContext())\n                .load(path)\n                .centerCrop()\n                .error(img_loading)\n                .placeholder(img_loading)\n                .dontAnimate()\n                .into(imageView);\n    }\n\n    @Override\n    public void displayCameraItem(ImageView imageView) {\n        chargeInit(imageView.getContext());\n        Glide.with(imageView.getContext())\n                .load(img_camera)\n                .centerCrop()\n                .error(img_camera)\n                .placeholder(img_camera)\n                .dontAnimate()\n                .into(imageView);\n    }\n\n    private void chargeInit(Context context) {\n        if (Glide.get(context) == null) {\n            throw new ExceptionInInitializerError(INITIALIZE_ENGINE_ERROR);\n        }\n    }\n\n    @Override\n    public void scrolling(GridView view) {\n\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.img_loading);\n        dest.writeInt(this.img_camera);\n    }\n\n    protected GlideEngine(Parcel in) {\n        this.img_loading = in.readInt();\n        this.img_camera = in.readInt();\n    }\n\n    public static final Creator<GlideEngine> CREATOR = new Creator<GlideEngine>() {\n        public GlideEngine createFromParcel(Parcel source) {\n            return new GlideEngine(source);\n        }\n\n        public GlideEngine[] newArray(int size) {\n            return new GlideEngine[size];\n        }\n    };\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/engine/ImageLoaderEngine.java",
    "content": "package io.valuesfeng.picker.engine;\n\nimport android.graphics.Bitmap;\nimport android.os.Parcel;\nimport android.widget.GridView;\nimport android.widget.ImageView;\n\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\nimport com.nostra13.universalimageloader.core.listener.PauseOnScrollListener;\n\nimport io.valuesfeng.picker.R;\n\n/**\n * Author:    valuesfeng\n * Version    V1.0\n * Date:      16/1/1\n * Description:\n * Modification  History:\n * Date         \tAuthor        \t\tVersion        \tDescription\n * -----------------------------------------------------------------------------------\n * 16/1/1          valuesfeng              1.0                    1.0\n * Why & What is modified:\n */\npublic class ImageLoaderEngine implements LoadEngine {\n\n    private int img_loading;\n    private int img_camera;\n    private DisplayImageOptions displayOptions;\n    private DisplayImageOptions cameraOptions;\n\n\n    public ImageLoaderEngine() {\n        this(0, 0);\n    }\n\n    public ImageLoaderEngine(int img_loading) {\n        this(img_loading,0);\n    }\n\n    public ImageLoaderEngine(int img_loading, int img_camera) {\n        if (ImageLoader.getInstance() == null) {\n            throw new ExceptionInInitializerError(INITIALIZE_ENGINE_ERROR);\n        }\n        if (img_loading == 0)\n            this.img_loading = R.drawable.image_not_exist;\n        else\n            this.img_loading = img_loading;\n        if (img_camera == 0)\n            this.img_camera = R.drawable.ic_camera;\n        else\n            this.img_camera = img_camera;\n    }\n\n    @Override\n    public void displayImage(String path, ImageView imageView) {\n        ImageLoader.getInstance().displayImage(path, imageView, getPathImageOptions());\n    }\n\n    @Override\n    public void displayCameraItem(ImageView imageView) {\n        ImageLoader.getInstance().displayImage(\"drawable://\" + img_camera, imageView, getCameraOptions());\n    }\n\n    @Override\n    public void scrolling(GridView view) {\n        view.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), false, true));\n    }\n\n    private DisplayImageOptions getPathImageOptions() {\n\n        if (displayOptions == null)\n            displayOptions = new DisplayImageOptions\n                    .Builder()\n                    .showImageOnLoading(img_loading)\n                    .showImageForEmptyUri(img_loading)\n                    .showImageOnFail(img_loading)\n                    .cacheInMemory(true)\n                    .cacheOnDisk(true)\n                    .considerExifParams(true)\n                    .bitmapConfig(Bitmap.Config.RGB_565)\n                    .imageScaleType(ImageScaleType.EXACTLY)\n                    .build();\n\n        return displayOptions;\n    }\n\n    private DisplayImageOptions getCameraOptions() {\n\n        if (cameraOptions == null)\n            cameraOptions = new DisplayImageOptions\n                    .Builder()\n                    .showImageOnLoading(img_camera)\n                    .showImageForEmptyUri(img_camera)\n                    .showImageOnFail(img_camera)\n                    .cacheInMemory(true)\n                    .cacheOnDisk(true)\n                    .considerExifParams(true)\n                    .build();\n        return cameraOptions;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.img_loading);\n        dest.writeInt(this.img_camera);\n    }\n\n    protected ImageLoaderEngine(Parcel in) {\n        this.img_loading = in.readInt();\n        this.img_camera = in.readInt();\n    }\n\n    public static final Creator<ImageLoaderEngine> CREATOR = new Creator<ImageLoaderEngine>() {\n        public ImageLoaderEngine createFromParcel(Parcel source) {\n            return new ImageLoaderEngine(source);\n        }\n\n        public ImageLoaderEngine[] newArray(int size) {\n            return new ImageLoaderEngine[size];\n        }\n    };\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/engine/LoadEngine.java",
    "content": "package io.valuesfeng.picker.engine;\n\nimport android.os.Parcelable;\nimport android.widget.GridView;\nimport android.widget.ImageView;\n\nimport java.io.Serializable;\n\n/**\n * Author:    valuesfeng\n * Version    V1.0\n * Date:      16/1/1\n * Description:\n * Modification  History:\n * Date         \tAuthor        \t\tVersion        \tDescription\n * -----------------------------------------------------------------------------------\n * 16/1/1          valuesfeng              1.0                    1.0\n * Why & What is modified:\n */\npublic interface LoadEngine extends Parcelable {\n    String INITIALIZE_ENGINE_ERROR = \"initialize error,image load engine can not be null\";\n\n    void displayCameraItem(ImageView imageView);\n\n    void displayImage(String path, ImageView imageView);\n\n    void scrolling(GridView view);\n}"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/engine/PicassoEngine.java",
    "content": "package io.valuesfeng.picker.engine;\n\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.widget.AbsListView;\nimport android.widget.GridView;\nimport android.widget.ImageView;\n\nimport com.squareup.picasso.Picasso;\n\nimport io.valuesfeng.picker.R;\n\n/**\n * Author:    valuesfeng\n * Version    V1.0\n * Date:      16/1/1\n * Description:\n * Modification  History:\n * Date         \tAuthor        \t\tVersion        \tDescription\n * -----------------------------------------------------------------------------------\n * 16/1/1          valuesfeng              1.0                    1.0\n * Why & What is modified:\n */\npublic class PicassoEngine implements LoadEngine {\n\n    private int img_loading;\n    private int img_camera;\n\n    public PicassoEngine() {\n        this(0, 0);\n    }\n\n    public PicassoEngine(int img_loading) {\n        this(img_loading,0);\n    }\n\n    public PicassoEngine(int img_camera, int img_loading) {\n        if (img_loading == 0)\n            this.img_loading = R.drawable.image_not_exist;\n        else\n            this.img_loading = img_loading;\n        if (img_camera == 0)\n            this.img_camera = R.drawable.ic_camera;\n        else\n            this.img_camera = img_camera;\n    }\n\n    @Override\n    public void displayImage(String path, ImageView imageView) {\n        chargeInit(imageView.getContext());\n        Picasso.with(imageView.getContext())\n                .load(path)\n                .centerCrop()\n                .fit()\n                .placeholder(img_loading)\n                .error(img_loading)\n                .into(imageView);\n    }\n\n    @Override\n    public void displayCameraItem(ImageView imageView) {\n        chargeInit(imageView.getContext());\n        Picasso.with(imageView.getContext())\n                .load(img_camera)\n                .centerCrop()\n                .fit()\n                .placeholder(img_camera)\n                .error(img_camera)\n                .into(imageView);\n    }\n\n    @Override\n    public void scrolling(GridView view) {\n        view.setOnScrollListener(new AbsListView.OnScrollListener() {\n            @Override\n            public void onScrollStateChanged(AbsListView view, int scrollState) {\n                final Picasso picasso = Picasso.with(view.getContext());\n                if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) {\n                    picasso.resumeTag(view.getContext());\n                } else {\n                    picasso.pauseTag(view.getContext());\n                }\n            }\n\n            @Override\n            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {\n\n            }\n        });\n    }\n\n\n    private void chargeInit(Context context) {\n        if (Picasso.with(context) == null) {\n            throw new ExceptionInInitializerError(INITIALIZE_ENGINE_ERROR);\n        }\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(this.img_loading);\n        dest.writeInt(this.img_camera);\n    }\n\n    protected PicassoEngine(Parcel in) {\n        this.img_loading = in.readInt();\n        this.img_camera = in.readInt();\n    }\n\n    public static final Creator<PicassoEngine> CREATOR = new Creator<PicassoEngine>() {\n        public PicassoEngine createFromParcel(Parcel source) {\n            return new PicassoEngine(source);\n        }\n\n        public PicassoEngine[] newArray(int size) {\n            return new PicassoEngine[size];\n        }\n    };\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/loader/AlbumLoader.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.loader;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.database.MergeCursor;\nimport android.net.Uri;\nimport android.provider.MediaStore;\nimport android.support.v4.content.CursorLoader;\n\nimport io.valuesfeng.picker.model.Album;\nimport io.valuesfeng.picker.model.SelectionSpec;\nimport io.valuesfeng.picker.utils.PhotoMetadataUtils;\n\n\n/**\n * Wrapper for {@link android.support.v4.content.CursorLoader} to merge custom cursors.\n *\n * @author KeithYokoma\n * @version 1.0.0\n * @hide\n * @Modification add picture size charge\n * by valuesFeng\n * @since 2014/03/26\n */\npublic class AlbumLoader extends CursorLoader {\n    private static final String[] PROJECTION = {MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media._ID, \"count(bucket_id) as cou\"};\n    private static final String BUCKET_GROUP_BY = \") GROUP BY  1,(2\";\n    private static final String BUCKET_ORDER_BY = \"MAX(datetaken) DESC\";\n    private static final String MEDIA_ID_DUMMY = String.valueOf(-1);\n    private static final String IS_LARGE_SIZE = \" _size > ? or _size is null\";\n\n    public static CursorLoader newInstance(Context context, SelectionSpec selectionSpec) {\n        return new AlbumLoader(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION, IS_LARGE_SIZE + BUCKET_GROUP_BY, new String[]{selectionSpec.getMinPixels() + \"\"}, BUCKET_ORDER_BY,selectionSpec );\n    }\n\n    private AlbumLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, SelectionSpec selectionSpec) {\n        super(context, uri, projection, selection, selectionArgs, sortOrder);\n    }\n\n    @Override\n    public Cursor loadInBackground() {\n        Cursor albums = super.loadInBackground();\n        MatrixCursor allAlbum = new MatrixCursor(PROJECTION);\n\n        long count = 0;\n        if (albums.getCount() > 0) {\n            while (albums.moveToNext()) {\n                count += albums.getLong(3);\n            }\n        }\n        allAlbum.addRow(new String[]{Album.ALBUM_ID_ALL, Album.ALBUM_NAME_ALL, MEDIA_ID_DUMMY, count + \"\"});\n\n        return new MergeCursor(new Cursor[]{allAlbum, albums});\n    }\n}"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/loader/PictureLoader.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.loader;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.database.MergeCursor;\nimport android.net.Uri;\nimport android.provider.MediaStore;\nimport android.support.v4.content.CursorLoader;\n\nimport io.valuesfeng.picker.model.Album;\nimport io.valuesfeng.picker.model.Picture;\nimport io.valuesfeng.picker.model.SelectionSpec;\nimport io.valuesfeng.picker.utils.MediaStoreCompat;\n\n\n/**\n * @author KeithYokoma\n * @version 1.0.0\n * @hide\n * @since 2014/03/27\n *\n * @Modification\n *          add picture size charge\n *              by valuesFeng\n */\npublic class PictureLoader extends CursorLoader {\n    private static final String[] PROJECTION = {MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME};\n    private static final String ORDER_BY = MediaStore.Images.Media._ID + \" DESC\";\n    private final boolean mEnableCapture;\n    private static final String IS_LARGE_SIZE = \"_size > ? or _size is null\";\n\n    public PictureLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, boolean capture) {\n        super(context, uri, projection, selection, selectionArgs, sortOrder);\n        mEnableCapture = capture;\n    }\n\n    public static CursorLoader newInstance(Context context, Album album, SelectionSpec selectionSpec) {\n        if (album == null || album.isAll()) {\n            return new PictureLoader(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION,\n                    IS_LARGE_SIZE, new String[]{selectionSpec.getMinPixels() + \"\"}, ORDER_BY, selectionSpec.ismEnableCamera());\n        }\n        return new PictureLoader(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, PROJECTION,\n                MediaStore.Images.Media.BUCKET_ID + \" = ? and (\" + IS_LARGE_SIZE + \")\", new String[]{album.getId(), selectionSpec.getMinPixels() + \"\"}, ORDER_BY, selectionSpec.ismEnableCamera());\n    }\n\n    @Override\n    public Cursor loadInBackground() {\n        Cursor result = super.loadInBackground();\n        if (!mEnableCapture || !MediaStoreCompat.hasCameraFeature(getContext())) {\n            return result;\n        }\n        MatrixCursor dummy = new MatrixCursor(PROJECTION);\n        dummy.addRow(new Object[]{Picture.ITEM_ID_CAPTURE, Picture.ITEM_DISPLAY_NAME_CAPTURE});\n        return new MergeCursor(new Cursor[]{dummy, result});\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/model/Album.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.model;\n\nimport android.content.ContentUris;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.provider.MediaStore;\nimport android.support.annotation.Nullable;\n\nimport io.valuesfeng.picker.R;\n\n\n/**\n * @author KeithYokoma\n * @version 1.0.0\n * @hide\n * @since 2014/03/20\n */\npublic class Album implements Parcelable {\n    public static final Creator<Album> CREATOR = new Creator<Album>() {\n        @Nullable\n        @Override\n        public Album createFromParcel(Parcel source) {\n            return new Album(source);\n        }\n\n        @Override\n        public Album[] newArray(int size) {\n            return new Album[size];\n        }\n    };\n    public static final String ALBUM_ID_ALL = String.valueOf(-1);\n    public static final String ALBUM_NAME_ALL = \"All\";\n    public static final String ALBUM_NAME_CAMERA = \"Camera\";\n    public static final String ALBUM_NAME_DOWNLOAD = \"Download\";\n    public static final String ALBUM_NAME_SCREEN_SHOT = \"Screenshots\";\n    private final String mId;       //BUCKET_ID\n    private final long mCoverId;   //Media_ID\n    private final String mDisplayName;//BUCKET_DISPLAY_NAME\n    private final String mCount;        // photo count\n\n    /* package */\n\n    public Album(String id, long coverId, String albumName, String count) {\n        mId = id;\n        mCoverId = coverId;\n        mDisplayName = albumName;\n        mCount = count;\n    }\n\n    /* package */ Album(Parcel source) {\n        mId = source.readString();\n        mCoverId = source.readLong();\n        mDisplayName = source.readString();\n        mCount = source.readString();\n    }\n\n    /**\n     * This method is not responsible for managing cursor resource, such as close, iterate, and so on.\n     *\n     * @param cursor to be converted.\n     */\n    public static Album valueOf(Cursor cursor) {\n        return new Album(\n                cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID)),\n                cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID)),\n                cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)),\n                cursor.getLong(3) + \"\"\n        );\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mId);\n        dest.writeLong(mCoverId);\n        dest.writeString(mDisplayName);\n        dest.writeString(mCount);\n    }\n\n    public String getId() {\n        return mId;\n    }\n\n    public long getCoverId() {\n        return mCoverId;\n    }\n\n    public String getDisplayName(Context context) {\n        if (isAll()) {\n            return context.getString(R.string.l_album_name_all);\n        }\n        if (isCamera()) {\n            return context.getString(R.string.l_album_name_camera);\n        }\n        if (ALBUM_NAME_DOWNLOAD.equals(mDisplayName)) {\n            return context.getString(R.string.l_album_name_download);\n        }\n        if (ALBUM_NAME_SCREEN_SHOT.equals(mDisplayName)) {\n            return context.getString(R.string.l_album_name_screen_shot);\n        }\n        return mDisplayName;\n    }\n\n    public Uri buildContentUri() {\n        return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mCoverId);\n    }\n\n    public boolean isAll() {\n        return ALBUM_ID_ALL.equals(mId);\n    }\n\n    public boolean isCamera() {\n        return ALBUM_NAME_CAMERA.equals(mDisplayName);\n    }\n\n    public String getCount() {\n        return mCount;\n    }\n}"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/model/Picture.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.model;\n\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.provider.MediaStore;\nimport android.support.annotation.Nullable;\n\n/**\n * @author KeithYokoma\n * @version 1.0.0\n * @hide\n * @since 2014/03/24\n */\npublic class Picture implements Parcelable {\n    public static final Creator<Picture> CREATOR = new Creator<Picture>() {\n        @Override\n        @Nullable\n        public Picture createFromParcel(Parcel source) {\n            return new Picture(source);\n        }\n\n        @Override\n        public Picture[] newArray(int size) {\n            return new Picture[size];\n        }\n    };\n    public static final long ITEM_ID_CAPTURE = -1;\n    public static final String ITEM_DISPLAY_NAME_CAPTURE = \"Capture\";\n    private final long mId;\n    private String mDisplayName;\n\n    /* package */ Picture(long id,String displayName) {\n        mId = id;\n        mDisplayName = displayName;\n    }\n\n    /* package */ Picture(Parcel source) {\n        mId = source.readLong();\n    }\n\n    public static Picture valueOf(Cursor cursor) {\n//        return new Picture(cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID)));\n        return new Picture(cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID)),cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)));\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeLong(mId);\n    }\n\n    public long getId() {\n        return mId;\n    }\n\n    public Uri buildContentUri() {\n        return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mId);\n    }\n\n    public Bitmap getThumbnail(Context context) {\n        BitmapFactory.Options options = new BitmapFactory.Options();\n        options.inDither = false;\n        options.inPreferredConfig = Bitmap.Config.ARGB_8888;\n        ContentResolver contentResolver = context.getContentResolver();\n        return MediaStore.Images.Thumbnails.getThumbnail(contentResolver, mId, MediaStore.Images.Thumbnails.MICRO_KIND, options);\n    }\n\n    public boolean isCapture() {\n        return mId == ITEM_ID_CAPTURE;\n    }\n}"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/model/SelectionSpec.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.model;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n\nimport java.util.ArrayList;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport io.valuesfeng.picker.MimeType;\nimport io.valuesfeng.picker.engine.LoadEngine;\nimport io.valuesfeng.picker.utils.ParcelUtils;\n\n/**\n */\npublic final class SelectionSpec implements Parcelable {\n    public static final Creator<SelectionSpec> CREATOR = new Creator<SelectionSpec>() {\n        @Override\n        public SelectionSpec createFromParcel(Parcel source) {\n            return new SelectionSpec(source);\n        }\n\n        @Override\n        public SelectionSpec[] newArray(int size) {\n            return new SelectionSpec[size];\n        }\n    };\n    private int mMaxSelectable;   // 最大选择数量\n    private int mMinSelectable;   // 最小选择数量\n    private long mMinPixels;       //最小size\n    private long mMaxPixels;        //最大size\n    private boolean mEnableCamera;//是否可用相机\n    private boolean mStartWithCamera;\n    private LoadEngine engine;      //图片加载器 glide  imageloder picasso\n    private Set<MimeType> mMimeTypeSet;\n\n    public SelectionSpec() {\n        mMinSelectable = 0;\n        mMaxSelectable = 1;\n        mMinPixels = 0L;\n        mMaxPixels = Long.MAX_VALUE;\n        mEnableCamera = false;\n        mStartWithCamera = false;\n    }\n\n    SelectionSpec(Parcel source) {\n        mMinSelectable = source.readInt();\n        mMaxSelectable = source.readInt();\n        mMinPixels = source.readLong();\n        mMaxPixels = source.readLong();\n        mEnableCamera = ParcelUtils.readBoolean(source);\n        mStartWithCamera = ParcelUtils.readBoolean(source);\n        this.engine = source.readParcelable(LoadEngine.class.getClassLoader());\n        List<MimeType> list = new ArrayList<>();\n        source.readList(list, MimeType.class.getClassLoader());\n        mMimeTypeSet = EnumSet.copyOf(list);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(mMinSelectable);\n        dest.writeInt(mMaxSelectable);\n        dest.writeLong(mMinPixels);\n        dest.writeLong(mMaxPixels);\n        ParcelUtils.writeBoolean(dest, mEnableCamera);\n        ParcelUtils.writeBoolean(dest, mStartWithCamera);\n        dest.writeParcelable(this.engine, 0);\n        dest.writeList(new ArrayList<>(mMimeTypeSet));\n    }\n\n    public boolean ismEnableCamera() {\n        return mEnableCamera;\n    }\n\n    public boolean willStartCamera() { return mStartWithCamera; }\n\n    public void setmEnableCamera(boolean mEnableCamera) {\n        this.mEnableCamera = mEnableCamera;\n    }\n\n    public void startWithCamera(boolean mStartWithCamera) { this.mStartWithCamera = mStartWithCamera; }\n\n    public void setMaxSelectable(int maxSelectable) {\n        mMaxSelectable = maxSelectable;\n    }\n\n    public void setMinSelectable(int minSelectable) {\n        mMinSelectable = minSelectable;\n    }\n\n    public void setMinPixels(long minPixels) {\n        mMinPixels = minPixels;\n    }\n\n    public void setMaxPixels(long maxPixels) {\n        mMaxPixels = maxPixels;\n    }\n\n    public void setMimeTypeSet(Set<MimeType> set) {\n        mMimeTypeSet = set;\n    }\n\n    public int getMinSelectable() {\n        return mMinSelectable;\n    }\n\n    public int getMaxSelectable() {\n        return mMaxSelectable;\n    }\n\n    public long getMinPixels() {\n        return mMinPixels;\n    }\n\n    public LoadEngine getEngine() {\n        return engine;\n    }\n\n    public void setEngine(LoadEngine engine) {\n        this.engine = engine;\n    }\n\n    public boolean isSingleChoose() {\n        if (mMinSelectable == 0 && mMaxSelectable == 1) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public long getMaxPixels() {\n        return mMaxPixels;\n    }\n\n    public Set<MimeType> getMimeTypeSet() {\n        return mMimeTypeSet;\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/BundleUtils.java",
    "content": "package io.valuesfeng.picker.utils;\n\n/**\n * Created by zaiyong on 2015/6/6.\n */\npublic class BundleUtils {\n    private BundleUtils() {\n    }\n\n    public static String buildKey(Class<?> clazz, String name) {\n        return clazz.getCanonicalName() + \".\" + name;\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/CloseableUtils.java",
    "content": "package io.valuesfeng.picker.utils;\n\nimport android.util.Log;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\n/**\n * Created by laputan on 15-6-8.\n */\npublic class CloseableUtils {\n\n    private static final String TAG = CloseableUtils.class.getSimpleName();\n\n    private CloseableUtils() {\n    }\n\n    public static final void close(Closeable closeable) {\n        if(closeable != null) {\n            try {\n                closeable.close();\n            } catch (IOException var2) {\n                Log.e(TAG, \"something went wrong on close\", var2);\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/ExifInterfaceCompat.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by Fernflower decompiler)\n//\n\npackage io.valuesfeng.picker.utils;\n\nimport android.media.ExifInterface;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.TimeZone;\n\npublic final class ExifInterfaceCompat {\n    public static final String TAG = ExifInterfaceCompat.class.getSimpleName();\n\n    private ExifInterfaceCompat() {\n    }\n\n    public static final ExifInterface newInstance(String filename) throws IOException {\n        if(filename == null) {\n            throw new NullPointerException(\"filename should not be null\");\n        } else {\n            return new ExifInterface(filename);\n        }\n    }\n\n    public static final Date getExifDateTime(String filepath) {\n        ExifInterface exif;\n\n        try {\n            exif = newInstance(filepath);\n        } catch (IOException var5) {\n            Log.e(TAG, \"cannot read exif\", var5);\n            return null;\n        }\n\n        String date = exif.getAttribute(\"DateTime\");\n        if(TextUtils.isEmpty(date)) {\n            return null;\n        } else {\n            try {\n                SimpleDateFormat e = new SimpleDateFormat(\"yyyy:MM:dd HH:mm:ss\");\n                e.setTimeZone(TimeZone.getTimeZone(\"UTC\"));\n                return e.parse(date);\n            } catch (ParseException var4) {\n                Log.d(TAG, \"failed to parse date taken\", var4);\n                return null;\n            }\n        }\n    }\n\n    public static final long getExifDateTimeInMillis(String filepath) {\n        Date datetime = getExifDateTime(filepath);\n        return datetime == null?-1L:datetime.getTime();\n    }\n\n    public static final int getExifOrientation(String filepath) {\n        ExifInterface exif = null;\n\n        try {\n            exif = newInstance(filepath);\n        } catch (IOException var3) {\n            Log.e(TAG, \"cannot read exif\", var3);\n            return -1;\n        }\n\n        int orientation = exif.getAttributeInt(\"Orientation\", -1);\n        if(orientation == -1) {\n            return 0;\n        } else {\n            switch(orientation) {\n                case 3:\n                    return 180;\n                case 6:\n                    return 90;\n                case 8:\n                    return 270;\n                default:\n                    return 0;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/HandlerUtils.java",
    "content": "package io.valuesfeng.picker.utils;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\n/**\n */\npublic class HandlerUtils {\n    private HandlerUtils() {\n    }\n\n    public static Handler getMainHandler() {\n        return new Handler(Looper.getMainLooper());\n    }\n\n    public static void postOnMain(Runnable message) {\n        getMainHandler().post(message);\n    }\n\n    public static void postOnMainWithDelay(Runnable message, long delayMillis) {\n        getMainHandler().postDelayed(message, delayMillis);\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/MediaStoreCompat.java",
    "content": "//\n// Source code recreated from a .class file by IntelliJ IDEA\n// (powered by Fernflower decompiler)\n//\n\npackage io.valuesfeng.picker.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.database.ContentObserver;\nimport android.database.Cursor;\nimport android.graphics.BitmapFactory.Options;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.provider.MediaStore.Images.Media;\nimport android.provider.MediaStore.Images.Thumbnails;\nimport android.util.Log;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.Iterator;\n\n\npublic class MediaStoreCompat {\n    public static final String TAG = MediaStoreCompat.class.getSimpleName();\n    private static final String MEDIA_FILE_NAME_FORMAT = \"yyyyMMdd_HHmmss\";\n    private static final String MEDIA_FILE_EXTENSION = \".jpg\";\n    private static final String MEDIA_FILE_PREFIX = \"IMG_\";\n    private final String MEDIA_FILE_DIRECTORY;\n    private Context mContext;\n    private ContentObserver mObserver;\n    private ArrayList<MediaStoreCompat.PhotoContent> mRecentlyUpdatedPhotos;\n\n    public MediaStoreCompat(Context context, final Handler handler) {\n        this.mContext = context;\n        this.MEDIA_FILE_DIRECTORY = context.getPackageName();\n        this.mObserver = new ContentObserver(handler) {\n            public void onChange(boolean selfChange) {\n                super.onChange(selfChange);\n                MediaStoreCompat.this.updateLatestPhotos();\n            }\n        };\n        this.mContext.getContentResolver().registerContentObserver(Media.EXTERNAL_CONTENT_URI, true, this.mObserver);\n    }\n\n    public static final boolean hasCameraFeature(Context context) {\n        PackageManager pm = context.getApplicationContext().getPackageManager();\n        return pm.hasSystemFeature(\"android.hardware.camera\");\n    }\n\n    public String invokeCameraCapture(Activity activity, int requestCode) {\n        if(!hasCameraFeature(this.mContext)) {\n            return null;\n        } else {\n            File toSave = this.getOutputFileUri();\n            if(toSave == null) {\n                return null;\n            } else {\n                Intent intent = new Intent(\"android.media.action.IMAGE_CAPTURE\");\n                intent.addCategory(\"android.intent.category.DEFAULT\");\n                intent.putExtra(\"output\", Uri.fromFile(toSave));\n                intent.putExtra(\"android.intent.extra.videoQuality\", 1);\n                activity.startActivityForResult(intent, requestCode);\n                return toSave.toString();\n            }\n        }\n    }\n\n    public void destroy() {\n        this.mContext.getContentResolver().unregisterContentObserver(this.mObserver);\n    }\n\n    public Uri getCapturedPhotoUri(Intent data, String preparedUri) {\n        Uri captured = null;\n        if(data != null) {\n            captured = data.getData();\n            if(captured == null) {\n                data.getParcelableExtra(\"android.intent.extra.STREAM\");\n            }\n        }\n\n        File prepared = new File(preparedUri.toString());\n        if(captured == null || captured.equals(Uri.fromFile(prepared))) {\n            captured = this.findPhotoFromRecentlyTaken(prepared);\n            if(captured == null) {\n                captured = this.storeImage(prepared);\n                prepared.delete();\n            } else {\n                String realPath = getPathFromUri(this.mContext.getContentResolver(), captured);\n                if(realPath != null && !prepared.equals(new File(realPath))) {\n                    prepared.delete();\n                }\n            }\n        }\n        return captured;\n    }\n\n    public void cleanUp(String uri) {\n        File file = new File(uri.toString());\n        if(file.exists()) {\n            file.delete();\n        }\n\n    }\n\n    public static String getPathFromUri(ContentResolver resolver, Uri contentUri) {\n        String dataColumn = \"_data\";\n        Cursor cursor = null;\n\n        String var5;\n        try {\n            cursor = resolver.query(contentUri, new String[]{\"_data\"}, (String)null, (String[])null, (String)null);\n            if(cursor == null || !cursor.moveToFirst()) {\n                Object index1 = null;\n                return (String)index1;\n            }\n\n            int index = cursor.getColumnIndex(\"_data\");\n            var5 = cursor.getString(index);\n        } finally {\n            if(cursor != null) {\n                cursor.close();\n            }\n\n        }\n\n        return var5;\n    }\n\n    public static long copyFileStream(FileInputStream is, FileOutputStream os) throws IOException {\n        FileChannel srcChannel = null;\n        FileChannel destChannel = null;\n        long length;\n        try {\n            srcChannel = is.getChannel();\n            destChannel = os.getChannel();\n            length = srcChannel.transferTo(0L, srcChannel.size(), destChannel);\n        } finally {\n            if(srcChannel != null) {\n                srcChannel.close();\n            }\n            if(destChannel != null) {\n                destChannel.close();\n            }\n        }\n        return length;\n    }\n\n    private Uri findPhotoFromRecentlyTaken(File file) {\n        if(this.mRecentlyUpdatedPhotos == null) {\n            this.updateLatestPhotos();\n        }\n        long fileSize = file.length();\n        long taken = ExifInterfaceCompat.getExifDateTimeInMillis(file.getAbsolutePath());\n        int maxPoint = 0;\n        MediaStoreCompat.PhotoContent maxItem = null;\n        Iterator i$ = this.mRecentlyUpdatedPhotos.iterator();\n\n        while(i$.hasNext()) {\n            MediaStoreCompat.PhotoContent item = (MediaStoreCompat.PhotoContent)i$.next();\n            int point = 0;\n            if((long)item.size == fileSize) {\n                ++point;\n            }\n            if(item.taken == taken) {\n                ++point;\n            }\n            if(point > maxPoint) {\n                maxPoint = point;\n                maxItem = item;\n            }\n        }\n        if(maxItem != null) {\n            this.generateThumbnails(maxItem.id);\n            return ContentUris.withAppendedId(Media.EXTERNAL_CONTENT_URI, maxItem.id);\n        } else {\n            return null;\n        }\n    }\n\n    private Uri storeImage(File file) {\n        try {\n            ContentValues e = new ContentValues();\n            e.put(\"title\", file.getName());\n            e.put(\"mime_type\", \"image/jpeg\");\n            e.put(\"description\", \"mixi Photo\");\n            e.put(\"orientation\", Integer.valueOf(ExifInterfaceCompat.getExifOrientation(file.getAbsolutePath())));\n            long date = ExifInterfaceCompat.getExifDateTimeInMillis(file.getAbsolutePath());\n            if(date != -1L) {\n                e.put(\"datetaken\", Long.valueOf(date));\n            }\n\n            Uri imageUri = this.mContext.getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, e);\n            FileOutputStream fos = (FileOutputStream)this.mContext.getContentResolver().openOutputStream(imageUri);\n            FileInputStream fis = new FileInputStream(file);\n            copyFileStream(fis, fos);\n            fos.close();\n            fis.close();\n            this.generateThumbnails(ContentUris.parseId(imageUri));\n            return imageUri;\n        } catch (Exception e) {\n            Log.w(TAG, \"cannot insert\", e);\n            return null;\n        }\n    }\n\n    private void updateLatestPhotos() {\n        Cursor c = Media.query(this.mContext.getContentResolver(), Media.EXTERNAL_CONTENT_URI, new String[]{\"_id\", \"datetaken\", \"_size\"}, (String)null, (String[])null, \"date_added DESC\");\n        if(c != null) {\n            try {\n                int count = 0;\n                this.mRecentlyUpdatedPhotos = new ArrayList();\n\n                while(c.moveToNext()) {\n                    MediaStoreCompat.PhotoContent item = new MediaStoreCompat.PhotoContent();\n                    item.id = c.getLong(0);\n                    item.taken = c.getLong(1);\n                    item.size = c.getInt(2);\n                    this.mRecentlyUpdatedPhotos.add(item);\n                    ++count;\n                    if(count > 5) {\n                        break;\n                    }\n                }\n            } finally {\n                c.close();\n            }\n        }\n    }\n\n    private void generateThumbnails(long imageId) {\n        try {\n            Thumbnails.getThumbnail(this.mContext.getContentResolver(), imageId, 1, (Options)null);\n        } catch (NullPointerException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @TargetApi(8)\n    private File getOutputFileUri() {\n        File extDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), this.MEDIA_FILE_DIRECTORY);\n        if(!extDir.exists() && !extDir.mkdirs()) {\n            return null;\n        } else {\n            String timeStamp = (new SimpleDateFormat(MEDIA_FILE_NAME_FORMAT)).format(new Date());\n            return new File(extDir.getPath() + File.separator + MEDIA_FILE_PREFIX + timeStamp + MEDIA_FILE_EXTENSION);\n        }\n    }\n\n    private static class PhotoContent {\n        public long id;\n        public long taken;\n        public int size;\n\n        private PhotoContent() {\n        }\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/ParcelUtils.java",
    "content": "package io.valuesfeng.picker.utils;\n\nimport android.os.Parcel;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.util.Date;\n\n/**\n */\npublic class ParcelUtils {\n    private static final int FALSE = 0;\n    private static final int TRUE = 1;\n    private static final byte MARKER_NO_ELEMENT_STORED = 0;\n    private static final byte MARKER_AN_ELEMENT_STORED = 1;\n\n    private ParcelUtils() {\n    }\n\n    public static void writeBoolean(Parcel dest, boolean bool) {\n        dest.writeInt(bool ? 1 : 0);\n    }\n\n    public static boolean readBoolean(Parcel source) {\n        return source.readInt() == 1;\n    }\n\n    public static void writeDate(Parcel parcel, Date date) {\n        if (parcel != null) {\n            parcel.writeByte((byte) (date == null ? 0 : 1));\n            if (date != null) {\n                parcel.writeLong(date.getTime());\n            }\n        }\n    }\n\n    public static Date readDate(Parcel parcel) {\n        byte isADateStored = parcel.readByte();\n        return isADateStored == 1 ? new Date(parcel.readLong()) : null;\n    }\n\n    public static java.lang.Object byteToObject(byte[] bytes) {\n        java.lang.Object obj = null;\n        try {\n            //bytearray to object\n            ByteArrayInputStream bi = new ByteArrayInputStream(bytes);\n            ObjectInputStream oi = new ObjectInputStream(bi);\n            obj = oi.readObject();\n\n            bi.close();\n            oi.close();\n        } catch (Exception e) {\n            System.out.println(\"translation\" + e.getMessage());\n            e.printStackTrace();\n        }\n        return obj;\n    }\n\n    public byte[] ObjectToByte(java.lang.Object obj)\n    {\n        byte[] bytes = null;\n        try {\n            //object to bytearray\n            ByteArrayOutputStream bo = new ByteArrayOutputStream();\n            ObjectOutputStream oo = new ObjectOutputStream(bo);\n            oo.writeObject(obj);\n\n            bytes = bo.toByteArray();\n\n            bo.close();\n            oo.close();\n        }\n        catch(Exception e) {\n            System.out.println(\"translation\"+e.getMessage());\n            e.printStackTrace();\n        }\n        return(bytes);\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/PhotoMetadataUtils.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.utils;\n\nimport android.app.Activity;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Point;\nimport android.media.ExifInterface;\nimport android.net.Uri;\nimport android.provider.MediaStore;\nimport android.util.DisplayMetrics;\nimport android.util.Log;\n\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport io.valuesfeng.picker.MimeType;\nimport io.valuesfeng.picker.model.SelectionSpec;\n\n/**\n */\npublic final class PhotoMetadataUtils {\n    public static final String TAG = PhotoMetadataUtils.class.getSimpleName();\n    private static final String SCHEME_CONTENT = \"content\";\n\n    private PhotoMetadataUtils() {\n        throw new AssertionError(\"oops! the utility class is about to be instantiated...\");\n    }\n\n    public static int getPixelsCount(ContentResolver resolver, Uri uri) {\n        Point size = getBitmapBound(resolver, uri);\n        return size.x * size.y;\n    }\n\n    public static Point getBitmapSize(ContentResolver resolver, Uri uri, Activity activity) {\n        Point imageSize = getBitmapBound(resolver, uri);\n        int w = imageSize.x;\n        int h = imageSize.y;\n        if (PhotoMetadataUtils.shouldRotate(resolver, uri)) {\n            w = imageSize.y;\n            h = imageSize.x;\n        }\n        DisplayMetrics metrics = new DisplayMetrics();\n        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);\n        float screenWidth = (float) metrics.widthPixels;\n        float screenHeight = (float) metrics.heightPixels;\n        float widthScale = screenWidth / w;\n        float heightScale = screenHeight / h;\n        if (widthScale > heightScale) {\n            return new Point((int) (w * widthScale), (int)(h * heightScale));\n        }\n        return new Point((int) (w * widthScale), (int) (h * heightScale));\n    }\n\n    public static Point getBitmapBound(ContentResolver resolver, Uri uri) {\n        InputStream is = null;\n        try {\n            BitmapFactory.Options options = new BitmapFactory.Options();\n            options.inJustDecodeBounds = true;\n            is = resolver.openInputStream(uri);\n            BitmapFactory.decodeStream(is, null, options);\n            int width = options.outWidth;\n            int height = options.outHeight;\n            return new Point(width, height);\n        } catch (FileNotFoundException e) {\n            return new Point(0, 0);\n        } finally {\n            CloseableUtils.close(is);\n        }\n    }\n\n    public static String getPath(ContentResolver resolver, Uri uri) {\n        if (uri == null) {\n            return null;\n        }\n\n        if (SCHEME_CONTENT.equals(uri.getScheme())) {\n            Cursor cursor = null;\n            try {\n                cursor = resolver.query(uri, new String[] { MediaStore.Images.ImageColumns.DATA }, null, null, null);\n                if (cursor == null || !cursor.moveToFirst()) {\n                    return null;\n                }\n                return cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA));\n            } finally {\n                if(cursor != null) {\n                    cursor.close();\n                }\n            }\n        }\n        return uri.getPath();\n    }\n\n//    public static UncapableCause isAcceptable(Context context, SelectionSpec spec, Uri uri) {\n//        if (!isSelectableType(context, spec, uri)) {\n//            return UncapableCause.FILE_TYPE;\n//        }\n//        if (!hasUnderAtMostQuality(context, spec, uri)) {\n//            return UncapableCause.OVER_COUNT;\n//        }\n//        if (!hasOverAtLeastQuality(context, spec, uri)) {\n//            return UncapableCause.UNDER_QUALITY;\n//        }\n//        return null;\n//    }\n\n    public static boolean hasOverAtLeastQuality(Context context, SelectionSpec spec, Uri uri) {\n        if (context == null) {\n            return false;\n        }\n\n        int pixels = PhotoMetadataUtils.getPixelsCount(context.getContentResolver(), uri);\n        return spec.getMinPixels() <= pixels;\n    }\n\n    public static boolean hasUnderAtMostQuality(Context context, SelectionSpec spec, Uri uri) {\n        if (context == null) {\n            return false;\n        }\n\n        int pixels = PhotoMetadataUtils.getPixelsCount(context.getContentResolver(), uri);\n        return pixels <= spec.getMaxPixels();\n    }\n\n    public static boolean isSelectableType(Context context, SelectionSpec spec, Uri uri) {\n        if (context == null) {\n            return false;\n        }\n\n        ContentResolver resolver = context.getContentResolver();\n        for (MimeType type : spec.getMimeTypeSet()) {\n            if (type.checkType(resolver, uri)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static boolean shouldRotate(ContentResolver resolver, Uri uri) {\n        ExifInterface exif;\n        try {\n            exif = ExifInterfaceCompat.newInstance(getPath(resolver, uri));\n        } catch (IOException e) {\n            Log.e(TAG, \"could not read exif info of the image: \" + uri);\n            return false;\n        }\n        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);\n        return orientation == ExifInterface.ORIENTATION_ROTATE_90\n                || orientation == ExifInterface.ORIENTATION_ROTATE_270;\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/utils/PicturePickerUtils.java",
    "content": "package io.valuesfeng.picker.utils;\n\nimport android.app.Activity;\nimport android.content.ContentResolver;\nimport android.content.Intent;\nimport android.net.Uri;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.valuesfeng.picker.ImageSelectActivity;\n\n/**\n * Created by zaiyong on 2015/6/6.\n */\npublic class PicturePickerUtils {\n\n    private PicturePickerUtils() {\n    }\n\n    /**\n     * Obtains the selection result passed to your {@link Activity#onActivityResult(int, int, Intent)}.\n     *\n     * @param data the data.\n     * @return the selected {@link Uri}s.\n     */\n    public static List<Uri> obtainResult(Intent data) {\n        return data.getParcelableArrayListExtra(ImageSelectActivity.EXTRA_RESULT_SELECTION);\n    }\n\n    public static List<String> obtainResult(ContentResolver resolver, Intent data) {\n        List<Uri> uris = data.getParcelableArrayListExtra(ImageSelectActivity.EXTRA_RESULT_SELECTION);\n        List<String> paths = new ArrayList<>();\n        for (Uri uri : uris) {\n            paths.add(PhotoMetadataUtils.getPath(resolver, uri));\n        }\n        return paths;\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/java/io/valuesfeng/picker/widget/GridViewItemRelativeLayout.java",
    "content": "/*\n * Copyright (C) 2014 nohana, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage io.valuesfeng.picker.widget;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.graphics.PorterDuff;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.RelativeLayout;\n\nimport com.nostra13.universalimageloader.core.DisplayImageOptions;\nimport com.nostra13.universalimageloader.core.ImageLoader;\nimport com.nostra13.universalimageloader.core.assist.ImageScaleType;\n\nimport io.valuesfeng.picker.ImageSelectActivity;\nimport io.valuesfeng.picker.R;\nimport io.valuesfeng.picker.control.SelectedUriCollection;\nimport io.valuesfeng.picker.model.Picture;\n\n/**\n * @author KeithYokoma\n * @version 1.0.0\n * @hide\n * @since 2014/03/24\n */\npublic class GridViewItemRelativeLayout extends RelativeLayout {\n\n    private ImageView imageView;\n    private ImageView imageCheck;\n    private Picture item;\n    SelectedUriCollection mCollection;\n\n    public GridViewItemRelativeLayout(Context context) {\n        this(context, null);\n    }\n\n    public GridViewItemRelativeLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public GridViewItemRelativeLayout(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, widthMeasureSpec);\n    }\n\n    public void setImageView(ImageView imageView, ImageView imageCheck, SelectedUriCollection mCollection) {\n        this.imageView = imageView;\n        this.imageView.setMinimumWidth(getWidth());\n        this.imageView.setMinimumHeight(getHeight());\n        this.imageCheck = imageCheck;\n        this.mCollection = mCollection;\n        this.imageView.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if (GridViewItemRelativeLayout.this.mCollection.isCountOver()\n                        && !GridViewItemRelativeLayout.this.mCollection.isSelected(item.buildContentUri())) {\n                    return;\n                }\n                if (item.isCapture()) {\n                    ((ImageSelectActivity) getContext()).showCameraAction();\n                    return;\n                } else if (GridViewItemRelativeLayout.this.mCollection.isSingleChoose()) {\n                    GridViewItemRelativeLayout.this.mCollection.add(item.buildContentUri());\n                    ((ImageSelectActivity) getContext()).setResult();\n                    return;\n                }\n                if (GridViewItemRelativeLayout.this.mCollection.isSelected(item.buildContentUri())) {\n                    GridViewItemRelativeLayout.this.mCollection.remove(item.buildContentUri());\n                    GridViewItemRelativeLayout.this.imageCheck.setImageResource(R.drawable.pick_photo_checkbox_normal);\n                    GridViewItemRelativeLayout.this.imageView.clearColorFilter();\n                } else {\n                    GridViewItemRelativeLayout.this.mCollection.add(item.buildContentUri());\n                    GridViewItemRelativeLayout.this.imageCheck.setImageResource(R.drawable.pick_photo_checkbox_check);\n                    GridViewItemRelativeLayout.this.imageView.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);\n                }\n            }\n        });\n    }\n\n    public void setItem(Picture item) {\n        this.item = item;\n        imageView.clearColorFilter();\n        imageCheck.setImageResource(R.drawable.pick_photo_checkbox_normal);\n        if (mCollection.isSelected(item.buildContentUri())) {\n            imageView.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);\n            imageCheck.setImageResource(R.drawable.pick_photo_checkbox_check);\n        }\n        imageCheck.setVisibility(mCollection.isSingleChoose() || item.isCapture() ? View.GONE : View.VISIBLE);\n        disPlay();\n    }\n\n    private void disPlay() {\n        if (item.isCapture()) {\n            mCollection.getEngine().displayCameraItem(imageView);\n//            ImageLoader.getInstance().displayImage(\"drawable://\" +, imageView, optionsCameraImage);\n        } else {\n            mCollection.getEngine().displayImage(item.buildContentUri().toString(), imageView);\n//            if (AlbumHelper.getInstance(getContext()).getThumbnail().containsKey(item.getId())) {\n//                String thumbnailuri = AlbumHelper.getInstance(getContext()).getThumbnail().get(item.getId());\n//                File file = new File(thumbnailuri);\n//                thumbnailuri = file.exists() && file.isFile() ? \"file://\" + thumbnailuri : item.buildContentUri().toString();\n//                ImageLoader.getInstance().displayImage(\"file://\" + thumbnailuri, imageView, optionsImage);\n//            } else {\n//                ImageLoader.getInstance().displayImage(item.buildContentUri().toString(), imageView, optionsImage);\n//            }\n//            ImageLoader.getInstance().displayImage(item.buildContentUri().toString(), imageView, optionsImage);\n        }\n    }\n}\n"
  },
  {
    "path": "gallery/src/main/res/anim/listview_down.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <translate\n        android:duration=\"200\"\n        android:fromYDelta=\"0%\"\n        android:toYDelta=\"-100%\" />\n\n\n</set>"
  },
  {
    "path": "gallery/src/main/res/anim/listview_fade_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <alpha\n        android:duration=\"200\"\n        android:toAlpha=\"1\"\n        android:fromAlpha=\"0\" />\n</set>"
  },
  {
    "path": "gallery/src/main/res/anim/listview_fade_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <alpha\n        android:duration=\"200\"\n        android:fromAlpha=\"1\"\n        android:toAlpha=\"0\" />\n</set>"
  },
  {
    "path": "gallery/src/main/res/anim/listview_up.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <translate\n        android:duration=\"200\"\n        android:fromYDelta=\"-100%\"\n        android:toYDelta=\"0%\" />\n</set>"
  },
  {
    "path": "gallery/src/main/res/drawable/pick_photo_checkbox.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_checked=\"true\" android:drawable=\"@drawable/pick_photo_checkbox_check\" />\n    <item android:state_checked=\"false\" android:drawable=\"@drawable/pick_photo_checkbox_normal\" />\n    <item android:drawable=\"@drawable/pick_photo_checkbox_normal\" />\n\n</selector>"
  },
  {
    "path": "gallery/src/main/res/layout/activity_image_select.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <include\n        android:id=\"@+id/top_layout\"\n        layout=\"@layout/include_select_image_top\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?android:attr/actionBarSize\" />\n\n    <GridView\n        android:id=\"@+id/gridView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_below=\"@+id/top_layout\"\n        android:background=\"@android:color/white\"\n        android:gravity=\"center\"\n        android:horizontalSpacing=\"4dip\"\n        android:numColumns=\"3\"\n        android:padding=\"4dip\"\n        android:stretchMode=\"columnWidth\"\n        android:verticalSpacing=\"4dip\" />\n\n    <FrameLayout\n        android:id=\"@+id/listViewParent\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_below=\"@+id/top_layout\"\n        android:background=\"#40000000\"\n        android:paddingBottom=\"45dp\"\n        android:visibility=\"invisible\">\n\n        <ListView\n            android:id=\"@+id/listView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"#55666666\"\n            android:divider=\"@null\"\n            android:dividerHeight=\"0dp\" />\n    </FrameLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "gallery/src/main/res/layout/activity_main.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\" tools:context=\".MainActivity\">\n\n    <TextView android:text=\"@string/hello_world\" android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "gallery/src/main/res/layout/include_select_image_top.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/rl_top\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@color/top_bg\">\n\n    <ImageView\n        android:id=\"@+id/btn_back\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_centerVertical=\"true\"\n        android:paddingLeft=\"17dp\"\n        android:paddingRight=\"20dp\"\n        android:scaleType=\"center\"\n        android:src=\"@drawable/gallery_back\" />\n\n    <LinearLayout\n        android:id=\"@+id/selectFold\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_centerInParent=\"true\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"20dp\"\n        android:paddingRight=\"20dp\">\n\n        <TextView\n            android:id=\"@+id/foldName\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:text=\"选择\"\n            android:textColor=\"#d6d6d6\"\n            android:textSize=\"14dp\" />\n\n        <ImageView\n            android:id=\"@+id/gallery_tip\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginLeft=\"5dp\"\n            android:src=\"@drawable/gallery_down\" />\n    </LinearLayout>\n\n    <Button\n        android:id=\"@+id/commit\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:layout_marginRight=\"10dp\"\n        android:background=\"@null\"\n        android:minHeight=\"1dp\"\n        android:minWidth=\"1dp\"\n        android:paddingBottom=\"5dp\"\n        android:paddingLeft=\"10dp\"\n        android:paddingRight=\"10dp\"\n        android:paddingTop=\"5dp\"\n        android:text=\"确定(3/4)\"\n        android:textColor=\"#d6d6d6\"\n        android:textSize=\"14dp\" />\n\n</RelativeLayout>"
  },
  {
    "path": "gallery/src/main/res/layout/photopick_gridlist_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<io.valuesfeng.picker.widget.GridViewItemRelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/rl\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/thumbnail\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"centerCrop\" />\n\n    <ImageView\n        android:id=\"@+id/check\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:layout_alignParentRight=\"true\"\n        android:button=\"@drawable/pick_photo_checkbox\" />\n\n</io.valuesfeng.picker.widget.GridViewItemRelativeLayout>"
  },
  {
    "path": "gallery/src/main/res/layout/photopick_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"50dp\"\n    android:background=\"#161616\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"49.5dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingLeft=\"28dp\"\n        android:paddingRight=\"10dp\">\n            <TextView\n                android:id=\"@+id/foldName\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textSize=\"14dp\"\n                android:textColor=\"#a7a7a7\"\n                android:text=\"相机胶卷\" />\n\n            <TextView\n                android:id=\"@+id/photoCount\"\n                android:textSize=\"14dp\"\n                android:textColor=\"#a7a7a7\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"(100)\" />\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"#1d1d1d\" />\n</LinearLayout>\n"
  },
  {
    "path": "gallery/src/main/res/menu/menu_main.xml",
    "content": "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\" tools:context=\".MainActivity\">\n    <item android:id=\"@+id/action_settings\" android:title=\"@string/action_settings\"\n        android:orderInCategory=\"100\" app:showAsAction=\"never\" />\n</menu>\n"
  },
  {
    "path": "gallery/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"top_bg\">#0f0f0f</color>\n</resources>"
  },
  {
    "path": "gallery/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"l_gridItemImageWidth\">56dp</dimen>\n    <dimen name=\"l_gridItemImageHeight\">56dp</dimen>\n</resources>\n"
  },
  {
    "path": "gallery/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">gallery</string>\n\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"l_album_name_all\">最近图片</string>\n    <string name=\"l_album_name_selected\">选择图片</string>\n    <string name=\"l_album_name_camera\">相机</string>\n    <string name=\"l_album_name_download\">下载</string>\n    <string name=\"l_album_name_screen_shot\">屏幕截图</string>\n    <string name=\"l_album_name_confirm\">确定</string>\n    <string name=\"l_album_name_unselected_picture\">未选择图片</string>\n    <string name=\"l_confirm_dialog_title\">提示</string>\n    <string name=\"l_confirm_dialog_message\">您确定要放弃本次选择的图片吗?</string>\n</resources>\n"
  },
  {
    "path": "gallery/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "gallery/src/main/res/values-en/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">gallery</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"l_album_name_all\">All</string>\n    <string name=\"l_album_name_camera\">Camera</string>\n    <string name=\"l_album_name_download\">Downloads</string>\n    <string name=\"l_album_name_screen_shot\">Screenshot</string>\n    <string name=\"l_album_name_selected\">Selected</string>\n    <string name=\"l_album_name_confirm\">Confirm</string>\n    <string name=\"l_album_name_unselected_picture\">Unselected</string>\n    <string name=\"l_confirm_dialog_message\">Do you want to give up this image selection?</string>\n    <string name=\"l_confirm_dialog_title\">Done</string>\n</resources>"
  },
  {
    "path": "gallery/src/main/res/values-ja/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">gallery</string>\n    <string name=\"hello_world\">Hello world!</string>\n    <string name=\"action_settings\">Settings</string>\n    <string name=\"l_album_name_all\">最近の写真</string>\n    <string name=\"l_album_name_selected\">画像を選択</string>\n    <string name=\"l_album_name_camera\">カメラ</string>\n    <string name=\"l_album_name_download\">ダウンロード</string>\n    <string name=\"l_album_name_screen_shot\">スクリーンショット</string>\n    <string name=\"l_album_name_confirm\">確定する</string>\n    <string name=\"l_album_name_unselected_picture\">画像を選択していない</string>\n    <string name=\"l_confirm_dialog_title\">ヒント</string>\n    <string name=\"l_confirm_dialog_message\">あなたは今回選択した画像を放棄することを決定しますか？</string>\n</resources>\n"
  },
  {
    "path": "gallery/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">galeria</string>\n    <string name=\"action_settings\">Configurações</string>\n    <string name=\"l_album_name_all\">Todos</string>\n    <string name=\"l_album_name_camera\">Camera</string>\n    <string name=\"l_album_name_download\">Downloads</string>\n    <string name=\"l_album_name_screen_shot\">Capturas de tela</string>\n    <string name=\"l_album_name_selected\">Selecionadas</string>\n    <string name=\"l_confirm_dialog_message\">Deseja desistir da seleção de imagens?</string>\n    <string name=\"l_confirm_dialog_title\">Concluir</string>\n</resources>"
  },
  {
    "path": "gallery/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Apr 10 15:27:10 PDT 2013\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.2.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':gallery'\n"
  }
]