├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ └── layout │ │ │ │ ├── list_item.xml │ │ │ │ └── activity_main.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── hc │ │ │ └── gallery │ │ │ └── util │ │ │ ├── StorageType.java │ │ │ ├── StorageUtil.java │ │ │ └── ExternalStorage.java │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── hc │ │ │ └── gallery │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── hc │ │ └── gallery │ │ └── ExampleInstrumentedTest.java ├── proguard-rules.pro └── build.gradle ├── gallery ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── drawable-xhdpi │ │ │ ├── checkbig.png │ │ │ ├── flash_on.png │ │ │ ├── ic_done.png │ │ │ ├── system.9.png │ │ │ ├── camera_btn.png │ │ │ ├── flash_auto.png │ │ │ ├── flash_off.png │ │ │ ├── ic_ab_back.png │ │ │ ├── nophotos.9.png │ │ │ ├── photo_crop.png │ │ │ ├── search_gif.png │ │ │ ├── search_web.png │ │ │ ├── header_shadow.png │ │ │ ├── ic_ab_other.png │ │ │ ├── ic_ab_search.png │ │ │ ├── layer_shadow.png │ │ │ ├── photobadge.9.png │ │ │ ├── popup_fixed.9.png │ │ │ ├── tool_rotate.png │ │ │ ├── camera_revert1.png │ │ │ ├── camera_revert2.png │ │ │ ├── ic_close_white.png │ │ │ ├── photobadge_new.png │ │ │ ├── ic_arrow_drop_down.png │ │ │ ├── selectphoto_large.png │ │ │ └── photoview_placeholder.png │ │ ├── values │ │ │ ├── values.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── drawable-hdpi │ │ │ └── ic_arrow_drop_down.png │ │ ├── drawable-mdpi │ │ │ └── ic_arrow_drop_down.png │ │ ├── anim │ │ │ ├── no_animation.xml │ │ │ ├── bottom_menu_enter.xml │ │ │ ├── bottom_menu_exit.xml │ │ │ ├── popup_in.xml │ │ │ ├── popup_out.xml │ │ │ ├── icon_anim_fade_in.xml │ │ │ └── icon_anim_fade_out.xml │ │ ├── drawable │ │ │ ├── transparent.xml │ │ │ ├── dialog_center_background.xml │ │ │ ├── dialog_text_background.xml │ │ │ ├── search_carret.xml │ │ │ ├── dialog_text_bottom_background.xml │ │ │ ├── bar_selector_style.xml │ │ │ └── list_selector.xml │ │ ├── layout │ │ │ ├── activity_gallery.xml │ │ │ ├── layout_media_loading.xml │ │ │ ├── layout_dialog_base.xml │ │ │ └── dialog_layout.xml │ │ ├── drawable-v21 │ │ │ └── list_selector.xml │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ ├── values-zh │ │ │ └── strings.xml │ │ └── values-pl │ │ │ └── strings.xml │ │ ├── java │ │ └── com │ │ │ └── dhc │ │ │ └── gallery │ │ │ ├── utils │ │ │ ├── Gallery.java │ │ │ ├── DispatchQueue.java │ │ │ ├── LayoutHelper.java │ │ │ └── NotificationCenter.java │ │ │ ├── proxy │ │ │ └── AnimatorListenerAdapterProxy.java │ │ │ ├── BaseFragmentAdapter.java │ │ │ ├── tl │ │ │ ├── TLObject.java │ │ │ ├── TLUploadFile.java │ │ │ ├── AbstractSerializedData.java │ │ │ ├── GeoPoint.java │ │ │ ├── InputFile.java │ │ │ ├── InputStickerSet.java │ │ │ ├── InputFileLocation.java │ │ │ ├── FileLocation.java │ │ │ ├── InputEncryptedFile.java │ │ │ ├── PhotoSize.java │ │ │ ├── StorageFileType.java │ │ │ └── Photo.java │ │ │ ├── camera │ │ │ ├── CameraInfo.java │ │ │ └── Size.java │ │ │ ├── components │ │ │ ├── SizeNotifierFrameLayoutPhoto.java │ │ │ ├── AspectRatioFrameLayout.java │ │ │ ├── BackupImageView.java │ │ │ ├── PickerBottomLayout.java │ │ │ ├── PhotoPickerPhotoCell.java │ │ │ ├── PhotoPickerSearchCell.java │ │ │ ├── PhotoPickerAlbumsCell.java │ │ │ ├── BaseDialog.java │ │ │ └── ClippingImageView.java │ │ │ ├── Theme.java │ │ │ ├── actionbar │ │ │ ├── MenuDrawable.java │ │ │ ├── BackDrawable.java │ │ │ └── ActionBarMenu.java │ │ │ ├── GalleryConfig.java │ │ │ └── GalleryHelper.java │ │ └── AndroidManifest.xml └── build.gradle ├── settings.gradle ├── gif ├── video.gif ├── photos.gif ├── photocrop.gif └── selectcrop.gif ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradle.properties ├── gradlew.bat ├── gradlew └── README.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /gallery/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':gallery' 2 | -------------------------------------------------------------------------------- /gif/video.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gif/video.gif -------------------------------------------------------------------------------- /gif/photos.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gif/photos.gif -------------------------------------------------------------------------------- /gif/photocrop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gif/photocrop.gif -------------------------------------------------------------------------------- /gif/selectcrop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gif/selectcrop.gif -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | KrGallery 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/checkbig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/checkbig.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/flash_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/flash_on.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/ic_done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/ic_done.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/system.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/system.9.png -------------------------------------------------------------------------------- /gallery/src/main/res/values/values.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/camera_btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/camera_btn.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/flash_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/flash_auto.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/flash_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/flash_off.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/ic_ab_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/ic_ab_back.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/nophotos.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/nophotos.9.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/photo_crop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/photo_crop.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/search_gif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/search_gif.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/search_web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/search_web.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/header_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/header_shadow.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/ic_ab_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/ic_ab_other.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/ic_ab_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/ic_ab_search.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/layer_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/layer_shadow.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/photobadge.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/photobadge.9.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/popup_fixed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/popup_fixed.9.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/tool_rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/tool_rotate.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/camera_revert1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/camera_revert1.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/camera_revert2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/camera_revert2.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/ic_close_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/ic_close_white.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/photobadge_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/photobadge_new.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-hdpi/ic_arrow_drop_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-hdpi/ic_arrow_drop_down.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-mdpi/ic_arrow_drop_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-mdpi/ic_arrow_drop_down.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/ic_arrow_drop_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/ic_arrow_drop_down.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/selectphoto_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/selectphoto_large.png -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-xhdpi/photoview_placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chengzichen/KrGallery/HEAD/gallery/src/main/res/drawable-xhdpi/photoview_placeholder.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | /.idea 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /gallery/src/main/res/anim/no_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable/transparent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /gallery/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #dcdcdc 4 | #000000 5 | 6 | -------------------------------------------------------------------------------- /gallery/src/main/res/anim/bottom_menu_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /gallery/src/main/res/anim/bottom_menu_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable/dialog_center_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /gallery/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /gallery/src/main/res/layout/activity_gallery.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable-v21/list_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable/dialog_text_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable/search_carret.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable/dialog_text_bottom_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /gallery/src/main/res/anim/popup_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /gallery/src/main/res/anim/popup_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /gallery/src/main/res/anim/icon_anim_fade_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /gallery/src/main/res/anim/icon_anim_fade_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /gallery/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /gallery/src/main/res/layout/layout_media_loading.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/test/java/com/hc/gallery/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.hc.gallery; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 13 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/utils/Gallery.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.utils; 3 | 4 | import android.app.Application; 5 | import android.os.Handler; 6 | 7 | public class Gallery { 8 | 9 | public volatile static Application applicationContext; 10 | public volatile static Handler applicationHandler; 11 | 12 | public static void init(Application application) { 13 | if (applicationContext == null) { 14 | applicationContext = application; 15 | applicationHandler = new Handler(application.getMainLooper()); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable/bar_selector_style.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\android-sdk-studio/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /gallery/src/main/res/drawable/list_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/proxy/AnimatorListenerAdapterProxy.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.proxy; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | 6 | public class AnimatorListenerAdapterProxy extends AnimatorListenerAdapter { 7 | 8 | @Override 9 | public void onAnimationCancel(Animator animator) { 10 | 11 | } 12 | 13 | @Override 14 | public void onAnimationEnd(Animator animator) { 15 | 16 | } 17 | 18 | @Override 19 | public void onAnimationRepeat(Animator animator) { 20 | 21 | } 22 | 23 | @Override 24 | public void onAnimationStart(Animator animator) { 25 | 26 | } 27 | 28 | @Override 29 | public void onAnimationPause(Animator animator) { 30 | 31 | } 32 | 33 | @Override 34 | public void onAnimationResume(Animator animator) { 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/hc/gallery/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.hc.gallery; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.hc.gallery", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/BaseFragmentAdapter.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery; 2 | 3 | import android.database.DataSetObserver; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | import android.widget.BaseAdapter; 7 | 8 | public class BaseFragmentAdapter extends BaseAdapter { 9 | 10 | @Override 11 | public int getCount() { 12 | return 0; 13 | } 14 | 15 | @Override 16 | public Object getItem(int i) { 17 | return null; 18 | } 19 | 20 | @Override 21 | public long getItemId(int i) { 22 | return 0; 23 | } 24 | 25 | @Override 26 | public View getView(int i, View view, ViewGroup viewGroup) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public void unregisterDataSetObserver(DataSetObserver observer) { 32 | if (observer != null) { 33 | super.unregisterDataSetObserver(observer); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /gallery/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /gallery/src/main/res/layout/layout_dialog_base.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | 17 | 22 | 23 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /gallery/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.novoda.bintray-release'//添加 3 | android { 4 | 5 | compileSdkVersion 25 6 | buildToolsVersion "25.0.2" 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | lintOptions { 14 | abortOnError false 15 | } 16 | buildTypes { 17 | release { 18 | zipAlignEnabled true 19 | shrinkResources true 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile 'com.android.support:support-fragment:25.3.1' 28 | // compile 'com.google.android.exoplayer:exoplayer:r2.4.0' 29 | } 30 | 31 | //添加 32 | publish { 33 | userOrg = 'chengzichen'//bintray.com用户名 34 | groupId = 'com.dhc.krgallery'//jcenter上的路径 35 | artifactId = 'gallerylib'//项目名称 36 | publishVersion = '1.0.3'//版本号 37 | desc = 'Oh hi, this is Crop , Video, Photos, from Telegram'//描述,不重要 38 | website = 'https://github.com/chengzichen/KrGallery'//网站,不重要 39 | } -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.hc.gallery" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | lintOptions { 15 | abortOnError false 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(include: ['*.jar'], dir: 'libs') 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | compile 'com.android.support:appcompat-v7:25.3.1' 31 | testCompile 'junit:junit:4.12' 32 | compile (project(':gallery')){ 33 | exclude module:"support-fragment" 34 | } 35 | compile 'com.yanzhenjie:permission:1.0.5' 36 | } 37 | -------------------------------------------------------------------------------- /gallery/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 图片 4 | 视频 5 | 所有图片 6 | 所有视频 7 | 还没有图片 8 | 还没有视频 9 | 剪切 10 | 图片 11 | %1$d / %2$d 12 | 设置 13 | 相册 14 | 15 | 你最多只能选择%d张图片 16 | 17 | 完成 18 | 取消 19 | 预览 20 | 相册读取失败,请检查权限 21 | 视频文件大小为: %1$dKB, 22 | 视频文件大小为: %1$.2fMB, 23 | 视频已超限,大小为: %1$dKB, 24 | 视频已超限,大小为: %1$.2fMB, 25 | 是否发送该视频? 26 | 27 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/TLObject.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This is the source code of Telegram for Android v. 3.x.x. 3 | * It is licensed under GNU GPL v. 2 or later. 4 | * You should have received a copy of the license in this archive (see LICENSE). 5 | * 6 | * Copyright Nikolai Kudashov, 2013-2016. 7 | */ 8 | 9 | package com.dhc.gallery.tl; 10 | 11 | public class TLObject { 12 | 13 | public boolean disableFree = false; 14 | private static final ThreadLocal sizeCalculator = new ThreadLocal() { 15 | @Override 16 | protected NativeByteBuffer initialValue() { 17 | return new NativeByteBuffer(true); 18 | } 19 | }; 20 | 21 | public TLObject() { 22 | 23 | } 24 | 25 | public void readParams(AbstractSerializedData stream, boolean exception) { 26 | 27 | } 28 | 29 | public void serializeToStream(AbstractSerializedData stream) { 30 | 31 | } 32 | 33 | public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, 34 | boolean exception) { 35 | return null; 36 | } 37 | 38 | public void freeResources() { 39 | 40 | } 41 | 42 | public int getObjectSize() { 43 | NativeByteBuffer byteBuffer = sizeCalculator.get(); 44 | byteBuffer.rewind(); 45 | serializeToStream(sizeCalculator.get()); 46 | return byteBuffer.length(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/TLUploadFile.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class TLUploadFile extends TLObject { 5 | public static int constructor = 0x96a18d5; 6 | 7 | public StorageFileType type; 8 | public int mtime; 9 | public NativeByteBuffer bytes; 10 | 11 | public static TLUploadFile TLdeserialize(AbstractSerializedData stream, int constructor, 12 | boolean exception) { 13 | if (TLUploadFile.constructor != constructor) { 14 | if (exception) { 15 | throw new RuntimeException( 16 | String.format("can't parse magic %x in TLUploadFile", constructor)); 17 | } else { 18 | return null; 19 | } 20 | } 21 | TLUploadFile result = new TLUploadFile(); 22 | result.readParams(stream, exception); 23 | return result; 24 | } 25 | 26 | public void readParams(AbstractSerializedData stream, boolean exception) { 27 | type = StorageFileType.TLdeserialize(stream, stream.readInt32(exception), exception); 28 | mtime = stream.readInt32(exception); 29 | bytes = stream.readByteBuffer(exception); 30 | } 31 | 32 | @Override 33 | public void freeResources() { 34 | if (disableFree) { 35 | return; 36 | } 37 | if (bytes != null) { 38 | bytes.reuse(); 39 | bytes = null; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 24 | 25 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /gallery/src/main/res/values-pl/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Zdjęcia 4 | Filmy 5 | Wszystkie zdjęcia 6 | Wszystkie filmy 7 | Brak zdjęć 8 | Brak filmów 9 | ZNAJDŹ ZDJĘCIA 10 | ZNAJDŹ GIFY 11 | Brak ostatnich zdjęć 12 | Brak osatnich GIFów 13 | Brak wyników 14 | PRZYTNIJ 15 | Zdjęcie 16 | %1$d z %2$d 17 | Zbiór 18 | Album 19 | 20 | Wyczyścić historię wyszukiwania? 21 | Wyczyść 22 | 23 | Przeszukaj sieć 24 | Szukaj GIFów 25 | 26 | SZUKAJ W SIECI 27 | Możesz wybrać do %d zdjęć 28 | 29 | Akceptuj 30 | Anuluj 31 | Podgląd 32 | Bład odczytu, sprawdź uprawnienia 33 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/AbstractSerializedData.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.tl; 2 | 3 | public abstract class AbstractSerializedData { 4 | 5 | public abstract void writeInt32(int x); 6 | 7 | public abstract void writeInt64(long x); 8 | 9 | public abstract void writeBool(boolean value); 10 | 11 | public abstract void writeBytes(byte[] b); 12 | 13 | public abstract void writeBytes(byte[] b, int offset, int count); 14 | 15 | public abstract void writeByte(int i); 16 | 17 | public abstract void writeByte(byte b); 18 | 19 | public abstract void writeString(String s); 20 | 21 | public abstract void writeByteArray(byte[] b, int offset, int count); 22 | 23 | public abstract void writeByteArray(byte[] b); 24 | 25 | public abstract void writeDouble(double d); 26 | 27 | public abstract void writeByteBuffer(NativeByteBuffer buffer); 28 | 29 | public abstract int readInt32(boolean exception); 30 | 31 | public abstract boolean readBool(boolean exception); 32 | 33 | public abstract long readInt64(boolean exception); 34 | 35 | public abstract void readBytes(byte[] b, boolean exception); 36 | 37 | public abstract byte[] readData(int count, boolean exception); 38 | 39 | public abstract String readString(boolean exception); 40 | 41 | public abstract byte[] readByteArray(boolean exception); 42 | 43 | public abstract NativeByteBuffer readByteBuffer(boolean exception); 44 | 45 | public abstract double readDouble(boolean exception); 46 | 47 | public abstract int length(); 48 | 49 | public abstract void skip(int count); 50 | 51 | public abstract int getPosition(); 52 | } 53 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/camera/CameraInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This is the source code of Telegram for Android v. 3.x.x. 3 | * It is licensed under GNU GPL v. 2 or later. 4 | * You should have received a copy of the license in this archive (see LICENSE). 5 | * 6 | * Copyright Nikolai Kudashov, 2013-2017. 7 | */ 8 | 9 | package com.dhc.gallery.camera; 10 | 11 | import android.hardware.Camera; 12 | 13 | import java.util.ArrayList; 14 | 15 | public class CameraInfo { 16 | 17 | protected int cameraId; 18 | protected Camera camera; 19 | protected ArrayList pictureSizes = new ArrayList<>(); 20 | protected ArrayList previewSizes = new ArrayList<>(); 21 | protected final int frontCamera; 22 | 23 | public CameraInfo(int id, Camera.CameraInfo info) { 24 | cameraId = id; 25 | frontCamera = info.facing; 26 | } 27 | 28 | public int getCameraId() { 29 | return cameraId; 30 | } 31 | 32 | private Camera getCamera() { 33 | return camera; 34 | } 35 | 36 | public ArrayList getPreviewSizes() { 37 | return previewSizes; 38 | } 39 | 40 | public ArrayList getPictureSizes() { 41 | return pictureSizes; 42 | } 43 | 44 | /*private int getScore(CameraSelectionCriteria criteria) { 45 | int score = 10; 46 | if (criteria != null) { 47 | if ((criteria.getFacing().isFront() && frontCamera != Camera.CameraInfo.CAMERA_FACING_FRONT) || (!criteria.getFacing().isFront() && frontCamera != Camera.CameraInfo.CAMERA_FACING_BACK)) { 48 | score = 0; 49 | } 50 | } 51 | return (score); 52 | }*/ 53 | } 54 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/GeoPoint.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class GeoPoint extends TLObject { 5 | public double _long; 6 | public double lat; 7 | 8 | public static GeoPoint TLdeserialize(AbstractSerializedData stream, int constructor, 9 | boolean exception) { 10 | GeoPoint result = null; 11 | switch (constructor) { 12 | case 0x1117dd5f: 13 | result = new TL_geoPointEmpty(); 14 | break; 15 | case 0x2049d70c: 16 | result = new TL_geoPoint(); 17 | break; 18 | } 19 | if (result == null && exception) { 20 | throw new RuntimeException( 21 | String.format("can't parse magic %x in GeoPoint", constructor)); 22 | } 23 | if (result != null) { 24 | result.readParams(stream, exception); 25 | } 26 | return result; 27 | } 28 | 29 | public static class TL_geoPointEmpty extends GeoPoint { 30 | public static int constructor = 0x1117dd5f; 31 | 32 | public void serializeToStream(AbstractSerializedData stream) { 33 | stream.writeInt32(constructor); 34 | } 35 | } 36 | 37 | public static class TL_geoPoint extends GeoPoint { 38 | public static int constructor = 0x2049d70c; 39 | 40 | public void readParams(AbstractSerializedData stream, boolean exception) { 41 | _long = stream.readDouble(exception); 42 | lat = stream.readDouble(exception); 43 | } 44 | 45 | public void serializeToStream(AbstractSerializedData stream) { 46 | stream.writeInt32(constructor); 47 | stream.writeDouble(_long); 48 | stream.writeDouble(lat); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/hc/gallery/util/StorageType.java: -------------------------------------------------------------------------------- 1 | package com.hc.gallery.util; 2 | 3 | /** 4 | * 创建者:邓浩宸 5 | * 时间 :2017/4/20 13:01 6 | * 描述 :TODO 请描述该类职责 7 | */ 8 | public enum StorageType { 9 | TYPE_LOG(DirectoryName.LOG_DIRECTORY_NAME), 10 | TYPE_TEMP(DirectoryName.TEMP_DIRECTORY_NAME), 11 | TYPE_FILE(DirectoryName.FILE_DIRECTORY_NAME), 12 | TYPE_AUDIO(DirectoryName.AUDIO_DIRECTORY_NAME), 13 | TYPE_IMAGE(DirectoryName.IMAGE_DIRECTORY_NAME), 14 | TYPE_VIDEO(DirectoryName.VIDEO_DIRECTORY_NAME), 15 | TYPE_THUMB_IMAGE(DirectoryName.THUMB_DIRECTORY_NAME), 16 | TYPE_THUMB_VIDEO(DirectoryName.THUMB_DIRECTORY_NAME), 17 | ; 18 | private DirectoryName storageDirectoryName; 19 | private long storageMinSize; 20 | 21 | public String getStoragePath() { 22 | return storageDirectoryName.getPath(); 23 | } 24 | 25 | public long getStorageMinSize() { 26 | return storageMinSize; 27 | } 28 | 29 | StorageType(DirectoryName dirName) { 30 | this(dirName, StorageUtil.THRESHOLD_MIN_SPCAE); 31 | } 32 | 33 | StorageType(DirectoryName dirName, long storageMinSize) { 34 | this.storageDirectoryName = dirName; 35 | this.storageMinSize = storageMinSize; 36 | } 37 | 38 | enum DirectoryName { 39 | AUDIO_DIRECTORY_NAME("audio/"), 40 | DATA_DIRECTORY_NAME("data/"), 41 | FILE_DIRECTORY_NAME("file/"), 42 | LOG_DIRECTORY_NAME("log/"), 43 | TEMP_DIRECTORY_NAME("temp/"), 44 | IMAGE_DIRECTORY_NAME("image/"), 45 | THUMB_DIRECTORY_NAME("thumb/"), 46 | VIDEO_DIRECTORY_NAME("video/"), 47 | ; 48 | 49 | private String path; 50 | 51 | public String getPath() { 52 | return path; 53 | } 54 | 55 | private DirectoryName(String path) { 56 | this.path = path; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /gallery/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | KrGallery 4 | 5 | Photos 6 | Video 7 | All Photos 8 | All Videos 9 | No photos yet 10 | No videos yet 11 | FIND IMAGES 12 | FIND GIFS 13 | No recent photos 14 | No recent GIFs 15 | No results 16 | CROP 17 | Photo 18 | %1$d of %2$d 19 | Set 20 | Album 21 | 22 | Clear search history? 23 | Clear 24 | 25 | Search web 26 | Search GIFs 27 | 28 | WEB SEARCH 29 | You can select up to %d pictures 30 | 31 | Done 32 | Cancel 33 | Preview 34 | Failed to read an album, please check permissions 35 | 36 | 37 | 视频文件大小为: %1$dKB, 38 | 视频文件大小为: %1$.2fMB, 39 | 视频已超限,大小为: %1$dKB, 40 | 视频已超限,大小为: %1$.2fMB, 41 | 是否发送该视频? 42 | -------------------------------------------------------------------------------- /gallery/src/main/res/layout/dialog_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 20 | 21 | 25 | 26 | 30 | 31 | 39 | 40 | 44 | 45 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/utils/DispatchQueue.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.utils; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | import android.os.Message; 6 | 7 | import java.util.concurrent.CountDownLatch; 8 | 9 | public class DispatchQueue extends Thread { 10 | 11 | private volatile Handler handler = null; 12 | private CountDownLatch syncLatch = new CountDownLatch(1); 13 | 14 | public DispatchQueue(final String threadName) { 15 | setName(threadName); 16 | start(); 17 | } 18 | 19 | private void sendMessage(Message msg, int delay) { 20 | try { 21 | syncLatch.await(); 22 | if (delay <= 0) { 23 | handler.sendMessage(msg); 24 | } else { 25 | handler.sendMessageDelayed(msg, delay); 26 | } 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | 32 | public void cancelRunnable(Runnable runnable) { 33 | try { 34 | syncLatch.await(); 35 | handler.removeCallbacks(runnable); 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | public void postRunnable(Runnable runnable) { 42 | postRunnable(runnable, 0); 43 | } 44 | 45 | public void postRunnable(Runnable runnable, long delay) { 46 | try { 47 | syncLatch.await(); 48 | if (delay <= 0) { 49 | handler.post(runnable); 50 | } else { 51 | handler.postDelayed(runnable, delay); 52 | } 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | public void cleanupQueue() { 59 | try { 60 | syncLatch.await(); 61 | handler.removeCallbacksAndMessages(null); 62 | } catch (Exception e) { 63 | e.printStackTrace(); 64 | } 65 | } 66 | 67 | @Override 68 | public void run() { 69 | Looper.prepare(); 70 | handler = new Handler(); 71 | syncLatch.countDown(); 72 | Looper.loop(); 73 | } 74 | } -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/camera/Size.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This is the source code of Telegram for Android v. 3.x.x. 3 | * It is licensed under GNU GPL v. 2 or later. 4 | * You should have received a copy of the license in this archive (see LICENSE). 5 | * 6 | * Copyright Nikolai Kudashov, 2013-2017. 7 | */ 8 | 9 | package com.dhc.gallery.camera; 10 | 11 | public final class Size { 12 | 13 | public Size(int width, int height) { 14 | mWidth = width; 15 | mHeight = height; 16 | } 17 | 18 | public int getWidth() { 19 | return mWidth; 20 | } 21 | 22 | public int getHeight() { 23 | return mHeight; 24 | } 25 | 26 | @Override 27 | public boolean equals(final Object obj) { 28 | if (obj == null) { 29 | return false; 30 | } 31 | if (this == obj) { 32 | return true; 33 | } 34 | if (obj instanceof Size) { 35 | Size other = (Size) obj; 36 | return mWidth == other.mWidth && mHeight == other.mHeight; 37 | } 38 | return false; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return mWidth + "x" + mHeight; 44 | } 45 | 46 | private static NumberFormatException invalidSize(String s) { 47 | throw new NumberFormatException("Invalid Size: \"" + s + "\""); 48 | } 49 | 50 | public static Size parseSize(String string) throws NumberFormatException { 51 | int sep_ix = string.indexOf('*'); 52 | if (sep_ix < 0) { 53 | sep_ix = string.indexOf('x'); 54 | } 55 | if (sep_ix < 0) { 56 | throw invalidSize(string); 57 | } 58 | try { 59 | return new Size(Integer.parseInt(string.substring(0, sep_ix)), Integer.parseInt(string.substring(sep_ix + 1))); 60 | } catch (NumberFormatException e) { 61 | throw invalidSize(string); 62 | } 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2))); 68 | } 69 | 70 | private final int mWidth; 71 | private final int mHeight; 72 | } 73 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/SizeNotifierFrameLayoutPhoto.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.components; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.view.View; 6 | import android.view.WindowManager; 7 | import android.widget.FrameLayout; 8 | 9 | import com.dhc.gallery.utils.AndroidUtilities; 10 | 11 | public class SizeNotifierFrameLayoutPhoto extends FrameLayout { 12 | 13 | private Rect rect = new Rect(); 14 | private int keyboardHeight; 15 | private SizeNotifierFrameLayoutPhotoDelegate delegate; 16 | private WindowManager windowManager; 17 | 18 | public interface SizeNotifierFrameLayoutPhotoDelegate { 19 | void onSizeChanged(int keyboardHeight, boolean isWidthGreater); 20 | } 21 | 22 | public SizeNotifierFrameLayoutPhoto(Context context) { 23 | super(context); 24 | } 25 | 26 | public void setDelegate(SizeNotifierFrameLayoutPhotoDelegate delegate) { 27 | this.delegate = delegate; 28 | } 29 | 30 | @Override 31 | protected void onLayout(boolean changed, int l, int t, int r, int b) { 32 | super.onLayout(changed, l, t, r, b); 33 | notifyHeightChanged(); 34 | } 35 | 36 | public int getKeyboardHeight() { 37 | View rootView = getRootView(); 38 | int usableViewHeight = rootView.getHeight() - AndroidUtilities.getViewInset(rootView); 39 | getWindowVisibleDisplayFrame(rect); 40 | int top = rect.top; 41 | int size = AndroidUtilities.displaySize.y - top - usableViewHeight; 42 | if (size <= AndroidUtilities.dp(10)) { 43 | size = 0; 44 | } 45 | return size; 46 | } 47 | 48 | public void notifyHeightChanged() { 49 | if (delegate != null) { 50 | keyboardHeight = getKeyboardHeight(); 51 | final boolean isWidthGreater = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; 52 | post(new Runnable() { 53 | @Override 54 | public void run() { 55 | if (delegate != null) { 56 | delegate.onSizeChanged(keyboardHeight, isWidthGreater); 57 | } 58 | } 59 | }); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/InputFile.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class InputFile extends TLObject { 5 | public long id; 6 | public int parts; 7 | public String name; 8 | public String md5_checksum; 9 | 10 | public static InputFile TLdeserialize(AbstractSerializedData stream, int constructor, 11 | boolean exception) { 12 | InputFile result = null; 13 | switch (constructor) { 14 | case 0xfa4f0bb5: 15 | result = new TL_inputFileBig(); 16 | break; 17 | case 0xf52ff27f: 18 | result = new TL_inputFile(); 19 | break; 20 | } 21 | if (result == null && exception) { 22 | throw new RuntimeException( 23 | String.format("can't parse magic %x in InputFile", constructor)); 24 | } 25 | if (result != null) { 26 | result.readParams(stream, exception); 27 | } 28 | return result; 29 | } 30 | 31 | public static class TL_inputFileBig extends InputFile { 32 | public static int constructor = 0xfa4f0bb5; 33 | 34 | public void readParams(AbstractSerializedData stream, boolean exception) { 35 | id = stream.readInt64(exception); 36 | parts = stream.readInt32(exception); 37 | name = stream.readString(exception); 38 | } 39 | 40 | public void serializeToStream(AbstractSerializedData stream) { 41 | stream.writeInt32(constructor); 42 | stream.writeInt64(id); 43 | stream.writeInt32(parts); 44 | stream.writeString(name); 45 | } 46 | } 47 | 48 | public static class TL_inputFile extends InputFile { 49 | public static int constructor = 0xf52ff27f; 50 | 51 | public void readParams(AbstractSerializedData stream, boolean exception) { 52 | id = stream.readInt64(exception); 53 | parts = stream.readInt32(exception); 54 | name = stream.readString(exception); 55 | md5_checksum = stream.readString(exception); 56 | } 57 | 58 | public void serializeToStream(AbstractSerializedData stream) { 59 | stream.writeInt32(constructor); 60 | stream.writeInt64(id); 61 | stream.writeInt32(parts); 62 | stream.writeString(name); 63 | stream.writeString(md5_checksum); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/InputStickerSet.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class InputStickerSet extends TLObject { 5 | public long id; 6 | public long access_hash; 7 | public String short_name; 8 | 9 | public static InputStickerSet TLdeserialize(AbstractSerializedData stream, int constructor, 10 | boolean exception) { 11 | InputStickerSet result = null; 12 | switch (constructor) { 13 | case 0xffb62b95: 14 | result = new TL_inputStickerSetEmpty(); 15 | break; 16 | case 0x9de7a269: 17 | result = new TL_inputStickerSetID(); 18 | break; 19 | case 0x861cc8a0: 20 | result = new TL_inputStickerSetShortName(); 21 | break; 22 | } 23 | if (result == null && exception) { 24 | throw new RuntimeException( 25 | String.format("can't parse magic %x in InputStickerSet", constructor)); 26 | } 27 | if (result != null) { 28 | result.readParams(stream, exception); 29 | } 30 | return result; 31 | } 32 | 33 | public static class TL_inputStickerSetEmpty extends InputStickerSet { 34 | public static int constructor = 0xffb62b95; 35 | 36 | public void serializeToStream(AbstractSerializedData stream) { 37 | stream.writeInt32(constructor); 38 | } 39 | } 40 | 41 | public static class TL_inputStickerSetID extends InputStickerSet { 42 | public static int constructor = 0x9de7a269; 43 | 44 | public void readParams(AbstractSerializedData stream, boolean exception) { 45 | id = stream.readInt64(exception); 46 | access_hash = stream.readInt64(exception); 47 | } 48 | 49 | public void serializeToStream(AbstractSerializedData stream) { 50 | stream.writeInt32(constructor); 51 | stream.writeInt64(id); 52 | stream.writeInt64(access_hash); 53 | } 54 | } 55 | 56 | public static class TL_inputStickerSetShortName extends InputStickerSet { 57 | public static int constructor = 0x861cc8a0; 58 | 59 | public void readParams(AbstractSerializedData stream, boolean exception) { 60 | short_name = stream.readString(exception); 61 | } 62 | 63 | public void serializeToStream(AbstractSerializedData stream) { 64 | stream.writeInt32(constructor); 65 | stream.writeString(short_name); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/InputFileLocation.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class InputFileLocation extends TLObject { 5 | public long id; 6 | public long access_hash; 7 | public long volume_id; 8 | public int local_id; 9 | public long secret; 10 | 11 | public static InputFileLocation TLdeserialize(AbstractSerializedData stream, int constructor, 12 | boolean exception) { 13 | InputFileLocation result = null; 14 | switch (constructor) { 15 | case 0xf5235d55: 16 | result = new TL_inputEncryptedFileLocation(); 17 | break; 18 | case 0x4e45abe9: 19 | result = new TL_inputDocumentFileLocation(); 20 | break; 21 | case 0x14637196: 22 | result = new TL_inputFileLocation(); 23 | break; 24 | } 25 | if (result == null && exception) { 26 | throw new RuntimeException( 27 | String.format("can't parse magic %x in InputFileLocation", constructor)); 28 | } 29 | if (result != null) { 30 | result.readParams(stream, exception); 31 | } 32 | return result; 33 | } 34 | 35 | public static class TL_inputEncryptedFileLocation extends InputFileLocation { 36 | public static int constructor = 0xf5235d55; 37 | 38 | public void readParams(AbstractSerializedData stream, boolean exception) { 39 | id = stream.readInt64(exception); 40 | access_hash = stream.readInt64(exception); 41 | } 42 | 43 | public void serializeToStream(AbstractSerializedData stream) { 44 | stream.writeInt32(constructor); 45 | stream.writeInt64(id); 46 | stream.writeInt64(access_hash); 47 | } 48 | } 49 | 50 | public static class TL_inputDocumentFileLocation extends InputFileLocation { 51 | public static int constructor = 0x4e45abe9; 52 | 53 | public void readParams(AbstractSerializedData stream, boolean exception) { 54 | id = stream.readInt64(exception); 55 | access_hash = stream.readInt64(exception); 56 | } 57 | 58 | public void serializeToStream(AbstractSerializedData stream) { 59 | stream.writeInt32(constructor); 60 | stream.writeInt64(id); 61 | stream.writeInt64(access_hash); 62 | } 63 | } 64 | 65 | public static class TL_inputFileLocation extends InputFileLocation { 66 | public static int constructor = 0x14637196; 67 | 68 | public void readParams(AbstractSerializedData stream, boolean exception) { 69 | volume_id = stream.readInt64(exception); 70 | local_id = stream.readInt32(exception); 71 | secret = stream.readInt64(exception); 72 | } 73 | 74 | public void serializeToStream(AbstractSerializedData stream) { 75 | stream.writeInt32(constructor); 76 | stream.writeInt64(volume_id); 77 | stream.writeInt32(local_id); 78 | stream.writeInt64(secret); 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/AspectRatioFrameLayout.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.dhc.gallery.components; 17 | 18 | import android.content.Context; 19 | import android.util.AttributeSet; 20 | import android.widget.FrameLayout; 21 | 22 | /** 23 | * A {@link FrameLayout} that resizes itself to match a specified aspect ratio. 24 | */ 25 | public final class AspectRatioFrameLayout extends FrameLayout { 26 | 27 | /** 28 | * The {@link FrameLayout} will not resize itself if the fractional difference between its natural 29 | * aspect ratio and the requested aspect ratio falls below this threshold. 30 | *

