Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

+ [android] support new feature image component can save to Photo Album #547

Merged
merged 2 commits into from
Aug 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class IndexActivity extends AbstractWeexActivity {

private static final String TAG = "IndexActivity";
private static final int CAMERA_PERMISSION_REQUEST_CODE = 0x1;
private static final int WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 0x2;
private static final String DEFAULT_IP = "your_current_IP";
private static String sCurrentIp = DEFAULT_IP; // your_current_IP

Expand Down Expand Up @@ -102,6 +103,18 @@ public void onReceive(Context context, Intent intent) {
};

LocalBroadcastManager.getInstance(this).registerReceiver(mReloadReceiver, new IntentFilter(WXSDKEngine.JS_FRAMEWORK_RELOAD));

requestWeexPermission();
}

private void requestWeexPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "please give me the permission", Toast.LENGTH_SHORT).show();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
}
}
}

@Override
Expand Down Expand Up @@ -147,6 +160,7 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_PERMISSION_REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startActivity(new Intent(this, CaptureActivity.class));
} else if (requestCode == WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "request camara permission fail!", Toast.LENGTH_SHORT).show();
}
Expand Down
10 changes: 10 additions & 0 deletions android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.taobao.weex.common.WXRefreshData;
import com.taobao.weex.common.WXRuntimeException;
import com.taobao.weex.common.WXThread;
import com.taobao.weex.common.WXWorkThreadManager;
import com.taobao.weex.dom.WXDomManager;
import com.taobao.weex.ui.WXRenderManager;
import com.taobao.weex.utils.WXLogUtils;
Expand All @@ -64,6 +65,7 @@ public class WXSDKManager {
private static volatile WXSDKManager sManager;
private static AtomicInteger sInstanceId = new AtomicInteger(0);
private final WXDomManager mWXDomManager;
private final WXWorkThreadManager mWXWorkThreadManager;
private WXBridgeManager mBridgeManager;
/** package **/ WXRenderManager mWXRenderManager;

Expand Down Expand Up @@ -97,6 +99,7 @@ private WXSDKManager(WXRenderManager renderManager) {
mWXRenderManager = renderManager;
mWXDomManager = new WXDomManager(mWXRenderManager);
mBridgeManager = WXBridgeManager.getInstance();
mWXWorkThreadManager = new WXWorkThreadManager();
}

/**
Expand Down Expand Up @@ -195,6 +198,10 @@ public WXRenderManager getWXRenderManager() {
return mWXRenderManager;
}

public WXWorkThreadManager getWXWorkThreadManager() {
return mWXWorkThreadManager;
}

public @Nullable WXSDKInstance getSDKInstance(String instanceId) {
return instanceId == null? null : mWXRenderManager.getWXSDKInstance(instanceId);
}
Expand All @@ -207,6 +214,9 @@ public void destroy() {
if (mWXDomManager != null) {
mWXDomManager.destroy();
}
if (mWXWorkThreadManager != null) {
mWXWorkThreadManager.destroy();
}
}

@Deprecated
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.taobao.weex.common;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Class for managing work thread
*/
public final class WXWorkThreadManager {

private ExecutorService singleThreadExecutor;

public WXWorkThreadManager() {
singleThreadExecutor = Executors.newSingleThreadExecutor();
}

public void post(Runnable task) {
if (singleThreadExecutor != null)
singleThreadExecutor.execute(task);
}

/**
* Destroy current instance
*/
public void destroy() {
if (singleThreadExecutor != null)
singleThreadExecutor.shutdown();
singleThreadExecutor = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
*/
package com.taobao.weex.ui.component;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
Expand All @@ -34,6 +37,8 @@
import com.taobao.weex.adapter.IWXImgLoaderAdapter;
import com.taobao.weex.adapter.URIAdapter;
import com.taobao.weex.annotation.Component;
import com.taobao.weex.annotation.JSMethod;
import com.taobao.weex.bridge.JSCallback;
import com.taobao.weex.common.Constants;
import com.taobao.weex.common.WXImageSharpen;
import com.taobao.weex.common.WXImageStrategy;
Expand All @@ -46,6 +51,7 @@
import com.taobao.weex.utils.ImageDrawable;
import com.taobao.weex.utils.ImgURIUtil;
import com.taobao.weex.utils.SingleFunctionParser;
import com.taobao.weex.utils.WXViewToImageUtil;
import com.taobao.weex.utils.WXDomUtils;
import com.taobao.weex.utils.WXLogUtils;
import com.taobao.weex.utils.WXUtils;
Expand All @@ -62,6 +68,10 @@
*/
@Component(lazyload = false)
public class WXImage extends WXComponent<ImageView> {

public static final String SUCCEED = "success";
public static final String ERRORDESC = "errorDesc";

private String mSrc;
private int mBlurRadius;

Expand Down Expand Up @@ -332,6 +342,64 @@ public void updateProperties(Map<String, Object> props) {
}
}

/**
* Need permission {android.permission.WRITE_EXTERNAL_STORAGE}
*/
@JSMethod(uiThread = false)
public void save(final JSCallback saveStatuCallback) {

if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (saveStatuCallback != null) {
Map<String, Object> result = new HashMap<>();
result.put(SUCCEED, false);
result.put(ERRORDESC,"Permission denied: android.permission.WRITE_EXTERNAL_STORAGE");
saveStatuCallback.invoke(result);
}
return;
}

if (mHost == null) {
if (saveStatuCallback != null) {
Map<String, Object> result = new HashMap<>();
result.put(SUCCEED, false);
result.put(ERRORDESC,"Image component not initialized");
saveStatuCallback.invoke(result);
}
return;
}

if (mSrc == null || mSrc.equals("")) {
if (saveStatuCallback != null) {
Map<String, Object> result = new HashMap<>();
result.put(SUCCEED, false);
result.put(ERRORDESC,"Image does not have the correct src");
saveStatuCallback.invoke(result);
}
return;
}

WXViewToImageUtil.generateImage(mHost, 0, 0xfff8f8f8, new WXViewToImageUtil.OnImageSavedCallback() {
@Override
public void onSaveSucceed(String path) {
if (saveStatuCallback != null) {
Map<String, Object> result = new HashMap<>();
result.put(SUCCEED, true);
saveStatuCallback.invoke(result);
}
}

@Override
public void onSaveFailed(String errorDesc) {
if (saveStatuCallback != null) {
Map<String, Object> result = new HashMap<>();
result.put(SUCCEED, false);
result.put(ERRORDESC,errorDesc);
saveStatuCallback.invoke(result);
}
}
});
}

public interface Measurable {
int getNaturalWidth();
int getNaturalHeight();
Expand Down
151 changes: 151 additions & 0 deletions android/sdk/src/main/java/com/taobao/weex/utils/WXViewToImageUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.taobao.weex.utils;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
import android.support.annotation.ColorInt;
import android.view.View;

import com.taobao.weex.WXSDKManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* Created by miomin on 7/25/17.
*/
public class WXViewToImageUtil {

public static int mBackgroundColor = Color.TRANSPARENT;

/**
* Generate image and return path via callback
*/
public static void generateImage(final View imageView, final int width,
@ColorInt final int backgroundColor, final OnImageSavedCallback mOnImageSavedCallback) {

mBackgroundColor = backgroundColor;

// Only one save image task occurs at the same time
WXSDKManager.getInstance().getWXWorkThreadManager().post(new Thread(new Runnable() {
@Override
public void run() {
// Generate bitmap from ImageView
Bitmap bitmap = getBitmapFromImageView(imageView, width);

if (bitmap == null) {
if (mOnImageSavedCallback != null) {
mOnImageSavedCallback.onSaveFailed("Image is empty");
}
return;
}

// Sava bitmap to gallery
final String destPath = saveBitmapToGallery(imageView.getContext(), bitmap, mOnImageSavedCallback);

new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
if (mOnImageSavedCallback != null) {
mOnImageSavedCallback.onSaveSucceed(destPath);
imageView.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(destPath)));
}
}
});
}
}));
}

