package com.wangdaye.mysplash.common.ui.activity; import android.app.WallpaperManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; import android.os.Bundle; import android.os.Message; import android.support.annotation.IntDef; import android.support.design.widget.CoordinatorLayout; import android.support.v4.content.ContextCompat; import android.view.View; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; import com.wangdaye.mysplash.R; import com.wangdaye.mysplash.common._basic.ReadWriteActivity; import com.wangdaye.mysplash.common.ui.dialog.WallpaperWhereDialog; import com.wangdaye.mysplash.common.ui.popup.WallpaperAlignPopupWindow; import com.wangdaye.mysplash.common.ui.popup.WallpaperClipPopupWindow; import com.wangdaye.mysplash.common.ui.widget.photoView.Info; import com.wangdaye.mysplash.common.ui.widget.photoView.PhotoView; import com.wangdaye.mysplash.common.utils.FileUtils; import com.wangdaye.mysplash.common.utils.helper.ImageHelper; import com.wangdaye.mysplash.common.utils.helper.IntentHelper; import com.wangdaye.mysplash.common.utils.manager.ThreadManager; import com.wangdaye.mysplash.common.utils.widget.SafeHandler; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; /** * Set wallpaper activity. * * This activity is used to set a photo as a wallpaper. * * */ public class SetWallpaperActivity extends ReadWriteActivity implements WallpaperClipPopupWindow.OnClipTypeChangedListener, WallpaperAlignPopupWindow.OnAlignTypeChangedListener, WallpaperWhereDialog.OnWhereSelectedListener, SafeHandler.HandlerContainer { @BindView(R.id.activity_set_wallpaper_container) CoordinatorLayout container; @BindView(R.id.activity_set_wallpaper_closeBtn) ImageButton closeBtn; @BindView(R.id.activity_set_wallpaper_typeBtn) ImageView typeBtn; @BindView(R.id.activity_set_wallpaper_alignBtn) ImageView alignBtn; @BindView(R.id.activity_set_wallpaper_setBtn) Button setBtn; @BindView(R.id.activity_set_wallpaper_photoView) PhotoView photoView; private SafeHandler<SetWallpaperActivity> handler; private File photoFile; private boolean light; @ClipRule private int clipType = CLIP_TYPE_SQUARE; @AlignRule private int alignType = ALIGN_TYPE_CENTER; public static final int CLIP_TYPE_SQUARE = 1; public static final int CLIP_TYPE_RECT = 2; @IntDef({CLIP_TYPE_SQUARE, CLIP_TYPE_RECT}) private @interface ClipRule {} public static final int ALIGN_TYPE_LEFT = 1; public static final int ALIGN_TYPE_CENTER = 2; public static final int ALIGN_TYPE_RIGHT = 3; @IntDef({ALIGN_TYPE_LEFT, ALIGN_TYPE_CENTER, ALIGN_TYPE_RIGHT}) private @interface AlignRule {} public static final int WHERE_WALLPAPER = 1; public static final int WHERE_LOCKSCREEN = 2; public static final int WHERE_WALL_LOCK = 3; @IntDef({WHERE_WALLPAPER, WHERE_LOCKSCREEN, WHERE_WALL_LOCK}) public @interface WallpaperWhereRule {} /** * A Runnable class to set picture as wallpaper. * */ public Runnable setWallpaper = new Runnable() { @Override public void run() { setWallpaper(true); handler.obtainMessage(WHERE_WALLPAPER).sendToTarget(); } }; /** * A Runnable class to set picture as background in lock screen. * */ public Runnable setLockScreen = new Runnable() { @Override public void run() { setWallpaper(false); handler.obtainMessage(WHERE_LOCKSCREEN).sendToTarget(); } }; /** * A Runnable class to set picture as wallpaper and background in lock screen. * */ public Runnable setWallAndLock = new Runnable() { @Override public void run() { setWallpaper(true); setWallpaper(false); handler.obtainMessage(WHERE_WALL_LOCK).sendToTarget(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_set_wallpaper); } @Override protected void onStart() { super.onStart(); if (!isStarted()) { setStarted(); ButterKnife.bind(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestReadWritePermission(); } else { initData(); initWidget(); } } } @Override protected void onSaveInstanceState(Bundle outState) { // do nothing. } @Override protected void setTheme() { setTheme(R.style.MysplashTheme_dark_SetWallpaper); getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getWindow().addFlags(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); } } @Override protected boolean operateStatusBarBySelf() { return true; } @Override public void handleBackPressed() { finishActivity(0); } @Override protected void backToTop() { // do nothing. } @Override public void finishActivity(int dir) { finish(); } @Override public CoordinatorLayout getSnackbarContainer() { return container; } // init. private void initData() { this.photoFile = new File(getIntent().getData().getSchemeSpecificPart()); if (!photoFile.exists()) { photoFile = new File(FileUtils.uriToFilePath(this, getIntent().getData())); } light = false; } private void initWidget() { this.handler = new SafeHandler<>(this); setTypeIcon(clipType); setAlignIcon(alignType); photoView.enable(); photoView.setMaxScale(2.5f); photoView.setScaleType(ImageView.ScaleType.CENTER_CROP); ImageHelper.loadImage(this, photoView, photoFile); ImageHelper.loadBitmap( this, new SimpleTarget<Bitmap>(100, 100) { @Override public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { int color = computeBackgroundColor(resource); container.setBackgroundColor(color); light = isLightColor(color); setStyle(); } }, photoFile); } // control. /** * Change text and icon color when loading picture. * */ private void setStyle() { if (light) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } else { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } closeBtn.setImageResource(R.drawable.ic_toolbar_close_light); setBtn.setTextColor(ContextCompat.getColor(this, R.color.colorTextContent_light)); } else { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); closeBtn.setImageResource(R.drawable.ic_toolbar_close_dark); setBtn.setTextColor(ContextCompat.getColor(this, R.color.colorTextContent_dark)); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getWindow().addFlags(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); } setTypeIcon(clipType); setAlignIcon(alignType); } private void setTypeIcon(int type) { switch (type) { case CLIP_TYPE_SQUARE: if (light) { typeBtn.setImageResource(R.drawable.ic_orientation_squarish_light); } else { typeBtn.setImageResource(R.drawable.ic_orientation_squarish_dark); } break; case CLIP_TYPE_RECT: if (light) { typeBtn.setImageResource(R.drawable.ic_orientation_portrait_light); } else { typeBtn.setImageResource(R.drawable.ic_orientation_portrait_dark); } break; } } private void setAlignIcon(int align) { switch (align) { case ALIGN_TYPE_LEFT: if (light) { alignBtn.setImageResource(R.drawable.ic_align_left_light); } else { alignBtn.setImageResource(R.drawable.ic_align_left_dark); } break; case ALIGN_TYPE_CENTER: if (light) { alignBtn.setImageResource(R.drawable.ic_align_center_light); } else { alignBtn.setImageResource(R.drawable.ic_align_center_dark); } break; case ALIGN_TYPE_RIGHT: if (light) { alignBtn.setImageResource(R.drawable.ic_align_right_light); } else { alignBtn.setImageResource(R.drawable.ic_align_right_dark); } break; } } private int computeBackgroundColor(Bitmap bitmap) { Matrix matrix = new Matrix(); matrix.setScale((float) (1.0 / bitmap.getWidth()), (float) (1.0 / 2.0)); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), 2, matrix, false); return bitmap.getPixel(0, 0); } private boolean isLightColor(int color) { int alpha = 0xFF << 24; int grey = color; int red = ((grey & 0x00FF0000) >> 16); int green = ((grey & 0x0000FF00) >> 8); int blue = (grey & 0x000000FF); grey = (int) (red * 0.3 + green * 0.59 + blue * 0.11); grey = alpha | (grey << 16) | (grey << 8) | grey; return grey > ContextCompat.getColor(this, R.color.colorTextGrey); } /** * Set picture as a wallpaper. * * @param wallpaper if set true, it means this picture needs to be set as a wallpaper, * otherwise, this picture needs to be set as a background in lock screen. * */ private void setWallpaper(boolean wallpaper) { FileInputStream[] streams = new FileInputStream[2]; try { streams[0] = new FileInputStream(photoFile); streams[1] = new FileInputStream(photoFile); } catch (FileNotFoundException e) { e.printStackTrace(); } if (streams[0] == null || streams[1] == null) { return; } int screenWidth = getResources().getDisplayMetrics().widthPixels; int screenHeight = getResources().getDisplayMetrics().heightPixels; // eliminate the error from PhotoView's bound. Info info = photoView.getInfo(); RectF imageBound = info.getImageBound(); if (imageBound.left > 0) { float delta = -imageBound.left; imageBound.left += delta; imageBound.right += delta; } else if (imageBound.right < screenWidth) { float delta = screenWidth - imageBound.right; imageBound.left += delta; imageBound.right += delta; } if (imageBound.top > 0) { float delta = -imageBound.top; imageBound.top += delta; imageBound.bottom += delta; } else if (imageBound.bottom < screenHeight) { float delta = screenHeight - imageBound.bottom; imageBound.top += delta; imageBound.bottom += delta; } // screen width + delta width = wallpaper width. // for example, when the wallpaper is align left. ■□□ // the black part is screen area, we need ensure the delta area in other area. int leftDeltaWidth = 0; int rightDeltaWidth = 0; if (wallpaper) { if (clipType == CLIP_TYPE_SQUARE) { switch (alignType) { case ALIGN_TYPE_LEFT: { // ■□□ int deltaWidth = (int) Math.abs(imageBound.right - screenWidth); if (screenWidth + deltaWidth > screenHeight) { // wallpaper's width cannot > wallpaper's height. deltaWidth = screenHeight - screenWidth; } leftDeltaWidth = 0; rightDeltaWidth = deltaWidth; break; } case ALIGN_TYPE_CENTER: { // □■□ int deltaWidth = (int) Math.min( Math.abs(imageBound.left), Math.abs(imageBound.right - screenWidth)); if (screenWidth + 2 * deltaWidth > screenHeight) { // wallpaper's width cannot > wallpaper's height. deltaWidth = (int) ((screenHeight - screenWidth) / 2.0); } leftDeltaWidth = rightDeltaWidth = deltaWidth; break; } case ALIGN_TYPE_RIGHT: { // □□■ int deltaWidth = (int) Math.abs(imageBound.left); if (screenWidth + deltaWidth > screenHeight) { // wallpaper's width cannot > wallpaper's height. deltaWidth = screenHeight - screenWidth; } leftDeltaWidth = deltaWidth; rightDeltaWidth = 0; break; } } } } // compute the percentage of left, right, top, bottom coordinates. float leftPercent = (-leftDeltaWidth - imageBound.left) / imageBound.width(); float rightPercent = (screenWidth + rightDeltaWidth - imageBound.left) / imageBound.width(); float topPercent = (-imageBound.top) / imageBound.height(); float bottomPercent = (imageBound.bottom - imageBound.top) / imageBound.height(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(streams[0], new Rect(0, 0, 0, 0), options); Rect wallpaperCorp = new Rect( (int) (options.outWidth * leftPercent), (int) (options.outHeight * topPercent), (int) (options.outWidth * rightPercent), (int) (options.outHeight * bottomPercent)); WallpaperManager manager = WallpaperManager.getInstance(this); Rect outPadding = new Rect( Math.max(0, wallpaperCorp.left), Math.max(0, wallpaperCorp.top), Math.max(0, options.outWidth - wallpaperCorp.right), Math.max(0, options.outHeight - wallpaperCorp.bottom)); options.inJustDecodeBounds = false; options.inSampleSize = wallpaperCorp.width() / manager.getDesiredMinimumWidth(); Bitmap bitmap = BitmapFactory.decodeStream(streams[1], outPadding, options); try { streams[0].close(); streams[1].close(); if (wallpaper) { manager.setBitmap(bitmap); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { manager.setBitmap( bitmap, new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()), true, WallpaperManager.FLAG_LOCK); } } catch (IOException e) { e.printStackTrace(); } } // permission. @Override protected void requestReadWritePermissionSucceed(int requestCode) { initData(); initWidget(); } // interface. // on click listener. @OnClick(R.id.activity_set_wallpaper_closeBtn) void close() { finishActivity(0); } @OnClick(R.id.activity_set_wallpaper_typeBtn) void showTypePopup() { WallpaperClipPopupWindow popup = new WallpaperClipPopupWindow(this, typeBtn, clipType); popup.setOnClipTypeChangedListener(this); } @OnClick(R.id.activity_set_wallpaper_closeBtn) void showAlignPopup() { WallpaperAlignPopupWindow popup = new WallpaperAlignPopupWindow(this, alignBtn, alignType); popup.setAlignTypeChangedListener(this); } @OnClick(R.id.activity_set_wallpaper_closeBtn) void set() { WallpaperWhereDialog dialog = new WallpaperWhereDialog(); dialog.setOnWhereSelectedListener(this); dialog.show(getFragmentManager(), null); } // on clip type changed listener. @Override public void onClipTypeChanged(int type) { clipType = type; setTypeIcon(type); } // on align type changed listener. @Override public void onAlignTypeChanged(int type) { alignType = type; setAlignIcon(type); } // on where selected listener. @Override public void onWhereSelected(int where) { switch (where) { case WHERE_WALLPAPER: ThreadManager.getInstance().execute(setWallpaper); break; case WHERE_LOCKSCREEN: ThreadManager.getInstance().execute(setLockScreen); break; case WHERE_WALL_LOCK: ThreadManager.getInstance().execute(setWallAndLock); break; } } // handler container. @Override public void handleMessage(Message message) { switch (message.what) { case WHERE_WALLPAPER: case WHERE_LOCKSCREEN: case WHERE_WALL_LOCK: IntentHelper.backToHome(this); finishActivity(0); break; } } }