31 | * This tolerance allows the view to occupy the whole of the screen when the requested aspect 32 | * ratio is very close, but not exactly equal to, the aspect ratio of the screen. This may reduce 33 | * the number of view layers that need to be composited by the underlying system, which can help 34 | * to reduce power consumption. 35 | */ 36 | private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f; 37 | 38 | private float videoAspectRatio; 39 | 40 | public AspectRatioFrameLayout(Context context) { 41 | super(context); 42 | } 43 | 44 | public AspectRatioFrameLayout(Context context, AttributeSet attrs) { 45 | super(context, attrs); 46 | } 47 | 48 | /** 49 | * Set the aspect ratio that this view should satisfy. 50 | * 51 | * @param widthHeightRatio The width to height ratio. 52 | */ 53 | public void setAspectRatio(float widthHeightRatio) { 54 | if (this.videoAspectRatio != widthHeightRatio) { 55 | this.videoAspectRatio = widthHeightRatio; 56 | requestLayout(); 57 | } 58 | } 59 | 60 | @Override 61 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 62 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 63 | if (videoAspectRatio == 0) { 64 | // Aspect ratio not set. 65 | return; 66 | } 67 | 68 | int width = getMeasuredWidth(); 69 | int height = getMeasuredHeight(); 70 | float viewAspectRatio = (float) width / height; 71 | float aspectDeformation = videoAspectRatio / viewAspectRatio - 1; 72 | if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) { 73 | // We're within the allowed tolerance. 74 | return; 75 | } 76 | 77 | if (aspectDeformation > 0) { 78 | height = (int) (width / videoAspectRatio); 79 | } else { 80 | width = (int) (height * videoAspectRatio); 81 | } 82 | super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 83 | MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/FileLocation.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class FileLocation extends TLObject { 5 | public int dc_id; 6 | public long volume_id; 7 | public int local_id; 8 | public long secret; 9 | public byte[] key; 10 | public byte[] iv; 11 | 12 | public static FileLocation TLdeserialize(AbstractSerializedData stream, int constructor, 13 | boolean exception) { 14 | FileLocation result = null; 15 | switch (constructor) { 16 | case 0x53d69076: 17 | result = new TL_fileLocation(); 18 | break; 19 | case 0x55555554: 20 | result = new TL_fileEncryptedLocation(); 21 | break; 22 | case 0x7c596b46: 23 | result = new TL_fileLocationUnavailable(); 24 | break; 25 | } 26 | if (result == null && exception) { 27 | throw new RuntimeException( 28 | String.format("can't parse magic %x in FileLocation", constructor)); 29 | } 30 | if (result != null) { 31 | result.readParams(stream, exception); 32 | } 33 | return result; 34 | } 35 | 36 | public static class TL_fileLocation extends FileLocation { 37 | public static int constructor = 0x53d69076; 38 | 39 | public void readParams(AbstractSerializedData stream, boolean exception) { 40 | dc_id = stream.readInt32(exception); 41 | volume_id = stream.readInt64(exception); 42 | local_id = stream.readInt32(exception); 43 | secret = stream.readInt64(exception); 44 | } 45 | 46 | public void serializeToStream(AbstractSerializedData stream) { 47 | stream.writeInt32(constructor); 48 | stream.writeInt32(dc_id); 49 | stream.writeInt64(volume_id); 50 | stream.writeInt32(local_id); 51 | stream.writeInt64(secret); 52 | } 53 | } 54 | 55 | public static class TL_fileEncryptedLocation extends FileLocation { 56 | public static int constructor = 0x55555554; 57 | 58 | public void readParams(AbstractSerializedData stream, boolean exception) { 59 | dc_id = stream.readInt32(exception); 60 | volume_id = stream.readInt64(exception); 61 | local_id = stream.readInt32(exception); 62 | secret = stream.readInt64(exception); 63 | key = stream.readByteArray(exception); 64 | iv = stream.readByteArray(exception); 65 | } 66 | 67 | public void serializeToStream(AbstractSerializedData stream) { 68 | stream.writeInt32(constructor); 69 | stream.writeInt32(dc_id); 70 | stream.writeInt64(volume_id); 71 | stream.writeInt32(local_id); 72 | stream.writeInt64(secret); 73 | stream.writeByteArray(key); 74 | stream.writeByteArray(iv); 75 | } 76 | } 77 | 78 | public static class TL_fileLocationUnavailable extends FileLocation { 79 | public static int constructor = 0x7c596b46; 80 | 81 | public void readParams(AbstractSerializedData stream, boolean exception) { 82 | volume_id = stream.readInt64(exception); 83 | local_id = stream.readInt32(exception); 84 | secret = stream.readInt64(exception); 85 | } 86 | 87 | public void serializeToStream(AbstractSerializedData stream) { 88 | stream.writeInt32(constructor); 89 | stream.writeInt64(volume_id); 90 | stream.writeInt32(local_id); 91 | stream.writeInt64(secret); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/InputEncryptedFile.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class InputEncryptedFile extends TLObject { 5 | public long id; 6 | public long access_hash; 7 | public int parts; 8 | public int key_fingerprint; 9 | public String md5_checksum; 10 | 11 | public static InputEncryptedFile TLdeserialize(AbstractSerializedData stream, int constructor, 12 | boolean exception) { 13 | InputEncryptedFile result = null; 14 | switch (constructor) { 15 | case 0x5a17b5e5: 16 | result = new TL_inputEncryptedFile(); 17 | break; 18 | case 0x2dc173c8: 19 | result = new TL_inputEncryptedFileBigUploaded(); 20 | break; 21 | case 0x1837c364: 22 | result = new TL_inputEncryptedFileEmpty(); 23 | break; 24 | case 0x64bd0306: 25 | result = new TL_inputEncryptedFileUploaded(); 26 | break; 27 | } 28 | if (result == null && exception) { 29 | throw new RuntimeException( 30 | String.format("can't parse magic %x in InputEncryptedFile", constructor)); 31 | } 32 | if (result != null) { 33 | result.readParams(stream, exception); 34 | } 35 | return result; 36 | } 37 | 38 | public static class TL_inputEncryptedFileBigUploaded extends InputEncryptedFile { 39 | public static int constructor = 0x2dc173c8; 40 | 41 | public void readParams(AbstractSerializedData stream, boolean exception) { 42 | id = stream.readInt64(exception); 43 | parts = stream.readInt32(exception); 44 | key_fingerprint = stream.readInt32(exception); 45 | } 46 | 47 | public void serializeToStream(AbstractSerializedData stream) { 48 | stream.writeInt32(constructor); 49 | stream.writeInt64(id); 50 | stream.writeInt32(parts); 51 | stream.writeInt32(key_fingerprint); 52 | } 53 | } 54 | 55 | public static class TL_inputEncryptedFile extends InputEncryptedFile { 56 | public static int constructor = 0x5a17b5e5; 57 | 58 | public void readParams(AbstractSerializedData stream, boolean exception) { 59 | id = stream.readInt64(exception); 60 | access_hash = stream.readInt64(exception); 61 | } 62 | 63 | public void serializeToStream(AbstractSerializedData stream) { 64 | stream.writeInt32(constructor); 65 | stream.writeInt64(id); 66 | stream.writeInt64(access_hash); 67 | } 68 | } 69 | 70 | public static class TL_inputEncryptedFileEmpty extends InputEncryptedFile { 71 | public static int constructor = 0x1837c364; 72 | 73 | public void serializeToStream(AbstractSerializedData stream) { 74 | stream.writeInt32(constructor); 75 | } 76 | } 77 | 78 | public static class TL_inputEncryptedFileUploaded extends InputEncryptedFile { 79 | public static int constructor = 0x64bd0306; 80 | 81 | public void readParams(AbstractSerializedData stream, boolean exception) { 82 | id = stream.readInt64(exception); 83 | parts = stream.readInt32(exception); 84 | md5_checksum = stream.readString(exception); 85 | key_fingerprint = stream.readInt32(exception); 86 | } 87 | 88 | public void serializeToStream(AbstractSerializedData stream) { 89 | stream.writeInt32(constructor); 90 | stream.writeInt64(id); 91 | stream.writeInt32(parts); 92 | stream.writeString(md5_checksum); 93 | stream.writeInt32(key_fingerprint); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/Theme.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery; 3 | 4 | import android.content.res.ColorStateList; 5 | import android.graphics.Canvas; 6 | import android.graphics.ColorFilter; 7 | import android.graphics.Paint; 8 | import android.graphics.drawable.ColorDrawable; 9 | import android.graphics.drawable.Drawable; 10 | import android.graphics.drawable.RippleDrawable; 11 | import android.graphics.drawable.StateListDrawable; 12 | import android.os.Build; 13 | 14 | import com.dhc.gallery.utils.AndroidUtilities; 15 | 16 | import java.util.HashMap; 17 | 18 | public class Theme { 19 | 20 | public static final int ACTION_BAR_COLOR = 0xff527da3; 21 | public static final int ACTION_BAR_PHOTO_VIEWER_COLOR = 0x7f000000; 22 | public static final int ACTION_BAR_MEDIA_PICKER_COLOR = 0xff333333; 23 | public static final int ACTION_BAR_SUBTITLE_COLOR = 0xffd5e8f7; 24 | public static final int ACTION_BAR_SELECTOR_COLOR = 0xff406d94; 25 | 26 | public static final int ACTION_BAR_PICKER_SELECTOR_COLOR = 0xff3d3d3d; 27 | public static final int ACTION_BAR_WHITE_SELECTOR_COLOR = 0x40ffffff; 28 | public static final int ACTION_BAR_AUDIO_SELECTOR_COLOR = 0x2f000000; 29 | public static final int ACTION_BAR_MODE_SELECTOR_COLOR = 0xfff0f0f0; 30 | 31 | private static Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 32 | private static HashMap defaultColors = new HashMap<>(); 33 | private static HashMap currentColors; 34 | 35 | 36 | public static final String key_chat_serviceBackground = "chat_serviceBackground"; 37 | private static int serviceMessageColor; 38 | 39 | public static Drawable createBarSelectorDrawable(int color) { 40 | return createBarSelectorDrawable(color, true); 41 | } 42 | 43 | public static Drawable createBarSelectorDrawable(int color, boolean masked) { 44 | if (Build.VERSION.SDK_INT >= 21) { 45 | Drawable maskDrawable = null; 46 | if (masked) { 47 | maskPaint.setColor(0xffffffff); 48 | maskDrawable = new Drawable() { 49 | @Override 50 | public void draw(Canvas canvas) { 51 | android.graphics.Rect bounds = getBounds(); 52 | canvas.drawCircle(bounds.centerX(), bounds.centerY(), 53 | AndroidUtilities.dp(18), maskPaint); 54 | } 55 | 56 | @Override 57 | public void setAlpha(int alpha) { 58 | 59 | } 60 | 61 | @Override 62 | public void setColorFilter(ColorFilter colorFilter) { 63 | 64 | } 65 | 66 | @Override 67 | public int getOpacity() { 68 | return 0; 69 | } 70 | }; 71 | } 72 | ColorStateList colorStateList = new ColorStateList( 73 | new int[][] { 74 | new int[] {} 75 | }, 76 | new int[] { 77 | color 78 | }); 79 | return new RippleDrawable(colorStateList, null, maskDrawable); 80 | } else { 81 | StateListDrawable stateListDrawable = new StateListDrawable(); 82 | stateListDrawable.addState(new int[] { 83 | android.R.attr.state_pressed 84 | }, new ColorDrawable(color)); 85 | stateListDrawable.addState(new int[] { 86 | android.R.attr.state_focused 87 | }, new ColorDrawable(color)); 88 | stateListDrawable.addState(new int[] { 89 | android.R.attr.state_selected 90 | }, new ColorDrawable(color)); 91 | stateListDrawable.addState(new int[] { 92 | android.R.attr.state_activated 93 | }, new ColorDrawable(color)); 94 | stateListDrawable.addState(new int[] {}, new ColorDrawable(0x00000000)); 95 | return stateListDrawable; 96 | } 97 | } 98 | 99 | 100 | 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/hc/gallery/util/StorageUtil.java: -------------------------------------------------------------------------------- 1 | package com.hc.gallery.util; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.os.Environment; 6 | import android.text.TextUtils; 7 | 8 | import java.io.File; 9 | import java.util.UUID; 10 | /** 11 | * 创建者:邓浩宸 12 | * 时间 :2017/4/20 13:01 13 | * 描述 :TODO 请描述该类职责 14 | */ 15 | public class StorageUtil { 16 | public final static long K = 1024; 17 | public final static long M = 1024 * 1024; 18 | // 外置存储卡默认预警临界值 19 | private static final long THRESHOLD_WARNING_SPACE = 100 * M; 20 | // 保存文件时所需的最小空间的默认值 21 | public static final long THRESHOLD_MIN_SPCAE = 20 * M; 22 | 23 | public static void init(Context context, String rootPath) { 24 | ExternalStorage.getInstance().init(context, rootPath); 25 | } 26 | 27 | /** 28 | * 获取文件保存路径,没有toast提示 29 | * 30 | * @param fileName 31 | * @param fileType 32 | * @return 可用的保存路径或者null 33 | */ 34 | public static String getWritePath(String fileName, StorageType fileType) { 35 | return getWritePath(null, fileName, fileType, false); 36 | } 37 | 38 | /** 39 | * 获取32位uuid 40 | * 41 | * @return 42 | */ 43 | public static String get32UUID() { 44 | return UUID.randomUUID().toString().replaceAll("-", ""); 45 | } 46 | 47 | /** 48 | * 获取文件保存路径 49 | * 50 | * @param fileName 51 | * 文件全名 52 | * @param tip 53 | * 空间不足时是否给出默认的toast提示 54 | * @return 可用的保存路径或者null 55 | */ 56 | private static String getWritePath(Context context, String fileName, StorageType fileType, boolean tip) { 57 | String path = ExternalStorage.getInstance().getWritePath(fileName, fileType); 58 | if (TextUtils.isEmpty(path)) { 59 | return null; 60 | } 61 | File dir = new File(path).getParentFile(); 62 | if (dir != null && !dir.exists()) { 63 | dir.mkdirs(); 64 | } 65 | return path; 66 | } 67 | 68 | /** 69 | * 判断能否使用外置存储 70 | */ 71 | public static boolean isExternalStorageExist() { 72 | return ExternalStorage.getInstance().isSdkStorageReady(); 73 | } 74 | 75 | 76 | /** 77 | * 判断外部存储是否存在,以及是否有足够空间保存指定类型的文件 78 | * 79 | * @param context 80 | * @param fileType 81 | * @param tip 是否需要toast提示 82 | * @return false: 无存储卡或无空间可写, true: 表示ok 83 | */ 84 | public static boolean hasEnoughSpaceForWrite(Context context, StorageType fileType, boolean tip) { 85 | if (!ExternalStorage.getInstance().isSdkStorageReady()) { 86 | return false; 87 | } 88 | 89 | long residual = ExternalStorage.getInstance().getAvailableExternalSize(); 90 | if (residual < fileType.getStorageMinSize()) { 91 | return false; 92 | } else if (residual < THRESHOLD_WARNING_SPACE) { 93 | } 94 | 95 | return true; 96 | } 97 | /** 98 | * 根据输入的文件名和类型,找到该文件的全路径。 99 | * 100 | * @param fileName 101 | * @param fileType 102 | * @return 如果存在该文件,返回路径,否则返回空 103 | */ 104 | public static String getReadPath(String fileName, StorageType fileType) { 105 | return ExternalStorage.getInstance().getReadPath(fileName, fileType); 106 | } 107 | 108 | /** 109 | * 获取文件保存路径,空间不足时有toast提示 110 | * 111 | * @param context 112 | * @param fileName 113 | * @param fileType 114 | * @return 可用的保存路径或者null 115 | */ 116 | public static String getWritePath(Context context, String fileName, StorageType fileType) { 117 | return getWritePath(context, fileName, fileType, true); 118 | } 119 | 120 | public static String getDirectoryByDirType(StorageType fileType) { 121 | return ExternalStorage.getInstance().getDirectoryByDirType(fileType); 122 | } 123 | 124 | public static String getSystemImagePath() { 125 | if (Build.VERSION.SDK_INT > 7) { 126 | String picturePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath(); 127 | return picturePath + "/nim/"; 128 | } else { 129 | String picturePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath(); 130 | return picturePath + "/nim/"; 131 | } 132 | } 133 | 134 | public static boolean isInvalidVideoFile(String filePath) { 135 | return filePath.toLowerCase().endsWith(".3gp") 136 | || filePath.toLowerCase().endsWith(".mp4"); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/PhotoSize.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class PhotoSize extends TLObject { 5 | public String type; 6 | public FileLocation location; 7 | public int w; 8 | public int h; 9 | public int size; 10 | public byte[] bytes; 11 | 12 | public static PhotoSize TLdeserialize(AbstractSerializedData stream, int constructor, 13 | boolean exception) { 14 | PhotoSize result = null; 15 | switch (constructor) { 16 | case 0x77bfb61b: 17 | result = new TL_photoSize(); 18 | break; 19 | case 0xe17e23c: 20 | result = new TL_photoSizeEmpty(); 21 | break; 22 | case 0xe9a734fa: 23 | result = new TL_photoCachedSize(); 24 | break; 25 | } 26 | if (result == null && exception) { 27 | throw new RuntimeException( 28 | String.format("can't parse magic %x in PhotoSize", constructor)); 29 | } 30 | if (result != null) { 31 | result.readParams(stream, exception); 32 | } 33 | return result; 34 | } 35 | 36 | public static class TL_photoSize extends PhotoSize { 37 | public static int constructor = 0x77bfb61b; 38 | 39 | public void readParams(AbstractSerializedData stream, boolean exception) { 40 | type = stream.readString(exception); 41 | location = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); 42 | w = stream.readInt32(exception); 43 | h = stream.readInt32(exception); 44 | size = stream.readInt32(exception); 45 | } 46 | 47 | public void serializeToStream(AbstractSerializedData stream) { 48 | stream.writeInt32(constructor); 49 | stream.writeString(type); 50 | location.serializeToStream(stream); 51 | stream.writeInt32(w); 52 | stream.writeInt32(h); 53 | stream.writeInt32(size); 54 | } 55 | } 56 | 57 | public static class TL_photoSizeEmpty extends PhotoSize { 58 | public static int constructor = 0xe17e23c; 59 | 60 | public void readParams(AbstractSerializedData stream, boolean exception) { 61 | int startReadPosiition = stream.getPosition(); // TODO remove this hack after some time 62 | try { 63 | type = stream.readString(true); 64 | if (type.length() > 1 || !type.equals("") && !type.equals("s") && !type.equals("x") 65 | && !type.equals("m") && !type.equals("y") && !type.equals("w")) { 66 | type = "s"; 67 | if (stream instanceof NativeByteBuffer) { 68 | ((NativeByteBuffer) stream).position(startReadPosiition); 69 | } 70 | } 71 | } catch (Exception e) { 72 | type = "s"; 73 | if (stream instanceof NativeByteBuffer) { 74 | ((NativeByteBuffer) stream).position(startReadPosiition); 75 | } 76 | } 77 | } 78 | 79 | public void serializeToStream(AbstractSerializedData stream) { 80 | stream.writeInt32(constructor); 81 | stream.writeString(type); 82 | } 83 | } 84 | 85 | public static class TL_photoCachedSize extends PhotoSize { 86 | public static int constructor = 0xe9a734fa; 87 | 88 | public void readParams(AbstractSerializedData stream, boolean exception) { 89 | type = stream.readString(exception); 90 | location = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); 91 | w = stream.readInt32(exception); 92 | h = stream.readInt32(exception); 93 | bytes = stream.readByteArray(exception); 94 | } 95 | 96 | public void serializeToStream(AbstractSerializedData stream) { 97 | stream.writeInt32(constructor); 98 | stream.writeString(type); 99 | location.serializeToStream(stream); 100 | stream.writeInt32(w); 101 | stream.writeInt32(h); 102 | stream.writeByteArray(bytes); 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/actionbar/MenuDrawable.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.actionbar; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.ColorFilter; 5 | import android.graphics.Paint; 6 | import android.graphics.PixelFormat; 7 | import android.graphics.drawable.Drawable; 8 | import android.view.animation.DecelerateInterpolator; 9 | 10 | import com.dhc.gallery.utils.AndroidUtilities; 11 | 12 | public class MenuDrawable extends Drawable { 13 | 14 | private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 15 | private boolean reverseAngle = false; 16 | private long lastFrameTime; 17 | private boolean animationInProgress; 18 | private float finalRotation; 19 | private float currentRotation; 20 | private int currentAnimationTime; 21 | private DecelerateInterpolator interpolator = new DecelerateInterpolator(); 22 | 23 | public MenuDrawable() { 24 | super(); 25 | paint.setColor(0xffffffff); 26 | paint.setStrokeWidth(AndroidUtilities.dp(2)); 27 | } 28 | 29 | public void setRotation(float rotation, boolean animated) { 30 | lastFrameTime = 0; 31 | if (currentRotation == 1) { 32 | reverseAngle = true; 33 | } else if (currentRotation == 0) { 34 | reverseAngle = false; 35 | } 36 | lastFrameTime = 0; 37 | if (animated) { 38 | if (currentRotation < rotation) { 39 | currentAnimationTime = (int) (currentRotation * 300); 40 | } else { 41 | currentAnimationTime = (int) ((1.0f - currentRotation) * 300); 42 | } 43 | lastFrameTime = System.currentTimeMillis(); 44 | finalRotation = rotation; 45 | } else { 46 | finalRotation = currentRotation = rotation; 47 | } 48 | invalidateSelf(); 49 | } 50 | 51 | @Override 52 | public void draw(Canvas canvas) { 53 | if (currentRotation != finalRotation) { 54 | if (lastFrameTime != 0) { 55 | long dt = System.currentTimeMillis() - lastFrameTime; 56 | 57 | currentAnimationTime += dt; 58 | if (currentAnimationTime >= 300) { 59 | currentRotation = finalRotation; 60 | } else { 61 | if (currentRotation < finalRotation) { 62 | currentRotation = interpolator.getInterpolation(currentAnimationTime / 300.0f) * finalRotation; 63 | } else { 64 | currentRotation = 1.0f - interpolator.getInterpolation(currentAnimationTime / 300.0f); 65 | } 66 | } 67 | } 68 | lastFrameTime = System.currentTimeMillis(); 69 | invalidateSelf(); 70 | } 71 | 72 | canvas.save(); 73 | canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2); 74 | canvas.rotate(currentRotation * (reverseAngle ? -180 : 180)); 75 | canvas.drawLine(-AndroidUtilities.dp(9), 0, AndroidUtilities.dp(9) - AndroidUtilities.dp(3.0f) * currentRotation, 0, paint); 76 | float endYDiff = AndroidUtilities.dp(5) * (1 - Math.abs(currentRotation)) - AndroidUtilities.dp(0.5f) * Math.abs(currentRotation); 77 | float endXDiff = AndroidUtilities.dp(9) - AndroidUtilities.dp(2.5f) * Math.abs(currentRotation); 78 | float startYDiff = AndroidUtilities.dp(5) + AndroidUtilities.dp(2.0f) * Math.abs(currentRotation); 79 | float startXDiff = -AndroidUtilities.dp(9) + AndroidUtilities.dp(7.5f) * Math.abs(currentRotation); 80 | canvas.drawLine(startXDiff, -startYDiff, endXDiff, -endYDiff, paint); 81 | canvas.drawLine(startXDiff, startYDiff, endXDiff, endYDiff, paint); 82 | canvas.restore(); 83 | } 84 | 85 | @Override 86 | public void setAlpha(int alpha) { 87 | 88 | } 89 | 90 | @Override 91 | public void setColorFilter(ColorFilter cf) { 92 | 93 | } 94 | 95 | @Override 96 | public int getOpacity() { 97 | return PixelFormat.TRANSPARENT; 98 | } 99 | 100 | @Override 101 | public int getIntrinsicWidth() { 102 | return AndroidUtilities.dp(24); 103 | } 104 | 105 | @Override 106 | public int getIntrinsicHeight() { 107 | return AndroidUtilities.dp(24); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /gallery/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 47 | 48 | 49 | 53 | 54 | 55 | 59 | 60 | 64 | 65 | 71 | 72 | 78 | 79 | 83 | 84 | 88 | 89 | 95 | 96 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/StorageFileType.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | public class StorageFileType extends TLObject { 5 | 6 | public static StorageFileType TLdeserialize(AbstractSerializedData stream, int constructor, 7 | boolean exception) { 8 | StorageFileType result = null; 9 | switch (constructor) { 10 | case 0xaa963b05: 11 | result = new TL_storage_fileUnknown(); 12 | break; 13 | case 0xb3cea0e4: 14 | result = new TL_storage_fileMp4(); 15 | break; 16 | case 0x1081464c: 17 | result = new TL_storage_fileWebp(); 18 | break; 19 | case 0xa4f63c0: 20 | result = new TL_storage_filePng(); 21 | break; 22 | case 0xcae1aadf: 23 | result = new TL_storage_fileGif(); 24 | break; 25 | case 0xae1e508d: 26 | result = new TL_storage_filePdf(); 27 | break; 28 | case 0x528a0677: 29 | result = new TL_storage_fileMp3(); 30 | break; 31 | case 0x7efe0e: 32 | result = new TL_storage_fileJpeg(); 33 | break; 34 | case 0x4b09ebbc: 35 | result = new TL_storage_fileMov(); 36 | break; 37 | case 0x40bc6f52: 38 | result = new TL_storage_filePartial(); 39 | break; 40 | } 41 | if (result == null && exception) { 42 | throw new RuntimeException( 43 | String.format("can't parse magic %x in StorageFileType", constructor)); 44 | } 45 | if (result != null) { 46 | result.readParams(stream, exception); 47 | } 48 | return result; 49 | } 50 | 51 | public static class TL_storage_fileUnknown extends StorageFileType { 52 | public static int constructor = 0xaa963b05; 53 | 54 | 55 | public void serializeToStream(AbstractSerializedData stream) { 56 | stream.writeInt32(constructor); 57 | } 58 | } 59 | 60 | public static class TL_storage_fileMp4 extends StorageFileType { 61 | public static int constructor = 0xb3cea0e4; 62 | 63 | 64 | public void serializeToStream(AbstractSerializedData stream) { 65 | stream.writeInt32(constructor); 66 | } 67 | } 68 | 69 | public static class TL_storage_fileWebp extends StorageFileType { 70 | public static int constructor = 0x1081464c; 71 | 72 | 73 | public void serializeToStream(AbstractSerializedData stream) { 74 | stream.writeInt32(constructor); 75 | } 76 | } 77 | 78 | public static class TL_storage_filePng extends StorageFileType { 79 | public static int constructor = 0xa4f63c0; 80 | 81 | 82 | public void serializeToStream(AbstractSerializedData stream) { 83 | stream.writeInt32(constructor); 84 | } 85 | } 86 | 87 | public static class TL_storage_fileGif extends StorageFileType { 88 | public static int constructor = 0xcae1aadf; 89 | 90 | 91 | public void serializeToStream(AbstractSerializedData stream) { 92 | stream.writeInt32(constructor); 93 | } 94 | } 95 | 96 | public static class TL_storage_filePdf extends StorageFileType { 97 | public static int constructor = 0xae1e508d; 98 | 99 | 100 | public void serializeToStream(AbstractSerializedData stream) { 101 | stream.writeInt32(constructor); 102 | } 103 | } 104 | 105 | public static class TL_storage_fileMp3 extends StorageFileType { 106 | public static int constructor = 0x528a0677; 107 | 108 | 109 | public void serializeToStream(AbstractSerializedData stream) { 110 | stream.writeInt32(constructor); 111 | } 112 | } 113 | 114 | public static class TL_storage_fileJpeg extends StorageFileType { 115 | public static int constructor = 0x7efe0e; 116 | 117 | 118 | public void serializeToStream(AbstractSerializedData stream) { 119 | stream.writeInt32(constructor); 120 | } 121 | } 122 | 123 | public static class TL_storage_fileMov extends StorageFileType { 124 | public static int constructor = 0x4b09ebbc; 125 | 126 | 127 | public void serializeToStream(AbstractSerializedData stream) { 128 | stream.writeInt32(constructor); 129 | } 130 | } 131 | 132 | public static class TL_storage_filePartial extends StorageFileType { 133 | public static int constructor = 0x40bc6f52; 134 | 135 | 136 | public void serializeToStream(AbstractSerializedData stream) { 137 | stream.writeInt32(constructor); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/BackupImageView.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.components; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.graphics.drawable.Drawable; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.dhc.gallery.proxy.ImageReceiver; 12 | import com.dhc.gallery.tl.FileLocation; 13 | import com.dhc.gallery.tl.TLObject; 14 | 15 | public class BackupImageView extends View { 16 | 17 | private ImageReceiver imageReceiver; 18 | private int width = -1; 19 | private int height = -1; 20 | 21 | public BackupImageView(Context context) { 22 | super(context); 23 | init(); 24 | } 25 | 26 | public BackupImageView(Context context, AttributeSet attrs) { 27 | super(context, attrs); 28 | init(); 29 | } 30 | 31 | public BackupImageView(Context context, AttributeSet attrs, int defStyleAttr) { 32 | super(context, attrs, defStyleAttr); 33 | init(); 34 | } 35 | 36 | private void init() { 37 | imageReceiver = new ImageReceiver(this); 38 | } 39 | 40 | public void setImage(TLObject path, String filter, String ext, Drawable thumb) { 41 | setImage(path, null, filter, thumb, null, null, null, ext, 0); 42 | } 43 | 44 | public void setImage(TLObject path, String filter, Drawable thumb) { 45 | setImage(path, null, filter, thumb, null, null, null, null, 0); 46 | } 47 | 48 | public void setImage(TLObject path, String filter, Bitmap thumb) { 49 | setImage(path, null, filter, null, thumb, null, null, null, 0); 50 | } 51 | 52 | public void setImage(TLObject path, String filter, Drawable thumb, int size) { 53 | setImage(path, null, filter, thumb, null, null, null, null, size); 54 | } 55 | 56 | public void setImage(TLObject path, String filter, Bitmap thumb, int size) { 57 | setImage(path, null, filter, null, thumb, null, null, null, size); 58 | } 59 | 60 | public void setImage(TLObject path, String filter, FileLocation thumb, int size) { 61 | setImage(path, null, filter, null, null, thumb, null, null, size); 62 | } 63 | 64 | public void setImage(String path, String filter, Drawable thumb) { 65 | setImage(null, path, filter, thumb, null, null, null, null, 0); 66 | } 67 | 68 | public void setOrientation(int angle, boolean center) { 69 | imageReceiver.setOrientation(angle, center); 70 | } 71 | 72 | public void setImage(TLObject path, String httpUrl, String filter, Drawable thumb, 73 | Bitmap thumbBitmap, FileLocation thumbLocation, String thumbFilter, String ext, 74 | int size) { 75 | if (thumbBitmap != null) { 76 | thumb = new BitmapDrawable(null, thumbBitmap); 77 | } 78 | imageReceiver.setImage(path, httpUrl, filter, thumb, thumbLocation, thumbFilter, size, ext, 79 | false); 80 | } 81 | 82 | public void setImageBitmap(Bitmap bitmap) { 83 | imageReceiver.setImageBitmap(bitmap); 84 | } 85 | 86 | public void setImageResource(int resId) { 87 | imageReceiver.setImageBitmap(getResources().getDrawable(resId)); 88 | } 89 | 90 | public void setImageDrawable(Drawable drawable) { 91 | imageReceiver.setImageBitmap(drawable); 92 | } 93 | 94 | public void setRoundRadius(int value) { 95 | imageReceiver.setRoundRadius(value); 96 | } 97 | 98 | public void setAspectFit(boolean value) { 99 | imageReceiver.setAspectFit(value); 100 | } 101 | 102 | public ImageReceiver getImageReceiver() { 103 | return imageReceiver; 104 | } 105 | 106 | public void setSize(int w, int h) { 107 | width = w; 108 | height = h; 109 | } 110 | 111 | @Override 112 | protected void onDetachedFromWindow() { 113 | super.onDetachedFromWindow(); 114 | imageReceiver.onDetachedFromWindow(); 115 | } 116 | 117 | @Override 118 | protected void onAttachedToWindow() { 119 | super.onAttachedToWindow(); 120 | imageReceiver.onAttachedToWindow(); 121 | } 122 | 123 | @Override 124 | protected void onDraw(Canvas canvas) { 125 | if (width != -1 && height != -1) { 126 | imageReceiver.setImageCoords((getWidth() - width) / 2, (getHeight() - height) / 2, 127 | width, height); 128 | } else { 129 | imageReceiver.setImageCoords(0, 0, getWidth(), getHeight()); 130 | } 131 | imageReceiver.draw(canvas); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/actionbar/BackDrawable.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.actionbar; 2 | 3 | 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.ColorFilter; 7 | import android.graphics.Paint; 8 | import android.graphics.PixelFormat; 9 | import android.graphics.drawable.Drawable; 10 | import android.view.animation.DecelerateInterpolator; 11 | 12 | import com.dhc.gallery.utils.AndroidUtilities; 13 | 14 | public class BackDrawable extends Drawable { 15 | 16 | private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 17 | private boolean reverseAngle = false; 18 | private long lastFrameTime; 19 | private boolean animationInProgress; 20 | private float finalRotation; 21 | private float currentRotation; 22 | private int currentAnimationTime; 23 | private boolean alwaysClose; 24 | private DecelerateInterpolator interpolator = new DecelerateInterpolator(); 25 | 26 | public BackDrawable(boolean close) { 27 | super(); 28 | paint.setColor(0xffffffff); 29 | paint.setStrokeWidth(AndroidUtilities.dp(2)); 30 | alwaysClose = close; 31 | } 32 | 33 | public void setRotation(float rotation, boolean animated) { 34 | lastFrameTime = 0; 35 | if (currentRotation == 1) { 36 | reverseAngle = true; 37 | } else if (currentRotation == 0) { 38 | reverseAngle = false; 39 | } 40 | lastFrameTime = 0; 41 | if (animated) { 42 | if (currentRotation < rotation) { 43 | currentAnimationTime = (int) (currentRotation * 300); 44 | } else { 45 | currentAnimationTime = (int) ((1.0f - currentRotation) * 300); 46 | } 47 | lastFrameTime = System.currentTimeMillis(); 48 | finalRotation = rotation; 49 | } else { 50 | finalRotation = currentRotation = rotation; 51 | } 52 | invalidateSelf(); 53 | } 54 | 55 | @Override 56 | public void draw(Canvas canvas) { 57 | if (currentRotation != finalRotation) { 58 | if (lastFrameTime != 0) { 59 | long dt = System.currentTimeMillis() - lastFrameTime; 60 | 61 | currentAnimationTime += dt; 62 | if (currentAnimationTime >= 300) { 63 | currentRotation = finalRotation; 64 | } else { 65 | if (currentRotation < finalRotation) { 66 | currentRotation = interpolator.getInterpolation(currentAnimationTime / 300.0f) * finalRotation; 67 | } else { 68 | currentRotation = 1.0f - interpolator.getInterpolation(currentAnimationTime / 300.0f); 69 | } 70 | } 71 | } 72 | lastFrameTime = System.currentTimeMillis(); 73 | invalidateSelf(); 74 | } 75 | 76 | int rD = (int) ((117 - 255) * currentRotation); 77 | int c = Color.rgb(255 + rD, 255 + rD, 255 + rD); 78 | paint.setColor(c); 79 | 80 | canvas.save(); 81 | canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2); 82 | float rotation = currentRotation; 83 | if (!alwaysClose) { 84 | canvas.rotate(currentRotation * (reverseAngle ? -225 : 135)); 85 | } else { 86 | canvas.rotate(135 + currentRotation * (reverseAngle ? -180 : 180)); 87 | rotation = 1.0f; 88 | } 89 | canvas.drawLine(-AndroidUtilities.dp(7) - AndroidUtilities.dp(1) * rotation, 0, AndroidUtilities.dp(8), 0, paint); 90 | float startYDiff = -AndroidUtilities.dp(0.5f); 91 | float endYDiff = AndroidUtilities.dp(7) + AndroidUtilities.dp(1) * rotation; 92 | float startXDiff = -AndroidUtilities.dp(7.0f) + AndroidUtilities.dp(7.0f) * rotation; 93 | float endXDiff = AndroidUtilities.dp(0.5f) - AndroidUtilities.dp(0.5f) * rotation; 94 | canvas.drawLine(startXDiff, -startYDiff, endXDiff, -endYDiff, paint); 95 | canvas.drawLine(startXDiff, startYDiff, endXDiff, endYDiff, paint); 96 | canvas.restore(); 97 | } 98 | 99 | @Override 100 | public void setAlpha(int alpha) { 101 | 102 | } 103 | 104 | @Override 105 | public void setColorFilter(ColorFilter cf) { 106 | 107 | } 108 | 109 | @Override 110 | public int getOpacity() { 111 | return PixelFormat.TRANSPARENT; 112 | } 113 | 114 | @Override 115 | public int getIntrinsicWidth() { 116 | return AndroidUtilities.dp(24); 117 | } 118 | 119 | @Override 120 | public int getIntrinsicHeight() { 121 | return AndroidUtilities.dp(24); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/GalleryConfig.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery; 3 | 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | 7 | import com.dhc.gallery.ui.GalleryActivity; 8 | 9 | /** 10 | * the {@link GalleryActivity} of buidler. 11 | */ 12 | public class GalleryConfig implements Parcelable { 13 | 14 | 15 | public static final int SELECT_PHOTO = 0; 16 | public static final int TAKE_PHOTO = 1; 17 | public static final int RECORD_VEDIO = 2; 18 | public static final int SELECT_VEDIO = 3; 19 | public static final int TAKEPHOTO_RECORDVEDIO = 4; 20 | private String[] filterMimeTypes = new String[]{}; 21 | private String hintOfPick; 22 | private boolean singlePhoto = false; 23 | private int limitPickPhoto = 9; 24 | private boolean isSingleVedio = false; 25 | private boolean isNeedCrop = false; 26 | private String filePath; 27 | private int type = SELECT_PHOTO; 28 | private int requestCode = -1; 29 | private int limitRecordTime; 30 | private int limitRecordSize; 31 | 32 | 33 | public GalleryConfig() { 34 | } 35 | 36 | public String[] getFilterMimeTypes() { 37 | return filterMimeTypes; 38 | } 39 | 40 | public void setFilterMimeTypes(String[] filterMimeTypes) { 41 | this.filterMimeTypes = filterMimeTypes; 42 | } 43 | 44 | public int getLimitRecordSize() { 45 | return limitRecordSize; 46 | } 47 | 48 | public void setLimitRecordSize(int limitRecordSize) { 49 | this.limitRecordSize = limitRecordSize; 50 | } 51 | 52 | public int getLimitRecordTime() { 53 | return limitRecordTime; 54 | } 55 | 56 | public void setLimitRecordTime(int limitRecordTime) { 57 | this.limitRecordTime = limitRecordTime; 58 | } 59 | 60 | public String getHintOfPick() { 61 | return hintOfPick; 62 | } 63 | 64 | public void setHintOfPick(String hintOfPick) { 65 | this.hintOfPick = hintOfPick; 66 | } 67 | 68 | public boolean isSinglePhoto() { 69 | return singlePhoto; 70 | } 71 | 72 | public void setSinglePhoto(boolean singlePhoto) { 73 | this.singlePhoto = singlePhoto; 74 | } 75 | 76 | public int getLimitPickPhoto() { 77 | return limitPickPhoto; 78 | } 79 | 80 | public void setLimitPickPhoto(int limitPickPhoto) { 81 | this.limitPickPhoto = limitPickPhoto; 82 | } 83 | 84 | public boolean isSingleVedio() { 85 | return isSingleVedio; 86 | } 87 | 88 | public void setSingleVedio(boolean singleVedio) { 89 | isSingleVedio = singleVedio; 90 | } 91 | 92 | public boolean isNeedCrop() { 93 | return isNeedCrop; 94 | } 95 | 96 | public void setNeedCrop(boolean needCrop) { 97 | isNeedCrop = needCrop; 98 | } 99 | 100 | public String getFilePath() { 101 | return filePath; 102 | } 103 | 104 | public void setFilePath(String filePath) { 105 | this.filePath = filePath; 106 | } 107 | 108 | public int getType() { 109 | return type; 110 | } 111 | 112 | public void setType(int type) { 113 | this.type = type; 114 | } 115 | 116 | public int getRequestCode() { 117 | return requestCode; 118 | } 119 | 120 | public void setRequestCode(int requestCode) { 121 | this.requestCode = requestCode; 122 | } 123 | 124 | 125 | @Override 126 | public int describeContents() { 127 | return 0; 128 | } 129 | 130 | @Override 131 | public void writeToParcel(Parcel dest, int flags) { 132 | dest.writeStringArray(this.filterMimeTypes); 133 | dest.writeString(this.hintOfPick); 134 | dest.writeByte(this.singlePhoto ? (byte) 1 : (byte) 0); 135 | dest.writeInt(this.limitPickPhoto); 136 | dest.writeByte(this.isSingleVedio ? (byte) 1 : (byte) 0); 137 | dest.writeByte(this.isNeedCrop ? (byte) 1 : (byte) 0); 138 | dest.writeString(this.filePath); 139 | dest.writeInt(this.type); 140 | dest.writeInt(this.requestCode); 141 | dest.writeInt(this.limitRecordTime); 142 | dest.writeInt(this.limitRecordSize); 143 | } 144 | 145 | protected GalleryConfig(Parcel in) { 146 | this.filterMimeTypes = in.createStringArray(); 147 | this.hintOfPick = in.readString(); 148 | this.singlePhoto = in.readByte() != 0; 149 | this.limitPickPhoto = in.readInt(); 150 | this.isSingleVedio = in.readByte() != 0; 151 | this.isNeedCrop = in.readByte() != 0; 152 | this.filePath = in.readString(); 153 | this.type = in.readInt(); 154 | this.requestCode = in.readInt(); 155 | this.limitRecordTime = in.readInt(); 156 | this.limitRecordSize = in.readInt(); 157 | } 158 | 159 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 160 | @Override 161 | public GalleryConfig createFromParcel(Parcel source) { 162 | return new GalleryConfig(source); 163 | } 164 | 165 | @Override 166 | public GalleryConfig[] newArray(int size) { 167 | return new GalleryConfig[size]; 168 | } 169 | }; 170 | } 171 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/PickerBottomLayout.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.components; 3 | 4 | import android.content.Context; 5 | import android.util.TypedValue; 6 | import android.view.Gravity; 7 | import android.view.View; 8 | import android.widget.FrameLayout; 9 | import android.widget.LinearLayout; 10 | import android.widget.TextView; 11 | 12 | import com.dhc.gallery.ui.PhotoAlbumPickerActivity; 13 | import com.dhc.gallery.R; 14 | import com.dhc.gallery.Theme; 15 | import com.dhc.gallery.utils.AndroidUtilities; 16 | import com.dhc.gallery.utils.LayoutHelper; 17 | 18 | public class PickerBottomLayout extends FrameLayout { 19 | 20 | public LinearLayout doneButton; 21 | public TextView cancelButton; 22 | public TextView doneButtonTextView; 23 | public TextView doneButtonBadgeTextView; 24 | 25 | private boolean isDarkTheme; 26 | 27 | public PickerBottomLayout(Context context) { 28 | this(context, true); 29 | } 30 | 31 | public PickerBottomLayout(Context context, boolean darkTheme) { 32 | super(context); 33 | isDarkTheme = darkTheme; 34 | 35 | setBackgroundColor(isDarkTheme ? 0xff1a1a1a : 0xffffffff); 36 | 37 | cancelButton = new TextView(context); 38 | cancelButton.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); 39 | cancelButton.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff); 40 | cancelButton.setGravity(Gravity.CENTER); 41 | cancelButton.setBackgroundDrawable( 42 | Theme.createBarSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR 43 | : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); 44 | cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); 45 | cancelButton.setText(R.string.Preview); 46 | // cancelButton.getPaint().setFakeBoldText(true); 47 | addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 48 | LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); 49 | 50 | doneButton = new LinearLayout(context); 51 | doneButton.setOrientation(LinearLayout.HORIZONTAL); 52 | doneButton.setBackgroundDrawable( 53 | Theme.createBarSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR 54 | : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); 55 | doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); 56 | addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 57 | LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); 58 | 59 | doneButtonBadgeTextView = new TextView(context); 60 | // doneButtonBadgeTextView.getPaint().setFakeBoldText(true); 61 | doneButtonBadgeTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); 62 | doneButtonBadgeTextView.setTextColor(0xffffffff); 63 | doneButtonBadgeTextView.setGravity(Gravity.CENTER); 64 | doneButtonBadgeTextView.setBackgroundResource( 65 | isDarkTheme ? R.drawable.photobadge_new : R.drawable.photobadge_new); 66 | doneButtonBadgeTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 67 | AndroidUtilities.dp(1)); 68 | doneButton.addView(doneButtonBadgeTextView, 69 | LayoutHelper.createLinear(26, 26, Gravity.CENTER_VERTICAL, 0, 0, 10, 0)); 70 | 71 | doneButtonTextView = new TextView(context); 72 | doneButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); 73 | doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff); 74 | doneButtonTextView.setGravity(Gravity.CENTER); 75 | doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); 76 | doneButtonTextView.setText(R.string.Send); 77 | // doneButtonTextView.getPaint().setFakeBoldText(true); 78 | doneButton.addView(doneButtonTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 79 | LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); 80 | } 81 | 82 | public void updateSelectedCount(int count, boolean disable) { 83 | if (count == 0) { 84 | doneButtonBadgeTextView.setVisibility(View.GONE); 85 | 86 | if (disable) { 87 | doneButtonTextView.setTextColor(0xff999999); 88 | cancelButton.setTextColor(0xff999999); 89 | doneButton.setEnabled(false); 90 | cancelButton.setEnabled(false); 91 | } else { 92 | // doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff19a7e8); 93 | doneButtonTextView.setTextColor( 94 | PhotoAlbumPickerActivity.limitPickPhoto == 1 ? 0xffffffff : 0xff999999); 95 | } 96 | } else { 97 | doneButtonTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); 98 | doneButtonBadgeTextView.setVisibility(View.VISIBLE); 99 | doneButtonBadgeTextView.setText(String.format("%d", count)); 100 | 101 | doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff); 102 | cancelButton.setTextColor(isDarkTheme ? 0xffffffff : 0xff007aff); 103 | if (disable) { 104 | doneButton.setEnabled(true); 105 | cancelButton.setEnabled(true); 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/src/main/java/com/hc/gallery/util/ExternalStorage.java: -------------------------------------------------------------------------------- 1 | package com.hc.gallery.util; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | import android.os.StatFs; 6 | import android.text.TextUtils; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | 11 | /** 12 | * 创建者:邓浩宸 13 | * 时间 :2017/4/20 13:01 14 | * 描述 :TODO 请描述该类职责 15 | */ 16 | class ExternalStorage { 17 | /** 18 | * 外部存储根目录 19 | */ 20 | private String sdkStorageRoot = null; 21 | 22 | private static ExternalStorage instance; 23 | 24 | private ExternalStorage() { 25 | 26 | } 27 | 28 | synchronized public static ExternalStorage getInstance() { 29 | if (instance == null) { 30 | instance = new ExternalStorage(); 31 | } 32 | return instance; 33 | } 34 | 35 | public void init(Context context, String sdkStorageRoot) { 36 | if (!TextUtils.isEmpty(sdkStorageRoot)) { 37 | File dir = new File(sdkStorageRoot); 38 | if (!dir.exists()) { 39 | dir.mkdirs(); 40 | } 41 | if (dir.exists() && !dir.isFile()) { 42 | this.sdkStorageRoot = sdkStorageRoot; 43 | if (!sdkStorageRoot.endsWith("/")) { 44 | this.sdkStorageRoot = sdkStorageRoot + "/"; 45 | } 46 | } 47 | } 48 | 49 | if (TextUtils.isEmpty(this.sdkStorageRoot)) { 50 | loadStorageState(context); 51 | } 52 | 53 | createSubFolders(); 54 | } 55 | 56 | private void loadStorageState(Context context) { 57 | String externalPath = Environment.getExternalStorageDirectory().getPath(); 58 | this.sdkStorageRoot = externalPath + "/" + context.getPackageName() + "/"; 59 | } 60 | 61 | private void createSubFolders() { 62 | boolean result = true; 63 | File root = new File(sdkStorageRoot); 64 | if (root.exists() && !root.isDirectory()) { 65 | root.delete(); 66 | } 67 | for (StorageType storageType : StorageType.values()) { 68 | result &= makeDirectory(sdkStorageRoot + storageType.getStoragePath()); 69 | } 70 | if (result) { 71 | createNoMediaFile(sdkStorageRoot); 72 | } 73 | } 74 | 75 | /** 76 | * 创建目录 77 | * 78 | * @param path 79 | * @return 80 | */ 81 | private boolean makeDirectory(String path) { 82 | File file = new File(path); 83 | boolean exist = file.exists(); 84 | if (!exist) { 85 | exist = file.mkdirs(); 86 | } 87 | return exist; 88 | } 89 | 90 | protected static String NO_MEDIA_FILE_NAME = ".nomedia"; 91 | 92 | private void createNoMediaFile(String path) { 93 | File noMediaFile = new File(path + "/" + NO_MEDIA_FILE_NAME); 94 | try { 95 | if (!noMediaFile.exists()) { 96 | noMediaFile.createNewFile(); 97 | } 98 | } catch (IOException e) { 99 | e.printStackTrace(); 100 | } 101 | } 102 | 103 | /** 104 | * 文件全名转绝对路径(写) 105 | * 106 | * @param fileName 107 | * 文件全名(文件名.扩展名) 108 | * @return 返回绝对路径信息 109 | */ 110 | public String getWritePath(String fileName, StorageType fileType) { 111 | return pathForName(fileName, fileType, false, false); 112 | } 113 | 114 | private String pathForName(String fileName, StorageType type, boolean dir, 115 | boolean check) { 116 | String directory = getDirectoryByDirType(type); 117 | StringBuilder path = new StringBuilder(directory); 118 | 119 | if (!dir) { 120 | path.append(fileName); 121 | } 122 | 123 | String pathString = path.toString(); 124 | File file = new File(pathString); 125 | 126 | if (check) { 127 | if (file.exists()) { 128 | if ((dir && file.isDirectory()) 129 | || (!dir && !file.isDirectory())) { 130 | return pathString; 131 | } 132 | } 133 | 134 | return ""; 135 | } else { 136 | return pathString; 137 | } 138 | } 139 | 140 | /** 141 | * 返回指定类型的文件夹路径 142 | * 143 | * @param fileType 144 | * @return 145 | */ 146 | public String getDirectoryByDirType(StorageType fileType) { 147 | return sdkStorageRoot + fileType.getStoragePath(); 148 | } 149 | 150 | /** 151 | * 根据输入的文件名和类型,找到该文件的全路径。 152 | * @param fileName 153 | * @param fileType 154 | * @return 如果存在该文件,返回路径,否则返回空 155 | */ 156 | public String getReadPath(String fileName, StorageType fileType) { 157 | if (TextUtils.isEmpty(fileName)) { 158 | return ""; 159 | } 160 | 161 | return pathForName(fileName, fileType, false, true); 162 | } 163 | 164 | public boolean isSdkStorageReady() { 165 | String externalRoot = Environment.getExternalStorageDirectory().getAbsolutePath(); 166 | if (this.sdkStorageRoot.startsWith(externalRoot)) { 167 | return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); 168 | } else { 169 | return true; 170 | } 171 | } 172 | 173 | /** 174 | * 获取外置存储卡剩余空间 175 | * @return 176 | */ 177 | public long getAvailableExternalSize() { 178 | return getResidualSpace(sdkStorageRoot); 179 | } 180 | 181 | /** 182 | * 获取目录剩余空间 183 | * @param directoryPath 184 | * @return 185 | */ 186 | private long getResidualSpace(String directoryPath) { 187 | try { 188 | StatFs sf = new StatFs(directoryPath); 189 | long blockSize = sf.getBlockSize(); 190 | long availCount = sf.getAvailableBlocks(); 191 | long availCountByte = availCount * blockSize; 192 | return availCountByte; 193 | } catch (Exception e) { 194 | e.printStackTrace(); 195 | } 196 | return 0; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/PhotoPickerPhotoCell.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.components; 3 | 4 | import android.animation.Animator; 5 | import android.animation.AnimatorSet; 6 | import android.animation.ObjectAnimator; 7 | import android.content.Context; 8 | import android.view.Gravity; 9 | import android.widget.FrameLayout; 10 | 11 | import com.dhc.gallery.R; 12 | import com.dhc.gallery.proxy.AnimatorListenerAdapterProxy; 13 | import com.dhc.gallery.utils.AndroidUtilities; 14 | import com.dhc.gallery.utils.LayoutHelper; 15 | 16 | import static com.dhc.gallery.ui.PhotoAlbumPickerActivity.DarkTheme; 17 | 18 | public class PhotoPickerPhotoCell extends FrameLayout { 19 | 20 | public BackupImageView photoImage; 21 | public FrameLayout checkFrame; 22 | public CheckBox checkBox; 23 | private AnimatorSet animator; 24 | public int itemWidth; 25 | 26 | public PhotoPickerPhotoCell(Context context) { 27 | super(context); 28 | 29 | photoImage = new BackupImageView(context); 30 | addView(photoImage, 31 | LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); 32 | 33 | checkFrame = new FrameLayout(context); 34 | addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.RIGHT | Gravity.TOP)); 35 | 36 | checkBox = new CheckBox(context, R.drawable.checkbig); 37 | checkBox.setSize(24); 38 | checkBox.setCheckOffset(AndroidUtilities.dp(1)); 39 | checkBox.setDrawBackground(true); 40 | checkBox.setColor(0xff007aff); 41 | addView(checkBox, 42 | LayoutHelper.createFrame(24, 24, Gravity.RIGHT | Gravity.TOP, 0, 4, 4, 0)); 43 | } 44 | 45 | @Override 46 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 47 | super.onMeasure(MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY), 48 | MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY)); 49 | } 50 | 51 | public void setChecked(final boolean checked, final boolean animated) { 52 | checkBox.setChecked(checked, animated); 53 | if (animator != null) { 54 | animator.cancel(); 55 | animator = null; 56 | } 57 | if (animated) { 58 | if (checked) { 59 | setBackgroundColor(DarkTheme ? 0xff0A0A0A : 0xffffffff); 60 | } 61 | animator = new AnimatorSet(); 62 | animator.playTogether( 63 | ObjectAnimator.ofFloat(photoImage, "scaleX", checked ? 0.85f : 1.0f), 64 | ObjectAnimator.ofFloat(photoImage, "scaleY", checked ? 0.85f : 1.0f)); 65 | animator.setDuration(200); 66 | animator.addListener(new AnimatorListenerAdapterProxy() { 67 | @Override 68 | public void onAnimationEnd(Animator animation) { 69 | if (animator != null && animator.equals(animation)) { 70 | animator = null; 71 | if (!checked) { 72 | setBackgroundColor(0); 73 | } 74 | } 75 | } 76 | 77 | @Override 78 | public void onAnimationCancel(Animator animation) { 79 | if (animator != null && animator.equals(animation)) { 80 | animator = null; 81 | } 82 | } 83 | }); 84 | animator.start(); 85 | } else { 86 | setBackgroundColor(checked ? DarkTheme ? 0xff0A0A0A : 0xffffffff : 0); 87 | photoImage.setScaleX(checked ? 0.85f : 1.0f); 88 | photoImage.setScaleY(checked ? 0.85f : 1.0f); 89 | } 90 | } 91 | 92 | public void setChecked(int num, final boolean checked, final boolean animated) { 93 | checkBox.setChecked(num, checked, animated); 94 | if (animator != null) { 95 | animator.cancel(); 96 | animator = null; 97 | } 98 | if (animated) { 99 | if (checked) { 100 | setBackgroundColor(DarkTheme ? 0xff0A0A0A : 0xffffffff); 101 | } 102 | animator = new AnimatorSet(); 103 | animator.playTogether( 104 | ObjectAnimator.ofFloat(photoImage, "scaleX", checked ? 0.85f : 1.0f), 105 | ObjectAnimator.ofFloat(photoImage, "scaleY", checked ? 0.85f : 1.0f)); 106 | animator.setDuration(200); 107 | animator.addListener(new AnimatorListenerAdapterProxy() { 108 | @Override 109 | public void onAnimationEnd(Animator animation) { 110 | if (animator != null && animator.equals(animation)) { 111 | animator = null; 112 | if (!checked) { 113 | setBackgroundColor(0); 114 | } 115 | } 116 | } 117 | 118 | @Override 119 | public void onAnimationCancel(Animator animation) { 120 | if (animator != null && animator.equals(animation)) { 121 | animator = null; 122 | } 123 | } 124 | }); 125 | animator.start(); 126 | } else { 127 | setBackgroundColor(checked ? DarkTheme ? 0xff0A0A0A : 0xffffffff : 0); 128 | photoImage.setScaleX(checked ? 0.85f : 1.0f); 129 | photoImage.setScaleY(checked ? 0.85f : 1.0f); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/PhotoPickerSearchCell.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.components; 2 | 3 | import android.content.Context; 4 | import android.os.Build; 5 | import android.text.TextUtils; 6 | import android.util.TypedValue; 7 | import android.view.Gravity; 8 | import android.view.MotionEvent; 9 | import android.view.View; 10 | import android.widget.FrameLayout; 11 | import android.widget.ImageView; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | 15 | import com.dhc.gallery.utils.AndroidUtilities; 16 | import com.dhc.gallery.utils.LayoutHelper; 17 | import com.dhc.gallery.R; 18 | 19 | public class PhotoPickerSearchCell extends LinearLayout { 20 | 21 | public interface PhotoPickerSearchCellDelegate { 22 | void didPressedSearchButton(int index); 23 | } 24 | 25 | private class SearchButton extends FrameLayout { 26 | 27 | private TextView textView1; 28 | private TextView textView2; 29 | private ImageView imageView; 30 | private View selector; 31 | 32 | public SearchButton(Context context) { 33 | super(context); 34 | 35 | setBackgroundColor(0xff1a1a1a); 36 | 37 | selector = new View(context); 38 | selector.setBackgroundResource(R.drawable.list_selector); 39 | addView(selector, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); 40 | 41 | imageView = new ImageView(context); 42 | imageView.setScaleType(ImageView.ScaleType.CENTER); 43 | addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); 44 | 45 | textView1 = new TextView(context); 46 | textView1.setGravity(Gravity.CENTER_VERTICAL); 47 | textView1.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); 48 | // textView1.getPaint().setFakeBoldText(true); 49 | textView1.setTextColor(0xffffffff); 50 | textView1.setSingleLine(true); 51 | textView1.setEllipsize(TextUtils.TruncateAt.END); 52 | addView(textView1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 51, 8, 4, 0)); 53 | 54 | textView2 = new TextView(context); 55 | textView2.setGravity(Gravity.CENTER_VERTICAL); 56 | textView2.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10); 57 | // textView2.getPaint().setFakeBoldText(true); 58 | textView2.setTextColor(0xff666666); 59 | textView2.setSingleLine(true); 60 | textView2.setEllipsize(TextUtils.TruncateAt.END); 61 | addView(textView2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 51, 26, 4, 0)); 62 | } 63 | 64 | @Override 65 | public boolean onTouchEvent(MotionEvent event) { 66 | if (Build.VERSION.SDK_INT >= 21) { 67 | selector.drawableHotspotChanged(event.getX(), event.getY()); 68 | } 69 | return super.onTouchEvent(event); 70 | } 71 | } 72 | 73 | private PhotoPickerSearchCellDelegate delegate; 74 | 75 | public PhotoPickerSearchCell(Context context, boolean allowGifs) { 76 | super(context); 77 | setOrientation(HORIZONTAL); 78 | 79 | SearchButton searchButton = new SearchButton(context); 80 | searchButton.textView1.setText(R.string.SearchImages); 81 | searchButton.textView2.setText(R.string.SearchImagesInfo); 82 | searchButton.imageView.setImageResource(R.drawable.search_web); 83 | addView(searchButton); 84 | LayoutParams layoutParams = (LayoutParams) searchButton.getLayoutParams(); 85 | layoutParams.weight = 0.5f; 86 | layoutParams.topMargin = AndroidUtilities.dp(4); 87 | layoutParams.height = AndroidUtilities.dp(48); 88 | layoutParams.width = 0; 89 | searchButton.setLayoutParams(layoutParams); 90 | searchButton.setOnClickListener(new OnClickListener() { 91 | @Override 92 | public void onClick(View v) { 93 | if (delegate != null) { 94 | delegate.didPressedSearchButton(0); 95 | } 96 | } 97 | }); 98 | 99 | FrameLayout frameLayout = new FrameLayout(context); 100 | frameLayout.setBackgroundColor(0); 101 | addView(frameLayout); 102 | layoutParams = (LayoutParams) frameLayout.getLayoutParams(); 103 | layoutParams.topMargin = AndroidUtilities.dp(4); 104 | layoutParams.height = AndroidUtilities.dp(48); 105 | layoutParams.width = AndroidUtilities.dp(4); 106 | frameLayout.setLayoutParams(layoutParams); 107 | 108 | searchButton = new SearchButton(context); 109 | searchButton.textView1.setText(R.string.SearchGifs); 110 | searchButton.textView2.setText("GIPHY"); 111 | searchButton.imageView.setImageResource(R.drawable.search_gif); 112 | addView(searchButton); 113 | layoutParams = (LayoutParams) searchButton.getLayoutParams(); 114 | layoutParams.weight = 0.5f; 115 | layoutParams.topMargin = AndroidUtilities.dp(4); 116 | layoutParams.height = AndroidUtilities.dp(48); 117 | layoutParams.width = 0; 118 | searchButton.setLayoutParams(layoutParams); 119 | if (allowGifs) { 120 | searchButton.setOnClickListener(new OnClickListener() { 121 | @Override 122 | public void onClick(View v) { 123 | if (delegate != null) { 124 | delegate.didPressedSearchButton(1); 125 | } 126 | } 127 | }); 128 | } else { 129 | searchButton.setAlpha(0.5f); 130 | } 131 | } 132 | 133 | public void setDelegate(PhotoPickerSearchCellDelegate delegate) { 134 | this.delegate = delegate; 135 | } 136 | 137 | @Override 138 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 139 | super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(52), MeasureSpec.EXACTLY)); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/GalleryHelper.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery; 2 | 3 | import android.app.Activity; 4 | import android.app.Fragment; 5 | import android.os.Environment; 6 | import android.provider.MediaStore; 7 | import android.widget.Toast; 8 | 9 | import com.dhc.gallery.ui.GalleryActivity; 10 | 11 | import static android.os.Environment.MEDIA_MOUNTED; 12 | 13 | 14 | /** 15 | * 创建者 邓浩宸 16 | * 创建时间 2017/4/17 15:52 17 | * 描述

18 | *

1, 选择单张图片 返回 String path 19 | *

2, 选择多张图片 返回 List 20 | *

3, 选择单张图片并裁剪 如果有输入path路径 返回 String path 否则返回 byte [] data 数据 21 | *

4, 拍照 返回 String path 22 | *

5, 拍照并裁剪 如果有输入path路径 返回 String path 否则返回 byte [] data 数据 23 | *

6, 摄影 返回 String path 24 | *

7, 选着视频 返回 String path 25 | */ 26 | public class GalleryHelper { 27 | 28 | 29 | public GalleryHelper() { 30 | } 31 | private Activity mActivity; 32 | private Fragment mFragment; 33 | private android.support.v4.app.Fragment mV4Fragment; 34 | 35 | 36 | GalleryConfig configuration = new GalleryConfig(); 37 | static GalleryHelper instance; 38 | 39 | /** 40 | * 开启页面 41 | * @param mActivity 42 | * @return 43 | */ 44 | public static GalleryHelper with(Activity mActivity) { 45 | instance = new GalleryHelper(); 46 | instance.mActivity=mActivity; 47 | return instance; 48 | } 49 | 50 | /** 51 | * 开启页面 52 | * @param mFragment 53 | * @return 54 | */ 55 | public static GalleryHelper with(Fragment mFragment ){ 56 | instance = new GalleryHelper(); 57 | instance.mFragment=mFragment; 58 | return instance; 59 | } 60 | /** 61 | * 开启页面 62 | * @param mV4Fragment 63 | * @return GalleryHelper 64 | */ 65 | public static GalleryHelper with(android.support.v4.app.Fragment mV4Fragment ){ 66 | instance = new GalleryHelper(); 67 | instance.mV4Fragment=mV4Fragment; 68 | return instance; 69 | } 70 | /** 71 | * 72 | * 选择的类型 73 | * @param type 74 | * {@link GalleryConfig.SELECT_PHOTO } 75 | * {@link GalleryConfig.TAKE_PHOTO } 76 | * {@link GalleryConfig.RECORD_VEDIO } 77 | * {@link GalleryConfig.SELECT_VEDIO } 78 | * {@link GalleryConfig.TAKEPHOTO_RECORDVEDIO } 79 | * @return GalleryHelper 80 | */ 81 | public GalleryHelper type(int type) { 82 | configuration.setType(type); 83 | return this; 84 | } 85 | 86 | /** 87 | * 响应码 88 | * @param type 89 | * @return GalleryHelper 90 | */ 91 | public GalleryHelper requestCode(int type) { 92 | configuration.setRequestCode(type); 93 | return this; 94 | } 95 | 96 | /** 97 | * 限定视频录制时间 98 | * @param limitRecordTime 99 | * @return GalleryHelper 100 | */ 101 | public GalleryHelper limitRecordTime(int limitRecordTime) { 102 | configuration.setLimitRecordTime(limitRecordTime); 103 | return this; 104 | } 105 | /** 106 | * 限定视频录制大小 107 | * @param limitRecordSize 108 | * @return GalleryHelper 109 | */ 110 | public GalleryHelper limitRecordSize(int limitRecordSize) { 111 | configuration.setLimitRecordSize(limitRecordSize); 112 | return this; 113 | } 114 | 115 | /** 116 | * 单选视频 117 | * @return 118 | */ 119 | public GalleryHelper isSingleVedio() { 120 | configuration.setSingleVedio(true); 121 | configuration.setFilterMimeTypes( new String[]{ 122 | MediaStore.Video.Media.DATA, 123 | MediaStore.Video.Media._ID, 124 | MediaStore.Video.Media.TITLE, 125 | MediaStore.Video.Media.MIME_TYPE 126 | }); 127 | return this; 128 | } 129 | 130 | /** 131 | * 需要裁剪图片 这将返回一个 byte[] data数据类型 132 | * @return 133 | */ 134 | public GalleryHelper isNeedCrop() { 135 | configuration.setNeedCrop(true); 136 | return this; 137 | } 138 | 139 | /** 140 | * 进行裁剪图片 返回一个传入路径值 141 | * @param filePath 142 | * @return 143 | */ 144 | public GalleryHelper isNeedCropWithPath(String filePath) { 145 | configuration.setNeedCrop(true); 146 | configuration.setFilePath(filePath); 147 | return this; 148 | } 149 | 150 | /** 151 | * @param filterMimeTypes filter of media type, based on MimeType standards: 152 | * {http://www.w3school.com.cn/media/media_mimeref.asp} 153 | *

  • eg:new string[]{"image/gif","image/jpeg"} 154 | */ 155 | public GalleryHelper selectVedioWithMimeTypes(String[] filterMimeTypes) { 156 | configuration.setSingleVedio(true); 157 | configuration.setFilterMimeTypes(filterMimeTypes); 158 | return this; 159 | } 160 | 161 | /** 162 | * @param hintOfPick hint of Toast when limit is reached 163 | */ 164 | public GalleryHelper hintOfPick(String hintOfPick) { 165 | configuration.setHintOfPick(hintOfPick); 166 | return this; 167 | } 168 | 169 | /** 170 | * 选择单张照片 171 | * @return 172 | */ 173 | public GalleryHelper singlePhoto() { 174 | configuration.setSinglePhoto(true); 175 | configuration.setLimitPickPhoto(1); 176 | return this; 177 | } 178 | 179 | /** 180 | * @param limitPickPhoto the limit of photos those can be selected 181 | */ 182 | public GalleryHelper limitPickPhoto(int limitPickPhoto) { 183 | configuration.setLimitPickPhoto(limitPickPhoto); 184 | return this; 185 | } 186 | 187 | 188 | public void execute() { 189 | if(mActivity == null&&mFragment==null&&mV4Fragment==null) { 190 | return; 191 | } 192 | if(!existSDcard()){ 193 | Toast.makeText(mActivity, "没有找到SD卡", Toast.LENGTH_SHORT).show(); 194 | return; 195 | } 196 | if (mActivity!=null){ 197 | GalleryActivity.openActivity(mActivity,configuration.getRequestCode(),configuration); 198 | }else if(mFragment!=null){ 199 | GalleryActivity.openActivity(mFragment,configuration.getRequestCode(),configuration); 200 | }else if(mV4Fragment!=null){ 201 | GalleryActivity.openActivity(mV4Fragment,configuration.getRequestCode(),configuration); 202 | } 203 | } 204 | private boolean existSDcard() { 205 | String externalStorageState; 206 | try { 207 | externalStorageState = Environment.getExternalStorageState(); 208 | } catch (NullPointerException e) { // (sh)it happens (Issue #660) 209 | externalStorageState = ""; 210 | } catch (IncompatibleClassChangeError e) { // (sh)it happens too (Issue #989) 211 | externalStorageState = ""; 212 | } 213 | return MEDIA_MOUNTED.equals(externalStorageState); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KrGallery 2 | 3 | Crop , Video, Photos, from Telegram 4 | 5 | 一个集**拍照和选择图片,裁剪**,**录制视频和选择视频**的强大且流畅简洁的库。 6 | 7 | 8 | KrGallery摘取于[Telegram](https://github.com/DrKLO/Telegram "https://github.com/DrKLO/Telegram"),基于[@TelegramGallery](https://github.com/TangXiaoLv/TelegramGallery)开发,快速,高效,低耗,轻量级,使用简单。 9 | 10 | - [功能](#功能) 11 | - [效果](#效果) 12 | - [安装](#安装) 13 | - [用途](#用途) 14 | - [选择图片](#选择图片) 15 | - [拍照](#拍照) 16 | - [获取图片](#获取图片) 17 | - [录制视频](#录制视频) 18 | - [选择视频](#选择视频) 19 | - [获取视频](#获取视频) 20 | - [注意](#注意) 21 | - [API](#API说明) 22 | - [TODO](#TODO) 23 | - [作者](#作者) 24 | - [感谢](#感谢) 25 | - [更变日志]() 26 | 27 | ## 功能 28 | 29 | * 快速,高效,低耗 30 | * 简易的整合,轻量级 31 | * 基本没有依赖于任何的三方库 32 | * 集拍照,选择图片,裁剪,录制视频和选择视频为一体 33 | 34 | ---------- 35 | 36 | ## 安装 37 | 38 | [![](https://jitpack.io/v/chengzichen/KrGallery.svg)](https://jitpack.io/#chengzichen/KrGallery) [ ![Download](https://api.bintray.com/packages/chengzichen/maven/gallerylib/images/download.svg) ](https://bintray.com/chengzichen/maven/gallerylib/_latestVersion) 39 | 40 | - 方式一: 41 | 42 | **Step 1. 在根目录的gradle文件中配置** 43 | 44 | 45 | **Add it in your root build.gradle at the end of repositories:** 46 | 47 | 48 | allprojects { 49 | repositories { 50 | ... 51 | maven { url 'https://jitpack.io' } 52 | } 53 | } 54 | 55 | 56 | **step2 添加依赖:** 57 | 58 | dependencies { 59 | compile 'com.github.chengzichen:KrGallery:v1.03' 60 | } 61 | 62 | 63 | 64 | - 方式二: 65 | 66 | 67 | **Step 1. 在根目录的gradle文件中配置** 68 | 69 | allprojects { 70 | repositories { 71 | ... 72 | jcenter() 73 | } 74 | } 75 | 76 | 77 | **step2 添加依赖:** 78 | 79 | 80 | dependencies { 81 | compile 'com.dhc.krgallery:gallerylib:1.0.3' 82 | } 83 | 84 | 85 | 86 | ---------- 87 | 88 | 89 | ## 效果 90 | ![Image text](https://github.com/chengzichen/KrGallery/raw/master/gif/photos.gif) 91 | ![Image text](https://github.com/chengzichen/KrGallery/raw/master/gif/selectcrop.gif) 92 | ![Image text](https://github.com/chengzichen/KrGallery/raw/master/gif/photocrop.gif) 93 | ![Image text](https://github.com/chengzichen/KrGallery/raw/master/gif/video.gif) 94 | 95 | ## 用途 96 | 97 | ### 选择图片 98 | 99 | - **单选**(type:GalleryConfig.SELECT_PHOTO) 100 | 101 | GalleryHelper 102 | .with(MainActivity.this) //Activity or Fragment 103 | .type(GalleryConfig.SELECT_PHOTO) //选择类型 104 | .requestCode(12) //startResultActivity requestcode 自己定义 105 | .singlePhoto() //选择单张图片 106 | .execute(); 107 | 108 | 109 | - **多选**(type:GalleryConfig.SELECT_PHOTO) 110 | 111 | GalleryHelper 112 | .with(MainActivity.this) //Activity or Fragment 113 | .type(GalleryConfig.SELECT_PHOTO) //选择类型 114 | .requestCode(12) //startResultActivity requestcode 自己定义 115 | .limitPickPhoto(9) //图片选择张数 116 | .execute(); 117 | 118 | 119 | - **需要裁剪图片** 120 | 121 | String outputPath = StorageUtil.getWritePath(StorageUtil.get32UUID() + ".jpg", StorageType.TYPE_TEMP);//定义裁剪图片输出在sdcard的位置 122 | 123 | GalleryHelper 124 | .with(MainActivity.this) //Activity or Fragment 125 | .type(GalleryConfig.SELECT_PHOTO) //选择类型 126 | .requestCode(12) //startResultActivity requestcode 自己定义 127 | .singlePhoto() //选择单张图片 128 | .isNeedCropWithPath(outputPath) //需要裁剪并输出图片的路径,没有传入时返回数据为byte[] 129 | .execute(); 130 | 131 | 132 | 133 | ### 拍照 134 | 135 | - 拍照 136 | 137 | GalleryHelper 138 | .with(MainActivity.this) //Activity or Fragment 139 | .type(GalleryConfig.TAKE_PHOTO) //选择类型,拍照 140 | .requestCode(12) //startResultActivity requestcode 自己定义 141 | .execute(); 142 | 143 | 144 | - 需要裁剪图片 145 | 146 | outputPath = StorageUtil.getWritePath(StorageUtil.get32UUID() + ".jpg", StorageType.TYPE_TEMP); 147 | GalleryHelper 148 | .with(MainActivity.this) //Activity or Fragment 149 | .type(GalleryConfig.TAKE_PHOTO) //选择类型 150 | .isNeedCropWithPath(outputPath) //需要裁剪并输出图片的路径,没有传入时返回数据为byte[] 151 | .requestCode(12) //startResultActivity requestcode 自己定义 152 | .execute(); 153 | 154 | **onActivityResult** 155 | 156 | 157 | ### 获取图片 158 | 159 | 160 | 161 | 162 | > **在Acitivity 或者Fragment 中onActivityResult 方法** 163 | 164 | 165 | String path = dataIntent.getStringExtra(GalleryActivity.PHOTOS); 166 | 167 | 168 | > **注意 : 需要裁剪并输出图片的路径,没有传入时返回数据为byte[]** 169 | 170 | 171 | 172 | byte[] datas =dataIntent.getByteArrayExtra(GalleryActivity.DATA); 173 | 174 | ### 录制视频(可限制录制时间) 175 | 176 | 177 | GalleryHelper 178 | .with(MainActivity.this) //Activity or Fragment 179 | .type(GalleryConfig.RECORD_VEDIO)//选择类型 180 | .requestCode(12) //startResultActivity requestcode 自己定义 181 | .limitRecordTime(10) //定义录制视频时间 182 | .limitRecordSize(10) //定义录制视频时间 183 | .execute(); 184 | 185 | ### 选择视频 186 | 187 | GalleryHelper 188 | .with(MainActivity.this) //Activity or Fragment 189 | .type(GalleryConfig.SELECT_VEDIO)//Activity or Fragment 190 | .requestCode(12) //startResultActivity requestcode 自己定义 191 | .isSingleVedio() //是否是单选视频 192 | .execute(); 193 | 194 | 195 | ### 获取视频 196 | 197 | > **在Acitivity 或者Fragment 中onActivityResult 方法** 198 | 199 | 200 | String path = data.getStringExtra(GalleryActivity.VIDEO); 201 | 202 | ### 注意 203 | 204 | - **需要裁剪并输出图片的路径,没有传入时返回数据为byte[]** 205 | - **选取多张图片时裁剪只对第一张照片有效** 206 | - **选着视频目前支持单个视频** 207 | 208 | 209 | ### API说明 210 | 211 | - 类[GalleryHelper](KrGallery/gallery/src/main/java/com/dhc/gallery/GalleryHelper.java) 212 | 213 | 1. with() //Activity or Fragment 214 | 2. type(int type) 215 | 1. GalleryConfig.SELECT_PHOTO //选择图片 216 | 2. GalleryConfig.TAKE_PHOTO //拍照 217 | 3. GalleryConfig.RECORD_VEDIO //录制视频 218 | 4. GalleryConfig.SELECT_VEDIO //选择单个视频 219 | 5. GalleryConfig.TAKEPHOTO_RECORDVEDIO //拍照和录制视频 220 | 3. requestCode(int code) //startResultActivity requestcode 自己定义 221 | 4. isSingleVedio() //选择单个视频,必须调用方法 222 | 5. isNeedCropWithPath() //进行裁剪图片 返回一个传入路径值 223 | 6. isNeedCrop() //需要裁剪图片 这将返回一个 byte[] data数据类型 224 | 7. selectVedioWithMimeTypes() //filter of media type, based on MimeType standards:{http://www.w3school.com.cn/media/media_mimeref.asp}
  • eg:new string[]{"image/gif","image/jpeg"} 225 | 8. hintOfPick() //hint of Toast when limit is reached 226 | 9. singlePhoto() //选择单张照片 227 | 10. limitPickPhoto(int) //hint of Toast when limit is reached 228 | 11. limitRecordTime(int) //限制视频录制的时间 229 | 11. execute() 230 | 231 | 232 | ## TODO 233 | 234 | - 修改部分样式 235 | - 自定义主题 236 | - 视频的编辑 237 | - 图片的编辑 238 | - 提供压缩 239 | - 优化代码 240 | 241 | 242 | ## 作者 243 | 244 | 245 | 246 | - github: [@chengzichen](https://github.com/chengzichen) 247 | 248 | 249 | - 博客 : [邓浩宸的博客](https://chengzichen.github.io/) 250 | 251 | 252 | ## 感谢 253 | 254 | 255 | 256 | > [@Telegram](https://github.com/DrKLO/Telegram "https://github.com/DrKLO/Telegram") 257 | 258 | 259 | 260 | > [@TelegramGallery](https://github.com/TangXiaoLv/TelegramGallery) 261 | 262 | ## 友情链接 263 | 264 | 265 | 266 | > [@XDroid](https://github.com/limedroid) 老司机 -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/actionbar/ActionBarMenu.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.actionbar; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.LinearLayout; 8 | 9 | import com.dhc.gallery.Theme; 10 | import com.dhc.gallery.utils.AndroidUtilities; 11 | import com.dhc.gallery.utils.LayoutHelper; 12 | 13 | public class ActionBarMenu extends LinearLayout { 14 | 15 | protected ActionBar parentActionBar; 16 | 17 | public ActionBarMenu(Context context, ActionBar layer) { 18 | super(context); 19 | setOrientation(LinearLayout.HORIZONTAL); 20 | parentActionBar = layer; 21 | } 22 | 23 | public ActionBarMenu(Context context) { 24 | super(context); 25 | } 26 | 27 | public View addItemResource(int id, int resourceId) { 28 | LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 29 | View view = li.inflate(resourceId, null); 30 | view.setTag(id); 31 | addView(view); 32 | LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); 33 | layoutParams.height = LayoutHelper.MATCH_PARENT; 34 | view.setBackgroundDrawable(Theme.createBarSelectorDrawable(parentActionBar.itemsBackgroundColor)); 35 | view.setLayoutParams(layoutParams); 36 | view.setOnClickListener(new OnClickListener() { 37 | @Override 38 | public void onClick(View view) { 39 | onItemClick((Integer) view.getTag()); 40 | } 41 | }); 42 | return view; 43 | } 44 | 45 | public ActionBarMenuItem addItem(int id, Drawable drawable) { 46 | return addItem(id, 0, parentActionBar.itemsBackgroundColor, drawable, AndroidUtilities.dp(48)); 47 | } 48 | 49 | public ActionBarMenuItem addItem(int id, int icon) { 50 | return addItem(id, icon, parentActionBar.itemsBackgroundColor); 51 | } 52 | 53 | public ActionBarMenuItem addItem(int id, int icon, int backgroundColor) { 54 | return addItem(id, icon, backgroundColor, null, AndroidUtilities.dp(48)); 55 | } 56 | 57 | public ActionBarMenuItem addItemWithWidth(int id, int icon, int width) { 58 | return addItem(id, icon, parentActionBar.itemsBackgroundColor, null, width); 59 | } 60 | 61 | public ActionBarMenuItem addItem(int id, int icon, int backgroundColor, Drawable drawable, int width) { 62 | ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundColor); 63 | menuItem.setTag(id); 64 | if (drawable != null) { 65 | menuItem.iconView.setImageDrawable(drawable); 66 | } else { 67 | menuItem.iconView.setImageResource(icon); 68 | } 69 | addView(menuItem); 70 | LayoutParams layoutParams = (LayoutParams) menuItem.getLayoutParams(); 71 | layoutParams.height = LayoutHelper.MATCH_PARENT; 72 | layoutParams.width = width; 73 | menuItem.setLayoutParams(layoutParams); 74 | menuItem.setOnClickListener(new OnClickListener() { 75 | @Override 76 | public void onClick(View view) { 77 | ActionBarMenuItem item = (ActionBarMenuItem) view; 78 | if (item.hasSubMenu()) { 79 | if (parentActionBar.actionBarMenuOnItemClick.canOpenMenu()) { 80 | item.toggleSubMenu(); 81 | } 82 | } else if (item.isSearchField()) { 83 | parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(true)); 84 | } else { 85 | onItemClick((Integer) view.getTag()); 86 | } 87 | } 88 | }); 89 | return menuItem; 90 | } 91 | 92 | public View addItem(int id,View view) { 93 | view.setTag(id); 94 | addView(view); 95 | view.setOnClickListener(new OnClickListener() { 96 | @Override 97 | public void onClick(View view) { 98 | onItemClick((Integer) view.getTag()); 99 | } 100 | }); 101 | return view; 102 | } 103 | 104 | public void hideAllPopupMenus() { 105 | int count = getChildCount(); 106 | for (int a = 0; a < count; a++) { 107 | View view = getChildAt(a); 108 | if (view instanceof ActionBarMenuItem) { 109 | ((ActionBarMenuItem) view).closeSubMenu(); 110 | } 111 | } 112 | } 113 | 114 | public void onItemClick(int id) { 115 | if (parentActionBar.actionBarMenuOnItemClick != null) { 116 | parentActionBar.actionBarMenuOnItemClick.onItemClick(id); 117 | } 118 | } 119 | 120 | public void clearItems() { 121 | removeAllViews(); 122 | } 123 | 124 | public void onMenuButtonPressed() { 125 | int count = getChildCount(); 126 | for (int a = 0; a < count; a++) { 127 | View view = getChildAt(a); 128 | if (view instanceof ActionBarMenuItem) { 129 | ActionBarMenuItem item = (ActionBarMenuItem) view; 130 | if (item.getVisibility() != VISIBLE) { 131 | continue; 132 | } 133 | if (item.hasSubMenu()) { 134 | item.toggleSubMenu(); 135 | break; 136 | } else if (item.overrideMenuClick) { 137 | onItemClick((Integer) item.getTag()); 138 | break; 139 | } 140 | } 141 | } 142 | } 143 | 144 | public void closeSearchField() { 145 | int count = getChildCount(); 146 | for (int a = 0; a < count; a++) { 147 | View view = getChildAt(a); 148 | if (view instanceof ActionBarMenuItem) { 149 | ActionBarMenuItem item = (ActionBarMenuItem) view; 150 | if (item.isSearchField()) { 151 | parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(false)); 152 | break; 153 | } 154 | } 155 | } 156 | } 157 | 158 | public void openSearchField(boolean toggle, String text) { 159 | int count = getChildCount(); 160 | for (int a = 0; a < count; a++) { 161 | View view = getChildAt(a); 162 | if (view instanceof ActionBarMenuItem) { 163 | ActionBarMenuItem item = (ActionBarMenuItem) view; 164 | if (item.isSearchField()) { 165 | if (toggle) { 166 | parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch(true)); 167 | } 168 | item.getSearchField().setText(text); 169 | item.getSearchField().setSelection(text.length()); 170 | break; 171 | } 172 | } 173 | } 174 | } 175 | 176 | public ActionBarMenuItem getItem(int id) { 177 | View v = findViewWithTag(id); 178 | if (v instanceof ActionBarMenuItem) { 179 | return (ActionBarMenuItem) v; 180 | } 181 | return null; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/tl/Photo.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.tl; 3 | 4 | import java.util.ArrayList; 5 | 6 | public class Photo extends TLObject { 7 | public long id; 8 | public long access_hash; 9 | public int user_id; 10 | public int date; 11 | public String caption; 12 | public GeoPoint geo; 13 | public ArrayList sizes = new ArrayList<>(); 14 | 15 | public static Photo TLdeserialize(AbstractSerializedData stream, int constructor, 16 | boolean exception) { 17 | Photo result = null; 18 | switch (constructor) { 19 | case 0x22b56751: 20 | result = new TL_photo_old(); 21 | break; 22 | case 0xcded42fe: 23 | result = new TL_photo(); 24 | break; 25 | case 0xc3838076: 26 | result = new TL_photo_old2(); 27 | break; 28 | case 0x2331b22d: 29 | result = new TL_photoEmpty(); 30 | break; 31 | } 32 | if (result == null && exception) { 33 | throw new RuntimeException(String.format("can't parse magic %x in Photo", constructor)); 34 | } 35 | if (result != null) { 36 | result.readParams(stream, exception); 37 | } 38 | return result; 39 | } 40 | 41 | public static class TL_photo_old extends TL_photo { 42 | public static int constructor = 0x22b56751; 43 | 44 | public void readParams(AbstractSerializedData stream, boolean exception) { 45 | id = stream.readInt64(exception); 46 | access_hash = stream.readInt64(exception); 47 | user_id = stream.readInt32(exception); 48 | date = stream.readInt32(exception); 49 | caption = stream.readString(exception); 50 | geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); 51 | int magic = stream.readInt32(exception); 52 | if (magic != 0x1cb5c415) { 53 | if (exception) { 54 | throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); 55 | } 56 | return; 57 | } 58 | int count = stream.readInt32(exception); 59 | for (int a = 0; a < count; a++) { 60 | PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), 61 | exception); 62 | if (object == null) { 63 | return; 64 | } 65 | sizes.add(object); 66 | } 67 | } 68 | 69 | public void serializeToStream(AbstractSerializedData stream) { 70 | stream.writeInt32(constructor); 71 | stream.writeInt64(id); 72 | stream.writeInt64(access_hash); 73 | stream.writeInt32(user_id); 74 | stream.writeInt32(date); 75 | stream.writeString(caption); 76 | geo.serializeToStream(stream); 77 | stream.writeInt32(0x1cb5c415); 78 | int count = sizes.size(); 79 | stream.writeInt32(count); 80 | for (int a = 0; a < count; a++) { 81 | sizes.get(a).serializeToStream(stream); 82 | } 83 | } 84 | } 85 | 86 | public static class TL_photo extends Photo { 87 | public static int constructor = 0xcded42fe; 88 | 89 | public void readParams(AbstractSerializedData stream, boolean exception) { 90 | id = stream.readInt64(exception); 91 | access_hash = stream.readInt64(exception); 92 | date = stream.readInt32(exception); 93 | int magic = stream.readInt32(exception); 94 | if (magic != 0x1cb5c415) { 95 | if (exception) { 96 | throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); 97 | } 98 | return; 99 | } 100 | int count = stream.readInt32(exception); 101 | for (int a = 0; a < count; a++) { 102 | PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), 103 | exception); 104 | if (object == null) { 105 | return; 106 | } 107 | sizes.add(object); 108 | } 109 | } 110 | 111 | public void serializeToStream(AbstractSerializedData stream) { 112 | stream.writeInt32(constructor); 113 | stream.writeInt64(id); 114 | stream.writeInt64(access_hash); 115 | stream.writeInt32(date); 116 | stream.writeInt32(0x1cb5c415); 117 | int count = sizes.size(); 118 | stream.writeInt32(count); 119 | for (int a = 0; a < count; a++) { 120 | sizes.get(a).serializeToStream(stream); 121 | } 122 | } 123 | } 124 | 125 | public static class TL_photo_old2 extends TL_photo { 126 | public static int constructor = 0xc3838076; 127 | 128 | public void readParams(AbstractSerializedData stream, boolean exception) { 129 | id = stream.readInt64(exception); 130 | access_hash = stream.readInt64(exception); 131 | user_id = stream.readInt32(exception); 132 | date = stream.readInt32(exception); 133 | geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); 134 | int magic = stream.readInt32(exception); 135 | if (magic != 0x1cb5c415) { 136 | if (exception) { 137 | throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); 138 | } 139 | return; 140 | } 141 | int count = stream.readInt32(exception); 142 | for (int a = 0; a < count; a++) { 143 | PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), 144 | exception); 145 | if (object == null) { 146 | return; 147 | } 148 | sizes.add(object); 149 | } 150 | } 151 | 152 | public void serializeToStream(AbstractSerializedData stream) { 153 | stream.writeInt32(constructor); 154 | stream.writeInt64(id); 155 | stream.writeInt64(access_hash); 156 | stream.writeInt32(user_id); 157 | stream.writeInt32(date); 158 | geo.serializeToStream(stream); 159 | stream.writeInt32(0x1cb5c415); 160 | int count = sizes.size(); 161 | stream.writeInt32(count); 162 | for (int a = 0; a < count; a++) { 163 | sizes.get(a).serializeToStream(stream); 164 | } 165 | } 166 | } 167 | 168 | public static class TL_photoEmpty extends Photo { 169 | public static int constructor = 0x2331b22d; 170 | 171 | public void readParams(AbstractSerializedData stream, boolean exception) { 172 | id = stream.readInt64(exception); 173 | } 174 | 175 | public void serializeToStream(AbstractSerializedData stream) { 176 | stream.writeInt32(constructor); 177 | stream.writeInt64(id); 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/PhotoPickerAlbumsCell.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.components; 3 | 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.text.TextUtils; 7 | import android.util.TypedValue; 8 | import android.view.Gravity; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.widget.FrameLayout; 12 | import android.widget.LinearLayout; 13 | import android.widget.TextView; 14 | 15 | import com.dhc.gallery.utils.AndroidUtilities; 16 | import com.dhc.gallery.utils.LayoutHelper; 17 | import com.dhc.gallery.utils.MediaController; 18 | import com.dhc.gallery.R; 19 | 20 | public class PhotoPickerAlbumsCell extends FrameLayout { 21 | 22 | public interface PhotoPickerAlbumsCellDelegate { 23 | void didSelectAlbum(MediaController.AlbumEntry albumEntry); 24 | } 25 | 26 | private AlbumView[] albumViews; 27 | private MediaController.AlbumEntry[] albumEntries; 28 | private int albumsCount; 29 | private PhotoPickerAlbumsCellDelegate delegate; 30 | 31 | private class AlbumView extends FrameLayout { 32 | 33 | private BackupImageView imageView; 34 | private TextView nameTextView; 35 | private TextView countTextView; 36 | private View selector; 37 | 38 | public AlbumView(Context context) { 39 | super(context); 40 | 41 | imageView = new BackupImageView(context); 42 | addView(imageView, 43 | LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); 44 | 45 | LinearLayout linearLayout = new LinearLayout(context); 46 | linearLayout.setOrientation(LinearLayout.HORIZONTAL); 47 | linearLayout.setBackgroundColor(0x7f000000); 48 | addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 28, 49 | Gravity.LEFT | Gravity.BOTTOM)); 50 | 51 | nameTextView = new TextView(context); 52 | nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); 53 | nameTextView.setTextColor(0xffffffff); 54 | nameTextView.setSingleLine(true); 55 | nameTextView.setEllipsize(TextUtils.TruncateAt.END); 56 | nameTextView.setMaxLines(1); 57 | nameTextView.setGravity(Gravity.CENTER_VERTICAL); 58 | linearLayout.addView(nameTextView, 59 | LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 8, 0, 0, 0)); 60 | 61 | countTextView = new TextView(context); 62 | countTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); 63 | countTextView.setTextColor(0xffaaaaaa); 64 | countTextView.setSingleLine(true); 65 | countTextView.setEllipsize(TextUtils.TruncateAt.END); 66 | countTextView.setMaxLines(1); 67 | countTextView.setGravity(Gravity.CENTER_VERTICAL); 68 | linearLayout.addView(countTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 69 | LayoutHelper.MATCH_PARENT, 4, 0, 4, 0)); 70 | 71 | selector = new View(context); 72 | selector.setBackgroundResource(R.drawable.list_selector); 73 | addView(selector, 74 | LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); 75 | } 76 | 77 | @Override 78 | public boolean onTouchEvent(MotionEvent event) { 79 | if (Build.VERSION.SDK_INT >= 21) { 80 | selector.drawableHotspotChanged(event.getX(), event.getY()); 81 | } 82 | return super.onTouchEvent(event); 83 | } 84 | } 85 | 86 | public PhotoPickerAlbumsCell(Context context) { 87 | super(context); 88 | albumEntries = new MediaController.AlbumEntry[4]; 89 | albumViews = new AlbumView[4]; 90 | for (int a = 0; a < 4; a++) { 91 | albumViews[a] = new AlbumView(context); 92 | addView(albumViews[a]); 93 | albumViews[a].setVisibility(INVISIBLE); 94 | albumViews[a].setTag(a); 95 | albumViews[a].setOnClickListener(new OnClickListener() { 96 | @Override 97 | public void onClick(View v) { 98 | if (delegate != null) { 99 | delegate.didSelectAlbum(albumEntries[(Integer) v.getTag()]); 100 | } 101 | } 102 | }); 103 | } 104 | } 105 | 106 | public void setAlbumsCount(int count) { 107 | for (int a = 0; a < albumViews.length; a++) { 108 | albumViews[a].setVisibility(a < count ? VISIBLE : INVISIBLE); 109 | } 110 | albumsCount = count; 111 | } 112 | 113 | public void setDelegate(PhotoPickerAlbumsCellDelegate delegate) { 114 | this.delegate = delegate; 115 | } 116 | 117 | public void setAlbum(int a, MediaController.AlbumEntry albumEntry) { 118 | albumEntries[a] = albumEntry; 119 | 120 | if (albumEntry != null) { 121 | AlbumView albumView = albumViews[a]; 122 | albumView.imageView.setOrientation(0, true); 123 | if (albumEntry.coverPhoto != null && albumEntry.coverPhoto.path != null) { 124 | albumView.imageView.setOrientation(albumEntry.coverPhoto.orientation, true); 125 | if (albumEntry.coverPhoto.isVideo) { 126 | albumView.imageView.setImage( 127 | "vthumb://" + albumEntry.coverPhoto.imageId + ":" 128 | + albumEntry.coverPhoto.path, 129 | null, getContext().getResources().getDrawable(R.drawable.nophotos)); 130 | } else { 131 | albumView.imageView.setImage( 132 | "thumb://" + albumEntry.coverPhoto.imageId + ":" 133 | + albumEntry.coverPhoto.path, 134 | null, getContext().getResources().getDrawable(R.drawable.nophotos)); 135 | } 136 | } else { 137 | albumView.imageView.setImageResource(R.drawable.nophotos); 138 | } 139 | albumView.nameTextView.setText(albumEntry.bucketName); 140 | albumView.countTextView.setText(String.format("%d", albumEntry.photos.size())); 141 | } else { 142 | albumViews[a].setVisibility(INVISIBLE); 143 | } 144 | } 145 | 146 | @Override 147 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 148 | int itemWidth; 149 | if (AndroidUtilities.isTablet()) { 150 | itemWidth = (AndroidUtilities.dp(490) - ((albumsCount + 1) * AndroidUtilities.dp(4))) 151 | / albumsCount; 152 | } else { 153 | itemWidth = (AndroidUtilities.displaySize.x 154 | - ((albumsCount + 1) * AndroidUtilities.dp(4))) / albumsCount; 155 | } 156 | 157 | for (int a = 0; a < albumsCount; a++) { 158 | LayoutParams layoutParams = (LayoutParams) albumViews[a].getLayoutParams(); 159 | layoutParams.topMargin = AndroidUtilities.dp(4); 160 | layoutParams.leftMargin = (itemWidth + AndroidUtilities.dp(4)) * a; 161 | layoutParams.width = itemWidth; 162 | layoutParams.height = itemWidth; 163 | layoutParams.gravity = Gravity.LEFT | Gravity.TOP; 164 | albumViews[a].setLayoutParams(layoutParams); 165 | } 166 | 167 | super.onMeasure(widthMeasureSpec, MeasureSpec 168 | .makeMeasureSpec(AndroidUtilities.dp(4) + itemWidth, MeasureSpec.EXACTLY)); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/BaseDialog.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.components; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.os.Handler; 7 | import android.util.DisplayMetrics; 8 | import android.view.Gravity; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.Window; 12 | import android.view.WindowManager; 13 | import android.widget.Button; 14 | import android.widget.FrameLayout; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | 18 | import com.dhc.gallery.R; 19 | import com.dhc.gallery.utils.AndroidUtilities; 20 | 21 | 22 | /** 23 | * Created by shiming on 16/11/28. 24 | */ 25 | 26 | public class BaseDialog extends Dialog implements View.OnClickListener,DialogInterface.OnDismissListener { 27 | 28 | private Context mContext; 29 | 30 | private FrameLayout mContainer; 31 | 32 | private FrameLayout mBtnPanel; 33 | 34 | private int lifeTime; 35 | 36 | private Handler handler; 37 | 38 | private OnClickListener mListener; 39 | private ImageView closeIV; 40 | 41 | public BaseDialog(Context context) { 42 | super(context, R.style.dialog_custom); 43 | mContext = context; 44 | handler = new Handler(context.getMainLooper()); 45 | initView(); 46 | } 47 | 48 | private void initView() { 49 | Window window = getWindow(); 50 | window.setGravity(Gravity.CENTER); // 此处可以设置dialog显示的位置为居中 51 | window.setWindowAnimations(R.style.bottom_menu_animation); // 添加动画效果 52 | View child = getLayoutInflater().inflate(R.layout.layout_dialog_base, null, false); 53 | setContentView(child); 54 | mContainer = (FrameLayout) findViewById(R.id.fl_container); 55 | mBtnPanel = (FrameLayout) findViewById(R.id.fl_btn_panel); 56 | closeIV = (ImageView) findViewById(R.id.iv_close); 57 | closeIV.setOnClickListener(new View.OnClickListener() { 58 | @Override 59 | public void onClick(View view) { 60 | dismiss(); 61 | } 62 | }); 63 | Window dialogWindow = getWindow(); 64 | WindowManager.LayoutParams lp = dialogWindow.getAttributes(); 65 | DisplayMetrics d = mContext.getResources().getDisplayMetrics(); // 获取屏幕宽、高用 66 | lp.width = (int) (d.widthPixels * 0.8); // 宽度设置为屏幕的0.9 67 | dialogWindow.setAttributes(lp); 68 | setIsCancelable(true); 69 | 70 | setOnDismissListener(this); 71 | } 72 | 73 | public BaseDialog setLifeTime(int seconds){ 74 | lifeTime = seconds; 75 | return this; 76 | } 77 | 78 | public BaseDialog setWindowAnimation(int style){ 79 | getWindow().setWindowAnimations(style); 80 | return this; 81 | } 82 | 83 | public BaseDialog showCloseBtn(boolean isShow){ 84 | if (isShow){ 85 | closeIV.setVisibility(View.VISIBLE); 86 | }else{ 87 | closeIV.setVisibility(View.GONE); 88 | } 89 | return this; 90 | } 91 | 92 | public BaseDialog setCloseBtnClickListener(View.OnClickListener listener){ 93 | closeIV.setOnClickListener(listener); 94 | return this; 95 | } 96 | 97 | public BaseDialog setMatchParent() { 98 | Window dialogWindow = getWindow(); 99 | WindowManager.LayoutParams lp = dialogWindow.getAttributes(); 100 | lp.width = WindowManager.LayoutParams.MATCH_PARENT; 101 | dialogWindow.setAttributes(lp); 102 | return this; 103 | } 104 | 105 | public BaseDialog setWindowBackground(int color){ 106 | mContainer.setBackgroundColor(mContext.getResources().getColor(color)); 107 | mBtnPanel.setBackgroundColor(mContext.getResources().getColor(color)); 108 | return this; 109 | } 110 | 111 | public BaseDialog setDialogSize(float widthDP,float heightDP){ 112 | Window dialogWindow = getWindow(); 113 | WindowManager.LayoutParams lp = dialogWindow.getAttributes(); 114 | lp.width = AndroidUtilities.dp2px(getContext(),widthDP); 115 | lp.height = AndroidUtilities.dp2px(getContext(),heightDP); 116 | dialogWindow.setAttributes(lp); 117 | return this; 118 | } 119 | 120 | public BaseDialog setGravity(int gravity) { 121 | getWindow().setGravity(gravity); 122 | return this; 123 | } 124 | 125 | public BaseDialog setIsCancelable(boolean isCancelable) { 126 | setCancelable(isCancelable); 127 | return this; 128 | } 129 | 130 | public BaseDialog setCanCancelOutside(boolean isCan){ 131 | setCanceledOnTouchOutside(isCan); 132 | return this; 133 | } 134 | 135 | public BaseDialog setCustomerContent(int layoutId) { 136 | View child = getLayoutInflater().inflate(layoutId, null, false); 137 | mContainer.addView(child); 138 | return this; 139 | } 140 | 141 | 142 | 143 | public BaseDialog setBackgroundResource(int viewId, int resId) { 144 | findViewById(viewId).setBackgroundResource(resId); 145 | return this; 146 | } 147 | 148 | public BaseDialog setText(int viewId, int textId) { 149 | ((TextView) findViewById(viewId)).setText(textId); 150 | return this; 151 | } 152 | public BaseDialog setText(int viewId, String text) { 153 | ((TextView) findViewById(viewId)).setText(text); 154 | return this; 155 | } 156 | 157 | 158 | public BaseDialog setTextColor(int viewId, int colorId) { 159 | ((TextView) findViewById(viewId)).setTextColor(colorId); 160 | return this; 161 | } 162 | 163 | public BaseDialog setImageResource(int viewId, int resId) { 164 | ((ImageView) findViewById(viewId)).setImageResource(resId); 165 | return this; 166 | } 167 | 168 | public BaseDialog setViewOnClickListener(int viewId, View.OnClickListener listener) { 169 | findViewById(viewId).setOnClickListener(listener); 170 | return this; 171 | } 172 | 173 | @Override 174 | public void show() { 175 | super.show(); 176 | if (lifeTime > 0){ 177 | handler.postDelayed(new Runnable() { 178 | @Override 179 | public void run() { 180 | dismiss(); 181 | } 182 | },lifeTime * 1000); 183 | } 184 | } 185 | 186 | public BaseDialog setListener(OnClickListener listener){ 187 | mListener = listener; 188 | return this; 189 | } 190 | 191 | 192 | public BaseDialog setBtnPanelView(int layoutId){ 193 | setBtnPanelView(layoutId,null); 194 | return this; 195 | } 196 | 197 | public BaseDialog setBtnPanelView(int layoutId, OnClickListener listener) { 198 | ViewGroup viewGroup = (ViewGroup) getLayoutInflater().inflate(layoutId, null, false); 199 | int count = viewGroup.getChildCount(); 200 | for (int i = 0; i < count; i++) { 201 | View child = viewGroup.getChildAt(i); 202 | if (child instanceof Button) { 203 | child.setOnClickListener(this); 204 | } 205 | } 206 | mListener = listener; 207 | mBtnPanel.addView(viewGroup); 208 | // 设置容器的背景 可以根据实际情况动态添加 209 | // mContainer.setBackgroundResource(R.drawable.zhenai_library_dialog_base_top_shape); 210 | return this; 211 | } 212 | 213 | @Override 214 | public void onClick(View view) { 215 | if (mListener != null) { 216 | mListener.onClick(this, view.getId()); 217 | } 218 | 219 | } 220 | 221 | @Override 222 | public void onDismiss(DialogInterface dialogInterface) { 223 | handler.removeCallbacksAndMessages(null); 224 | handler = null; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/utils/LayoutHelper.java: -------------------------------------------------------------------------------- 1 | 2 | package com.dhc.gallery.utils; 3 | 4 | import android.widget.FrameLayout; 5 | import android.widget.LinearLayout; 6 | import android.widget.RelativeLayout; 7 | import android.widget.ScrollView; 8 | 9 | public class LayoutHelper { 10 | 11 | public static final int MATCH_PARENT = -1; 12 | public static final int WRAP_CONTENT = -2; 13 | 14 | private static int getSize(float size) { 15 | return (int) (size < 0 ? size : AndroidUtilities.dp(size)); 16 | } 17 | 18 | public static FrameLayout.LayoutParams createScroll(int width, int height, int gravity) { 19 | return new ScrollView.LayoutParams(getSize(width), getSize(height), gravity); 20 | } 21 | 22 | public static FrameLayout.LayoutParams createFrame(int width, float height, int gravity, 23 | float leftMargin, float topMargin, float rightMargin, float bottomMargin) { 24 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(getSize(width), 25 | getSize(height), gravity); 26 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), 27 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin)); 28 | return layoutParams; 29 | } 30 | 31 | public static FrameLayout.LayoutParams createFrame(int width, int height, int gravity) { 32 | return new FrameLayout.LayoutParams(getSize(width), getSize(height), gravity); 33 | } 34 | 35 | public static FrameLayout.LayoutParams createFrame(int width, float height) { 36 | return new FrameLayout.LayoutParams(getSize(width), getSize(height)); 37 | } 38 | 39 | public static RelativeLayout.LayoutParams createRelative(float width, float height, 40 | int leftMargin, int topMargin, int rightMargin, int bottomMargin, int alignParent, 41 | int alignRelative, int anchorRelative) { 42 | RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(getSize(width), 43 | getSize(height)); 44 | if (alignParent >= 0) { 45 | layoutParams.addRule(alignParent); 46 | } 47 | if (alignRelative >= 0 && anchorRelative >= 0) { 48 | layoutParams.addRule(alignRelative, anchorRelative); 49 | } 50 | layoutParams.leftMargin = AndroidUtilities.dp(leftMargin); 51 | layoutParams.topMargin = AndroidUtilities.dp(topMargin); 52 | layoutParams.rightMargin = AndroidUtilities.dp(rightMargin); 53 | layoutParams.bottomMargin = AndroidUtilities.dp(bottomMargin); 54 | return layoutParams; 55 | } 56 | 57 | public static RelativeLayout.LayoutParams createRelative(int width, int height, int leftMargin, 58 | int topMargin, int rightMargin, int bottomMargin) { 59 | return createRelative(width, height, leftMargin, topMargin, rightMargin, bottomMargin, -1, 60 | -1, -1); 61 | } 62 | 63 | public static RelativeLayout.LayoutParams createRelative(int width, int height, int leftMargin, 64 | int topMargin, int rightMargin, int bottomMargin, int alignParent) { 65 | return createRelative(width, height, leftMargin, topMargin, rightMargin, bottomMargin, 66 | alignParent, -1, -1); 67 | } 68 | 69 | public static RelativeLayout.LayoutParams createRelative(float width, float height, 70 | int leftMargin, int topMargin, int rightMargin, int bottomMargin, int alignRelative, 71 | int anchorRelative) { 72 | return createRelative(width, height, leftMargin, topMargin, rightMargin, bottomMargin, -1, 73 | alignRelative, anchorRelative); 74 | } 75 | 76 | public static RelativeLayout.LayoutParams createRelative(int width, int height, int alignParent, 77 | int alignRelative, int anchorRelative) { 78 | return createRelative(width, height, 0, 0, 0, 0, alignParent, alignRelative, 79 | anchorRelative); 80 | } 81 | 82 | public static RelativeLayout.LayoutParams createRelative(int width, int height) { 83 | return createRelative(width, height, 0, 0, 0, 0, -1, -1, -1); 84 | } 85 | 86 | public static RelativeLayout.LayoutParams createRelative(int width, int height, 87 | int alignParent) { 88 | return createRelative(width, height, 0, 0, 0, 0, alignParent, -1, -1); 89 | } 90 | 91 | public static RelativeLayout.LayoutParams createRelative(int width, int height, 92 | int alignRelative, int anchorRelative) { 93 | return createRelative(width, height, 0, 0, 0, 0, -1, alignRelative, anchorRelative); 94 | } 95 | 96 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight, 97 | int gravity, int leftMargin, int topMargin, int rightMargin, int bottomMargin) { 98 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), 99 | getSize(height), weight); 100 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), 101 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin)); 102 | layoutParams.gravity = gravity; 103 | return layoutParams; 104 | } 105 | 106 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight, 107 | int leftMargin, int topMargin, int rightMargin, int bottomMargin) { 108 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), 109 | getSize(height), weight); 110 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), 111 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin)); 112 | return layoutParams; 113 | } 114 | 115 | public static LinearLayout.LayoutParams createLinear(int width, int height, int gravity, 116 | int leftMargin, int topMargin, int rightMargin, int bottomMargin) { 117 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), 118 | getSize(height)); 119 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), 120 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin)); 121 | layoutParams.gravity = gravity; 122 | return layoutParams; 123 | } 124 | 125 | public static LinearLayout.LayoutParams createLinear(int width, int height, float leftMargin, 126 | float topMargin, float rightMargin, float bottomMargin) { 127 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), 128 | getSize(height)); 129 | layoutParams.setMargins(AndroidUtilities.dp(leftMargin), AndroidUtilities.dp(topMargin), 130 | AndroidUtilities.dp(rightMargin), AndroidUtilities.dp(bottomMargin)); 131 | return layoutParams; 132 | } 133 | 134 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight, 135 | int gravity) { 136 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), 137 | getSize(height), weight); 138 | layoutParams.gravity = gravity; 139 | return layoutParams; 140 | } 141 | 142 | public static LinearLayout.LayoutParams createLinear(int width, int height, int gravity) { 143 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(getSize(width), 144 | getSize(height)); 145 | layoutParams.gravity = gravity; 146 | return layoutParams; 147 | } 148 | 149 | public static LinearLayout.LayoutParams createLinear(int width, int height, float weight) { 150 | return new LinearLayout.LayoutParams(getSize(width), getSize(height), weight); 151 | } 152 | 153 | public static LinearLayout.LayoutParams createLinear(int width, int height) { 154 | return new LinearLayout.LayoutParams(getSize(width), getSize(height)); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/components/ClippingImageView.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.components; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapShader; 6 | import android.graphics.Canvas; 7 | import android.graphics.Matrix; 8 | import android.graphics.Paint; 9 | import android.graphics.RectF; 10 | import android.graphics.Shader; 11 | import android.view.View; 12 | 13 | public class ClippingImageView extends View { 14 | 15 | private int clipBottom; 16 | private int clipLeft; 17 | private int clipRight; 18 | private int clipTop; 19 | private int orientation; 20 | private RectF drawRect; 21 | private Paint paint; 22 | private Bitmap bmp; 23 | private Matrix matrix; 24 | 25 | private boolean needRadius; 26 | private int radius; 27 | private BitmapShader bitmapShader; 28 | private Paint roundPaint; 29 | private RectF roundRect; 30 | private RectF bitmapRect; 31 | private Matrix shaderMatrix; 32 | 33 | private float animationProgress; 34 | private float animationValues[][]; 35 | 36 | public ClippingImageView(Context context) { 37 | super(context); 38 | paint = new Paint(); 39 | paint.setFilterBitmap(true); 40 | matrix = new Matrix(); 41 | drawRect = new RectF(); 42 | bitmapRect = new RectF(); 43 | roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 44 | roundRect = new RectF(); 45 | shaderMatrix = new Matrix(); 46 | } 47 | 48 | public void setAnimationValues(float[][] values) { 49 | animationValues = values; 50 | } 51 | 52 | public float getAnimationProgress() { 53 | return animationProgress; 54 | } 55 | 56 | public void setAnimationProgress(float progress) { 57 | animationProgress = progress; 58 | 59 | setScaleX(animationValues[0][0] + (animationValues[1][0] - animationValues[0][0]) * animationProgress); 60 | setScaleY(animationValues[0][1] + (animationValues[1][1] - animationValues[0][1]) * animationProgress); 61 | setTranslationX(animationValues[0][2] + (animationValues[1][2] - animationValues[0][2]) * animationProgress); 62 | setTranslationY(animationValues[0][3] + (animationValues[1][3] - animationValues[0][3]) * animationProgress); 63 | setClipHorizontal((int) (animationValues[0][4] + (animationValues[1][4] - animationValues[0][4]) * animationProgress)); 64 | setClipTop((int) (animationValues[0][5] + (animationValues[1][5] - animationValues[0][5]) * animationProgress)); 65 | setClipBottom((int) (animationValues[0][6] + (animationValues[1][6] - animationValues[0][6]) * animationProgress)); 66 | setRadius((int) (animationValues[0][7] + (animationValues[1][7] - animationValues[0][7]) * animationProgress)); 67 | 68 | invalidate(); 69 | } 70 | 71 | public int getClipBottom() { 72 | return clipBottom; 73 | } 74 | 75 | public int getClipHorizontal() { 76 | return clipRight; 77 | } 78 | 79 | public int getClipLeft() { 80 | return clipLeft; 81 | } 82 | 83 | public int getClipRight() { 84 | return clipRight; 85 | } 86 | 87 | public int getClipTop() { 88 | return clipTop; 89 | } 90 | 91 | public int getRadius() { 92 | return radius; 93 | } 94 | 95 | public void onDraw(Canvas canvas) { 96 | if (getVisibility() != VISIBLE) { 97 | return; 98 | } 99 | if (bmp != null) { 100 | float scaleY = getScaleY(); 101 | canvas.save(); 102 | 103 | if (needRadius) { 104 | shaderMatrix.reset(); 105 | roundRect.set(0, 0, getWidth(), getHeight()); 106 | 107 | int bitmapW; 108 | int bitmapH; 109 | if (orientation % 360 == 90 || orientation % 360 == 270) { 110 | bitmapW = bmp.getHeight(); 111 | bitmapH = bmp.getWidth(); 112 | } else { 113 | bitmapW = bmp.getWidth(); 114 | bitmapH = bmp.getHeight(); 115 | } 116 | float scaleW = getWidth() != 0 ? bitmapW / getWidth() : 1.0f; 117 | float scaleH = getHeight() != 0 ? bitmapH / getHeight() : 1.0f; 118 | float scale = Math.min(scaleW, scaleH); 119 | if (Math.abs(scaleW - scaleH) > 0.00001f) { 120 | int w = (int) Math.floor(getWidth() * scale); 121 | int h = (int) Math.floor(getHeight() * scale); 122 | bitmapRect.set((bitmapW - w) / 2, (bitmapH - h) / 2, w, h); 123 | shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.START); 124 | } else { 125 | bitmapRect.set(0, 0, bmp.getWidth(), bmp.getHeight()); 126 | shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL); 127 | } 128 | bitmapShader.setLocalMatrix(shaderMatrix); 129 | canvas.clipRect(clipLeft / scaleY, clipTop / scaleY, getWidth() - clipRight / scaleY, getHeight() - clipBottom / scaleY); 130 | canvas.drawRoundRect(roundRect, radius, radius, roundPaint); 131 | } else { 132 | if (orientation == 90 || orientation == 270) { 133 | drawRect.set(-getHeight() / 2, -getWidth() / 2, getHeight() / 2, getWidth() / 2); 134 | matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL); 135 | matrix.postRotate(orientation, 0, 0); 136 | matrix.postTranslate(getWidth() / 2, getHeight() / 2); 137 | } else if (orientation == 180) { 138 | drawRect.set(-getWidth() / 2, -getHeight() / 2, getWidth() / 2, getHeight() / 2); 139 | matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL); 140 | matrix.postRotate(orientation, 0, 0); 141 | matrix.postTranslate(getWidth() / 2, getHeight() / 2); 142 | } else { 143 | drawRect.set(0, 0, getWidth(), getHeight()); 144 | matrix.setRectToRect(bitmapRect, drawRect, Matrix.ScaleToFit.FILL); 145 | } 146 | 147 | canvas.clipRect(clipLeft / scaleY, clipTop / scaleY, getWidth() - clipRight / scaleY, getHeight() - clipBottom / scaleY); 148 | try { 149 | canvas.drawBitmap(bmp, matrix, paint); 150 | } catch (Exception e) { 151 | e.printStackTrace(); 152 | } 153 | } 154 | canvas.restore(); 155 | } 156 | } 157 | 158 | public void setClipBottom(int value) { 159 | clipBottom = value; 160 | invalidate(); 161 | } 162 | 163 | public void setClipHorizontal(int value) { 164 | clipRight = value; 165 | clipLeft = value; 166 | invalidate(); 167 | } 168 | 169 | public void setClipLeft(int value) { 170 | clipLeft = value; 171 | invalidate(); 172 | } 173 | 174 | public void setClipRight(int value) { 175 | clipRight = value; 176 | invalidate(); 177 | } 178 | 179 | public void setClipTop(int value) { 180 | clipTop = value; 181 | invalidate(); 182 | } 183 | 184 | public void setClipVertical(int value) { 185 | clipBottom = value; 186 | clipTop = value; 187 | invalidate(); 188 | } 189 | 190 | public void setOrientation(int angle) { 191 | orientation = angle; 192 | } 193 | 194 | public void setImageBitmap(Bitmap bitmap) { 195 | bmp = bitmap; 196 | if (bitmap != null) { 197 | bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); 198 | if (needRadius) { 199 | bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 200 | roundPaint.setShader(bitmapShader); 201 | } 202 | } 203 | invalidate(); 204 | } 205 | 206 | public void setNeedRadius(boolean value) { 207 | needRadius = value; 208 | } 209 | 210 | public void setRadius(int value) { 211 | radius = value; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /gallery/src/main/java/com/dhc/gallery/utils/NotificationCenter.java: -------------------------------------------------------------------------------- 1 | package com.dhc.gallery.utils; 2 | 3 | import android.os.Looper; 4 | import android.util.SparseArray; 5 | 6 | import java.util.ArrayList; 7 | 8 | public class NotificationCenter { 9 | 10 | private static int totalEvents = 1; 11 | 12 | public static final int didReceivedNewMessages = totalEvents++; 13 | public static final int dialogsNeedReload = totalEvents++; 14 | public static final int closeChats = totalEvents++; 15 | public static final int messagesDeleted = totalEvents++; 16 | public static final int mediaDidLoaded = totalEvents++; 17 | public static final int mediaCountDidLoaded = totalEvents++; 18 | public static final int dialogPhotosLoaded = totalEvents++; 19 | public static final int removeAllMessagesFromDialog = totalEvents++; 20 | public static final int recentImagesDidLoaded = totalEvents++; 21 | public static final int didReplacedPhotoInMemCache = totalEvents++; 22 | public static final int musicDidLoaded = totalEvents++; 23 | 24 | public static final int recordProgressChanged = totalEvents++; 25 | public static final int httpFileDidLoaded = totalEvents++; 26 | public static final int httpFileDidFailedLoad = totalEvents++; 27 | public static final int cameraInitied = totalEvents++; 28 | public static final int messageThumbGenerated = totalEvents++; 29 | 30 | public static final int emojiDidLoaded = totalEvents++; 31 | public static final int recordStopped = totalEvents++; 32 | public static final int FileDidUpload = totalEvents++; 33 | public static final int FileDidFailUpload = totalEvents++; 34 | public static final int FileUploadProgressChanged = totalEvents++; 35 | public static final int FileLoadProgressChanged = totalEvents++; 36 | public static final int FileDidLoaded = totalEvents++; 37 | public static final int FileDidFailedLoad = totalEvents++; 38 | public static final int recordStarted = totalEvents++; 39 | 40 | public static final int screenshotTook = totalEvents++; 41 | public static final int albumsDidLoaded = totalEvents++; 42 | 43 | private SparseArray> observers = new SparseArray<>(); 44 | private SparseArray> removeAfterBroadcast = new SparseArray<>(); 45 | private SparseArray> addAfterBroadcast = new SparseArray<>(); 46 | private ArrayList delayedPosts = new ArrayList<>(10); 47 | 48 | private int broadcasting = 0; 49 | private int[] allowedNotifications; 50 | private boolean animationInProgress; 51 | 52 | public interface NotificationCenterDelegate { 53 | void didReceivedNotification(int id, Object... args); 54 | } 55 | 56 | private class DelayedPost { 57 | 58 | private DelayedPost(int id, Object[] args) { 59 | this.id = id; 60 | this.args = args; 61 | } 62 | 63 | private int id; 64 | private Object[] args; 65 | } 66 | 67 | private static volatile NotificationCenter Instance = null; 68 | 69 | public static NotificationCenter getInstance() { 70 | NotificationCenter localInstance = Instance; 71 | if (localInstance == null) { 72 | synchronized (NotificationCenter.class) { 73 | localInstance = Instance; 74 | if (localInstance == null) { 75 | Instance = localInstance = new NotificationCenter(); 76 | } 77 | } 78 | } 79 | return localInstance; 80 | } 81 | 82 | public void setAllowedNotificationsDutingAnimation(int notifications[]) { 83 | allowedNotifications = notifications; 84 | } 85 | 86 | public void setAnimationInProgress(boolean value) { 87 | animationInProgress = value; 88 | if (!animationInProgress && !delayedPosts.isEmpty()) { 89 | for (DelayedPost delayedPost : delayedPosts) { 90 | postNotificationNameInternal(delayedPost.id, true, delayedPost.args); 91 | } 92 | delayedPosts.clear(); 93 | } 94 | } 95 | 96 | public boolean isAnimationInProgress() { 97 | return animationInProgress; 98 | } 99 | 100 | public void postNotificationName(int id, Object... args) { 101 | boolean allowDuringAnimation = false; 102 | if (allowedNotifications != null) { 103 | for (int a = 0; a < allowedNotifications.length; a++) { 104 | if (allowedNotifications[a] == id) { 105 | allowDuringAnimation = true; 106 | break; 107 | } 108 | } 109 | } 110 | postNotificationNameInternal(id, allowDuringAnimation, args); 111 | } 112 | 113 | public void postNotificationNameInternal(int id, boolean allowDuringAnimation, Object... args) { 114 | if (Looper.getMainLooper() != Looper.myLooper()){ 115 | throw new RuntimeException("addObserver allowed only from MAIN thread"); 116 | } 117 | 118 | if (!allowDuringAnimation && animationInProgress) { 119 | DelayedPost delayedPost = new DelayedPost(id, args); 120 | delayedPosts.add(delayedPost); 121 | return; 122 | } 123 | broadcasting++; 124 | ArrayList objects = observers.get(id); 125 | if (objects != null && !objects.isEmpty()) { 126 | for (int a = 0; a < objects.size(); a++) { 127 | Object obj = objects.get(a); 128 | ((NotificationCenterDelegate) obj).didReceivedNotification(id, args); 129 | } 130 | } 131 | broadcasting--; 132 | if (broadcasting == 0) { 133 | if (removeAfterBroadcast.size() != 0) { 134 | for (int a = 0; a < removeAfterBroadcast.size(); a++) { 135 | int key = removeAfterBroadcast.keyAt(a); 136 | ArrayList arrayList = removeAfterBroadcast.get(key); 137 | for (int b = 0; b < arrayList.size(); b++) { 138 | removeObserver(arrayList.get(b), key); 139 | } 140 | } 141 | removeAfterBroadcast.clear(); 142 | } 143 | if (addAfterBroadcast.size() != 0) { 144 | for (int a = 0; a < addAfterBroadcast.size(); a++) { 145 | int key = addAfterBroadcast.keyAt(a); 146 | ArrayList arrayList = addAfterBroadcast.get(key); 147 | for (int b = 0; b < arrayList.size(); b++) { 148 | addObserver(arrayList.get(b), key); 149 | } 150 | } 151 | addAfterBroadcast.clear(); 152 | } 153 | } 154 | } 155 | 156 | public void addObserver(Object observer, int id) { 157 | if (Looper.getMainLooper() != Looper.myLooper()){ 158 | throw new RuntimeException("addObserver allowed only from MAIN thread"); 159 | } 160 | 161 | if (broadcasting != 0) { 162 | ArrayList arrayList = addAfterBroadcast.get(id); 163 | if (arrayList == null) { 164 | arrayList = new ArrayList<>(); 165 | addAfterBroadcast.put(id, arrayList); 166 | } 167 | arrayList.add(observer); 168 | return; 169 | } 170 | ArrayList objects = observers.get(id); 171 | if (objects == null) { 172 | observers.put(id, (objects = new ArrayList<>())); 173 | } 174 | if (objects.contains(observer)) { 175 | return; 176 | } 177 | objects.add(observer); 178 | } 179 | 180 | public void removeObserver(Object observer, int id) { 181 | if (Looper.getMainLooper() != Looper.myLooper()){ 182 | throw new RuntimeException("addObserver allowed only from MAIN thread"); 183 | } 184 | 185 | if (broadcasting != 0) { 186 | ArrayList arrayList = removeAfterBroadcast.get(id); 187 | if (arrayList == null) { 188 | arrayList = new ArrayList<>(); 189 | removeAfterBroadcast.put(id, arrayList); 190 | } 191 | arrayList.add(observer); 192 | return; 193 | } 194 | ArrayList objects = observers.get(id); 195 | if (objects != null) { 196 | objects.remove(observer); 197 | } 198 | } 199 | } 200 | --------------------------------------------------------------------------------