/**
* Save bitmap to gallery
* @return image save path
*/
public static String saveBitmapToGallery(Context context, Bitmap bitmap, final OnImageSavedCallback mOnImageSavedCallback) {

// Save image
File appDir = new File(Environment.getExternalStorageDirectory(), "Weex");
if (!appDir.exists()) {
appDir.mkdir();
}

String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);

try {
FileOutputStream fos = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
if (mOnImageSavedCallback != null)
mOnImageSavedCallback.onSaveFailed("Image creation failed due to system reason");
e.printStackTrace();
} catch (IOException e) {
if (mOnImageSavedCallback != null)
mOnImageSavedCallback.onSaveFailed("Android IOException");
e.printStackTrace();
}

// Insert the image file into the system gallery
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

// Notify the system gallery update
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + appDir.getAbsolutePath() + "/" + fileName)));

return file.getAbsolutePath();
}

/**
* Save state callback
*/
public interface OnImageSavedCallback {
void onSaveSucceed(String path);
void onSaveFailed(String errorDesc);
}

/**
* Get bitmap from imageview
*/
public static Bitmap getBitmapFromImageView(final View view, int width) {
if (view.getWidth() <= 0 || view.getHeight() <= 0) {
view.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
}

view.setDrawingCacheEnabled(true);
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}
}