/*
HostCanvasProfile.java
Copyright (c) 2015 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.host.profile;
import android.app.ActivityManager;
import android.app.Service;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.deviceconnect.android.deviceplugin.host.activity.CanvasProfileActivity;
import org.deviceconnect.android.deviceplugin.host.canvas.CanvasDrawImageObject;
import org.deviceconnect.android.message.MessageUtils;
import org.deviceconnect.android.profile.CanvasProfile;
import org.deviceconnect.android.profile.api.DConnectApi;
import org.deviceconnect.android.profile.api.DeleteApi;
import org.deviceconnect.android.profile.api.PostApi;
import org.deviceconnect.message.DConnectMessage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Canvas Profile.
*
* @author NTT DOCOMO, INC.
*/
public class HostCanvasProfile extends CanvasProfile {
/** ファイルが生存できる有効時間を定義する. */
private static final long DEFAULT_EXPIRE = 1000 * 60 * 5;
/** Canvasプロファイルのファイル名プレフィックス。 */
private static final String CANVAS_PREFIX = "host_canvas";
/** ファイルが生存できる有効時間. */
private long mExpire = DEFAULT_EXPIRE;
/** Edit Image Thread. */
private ExecutorService mImageService = Executors.newSingleThreadExecutor();
private final DConnectApi mDrawImageApi = new PostApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_DRAW_IMAGE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
String mode = getMode(request);
String mimeType = getMIMEType(request);
final CanvasDrawImageObject.Mode enumMode = CanvasDrawImageObject.convertMode(mode);
if (enumMode == null) {
MessageUtils.setInvalidRequestParameterError(response);
return true;
}
if (mimeType != null && !mimeType.contains("image")) {
MessageUtils.setInvalidRequestParameterError(response,
"Unsupported mimeType: " + mimeType);
return true;
}
final byte[] data = getData(request);
final String uri = getURI(request);
final double x = getX(request);
final double y = getY(request);
if (data == null) {
if (uri != null) {
if (uri.startsWith("http")) {
drawImage(response, uri, enumMode, x, y);
} else {
MessageUtils.setInvalidRequestParameterError(response, "Invalid uri.");
}
} else {
MessageUtils.setInvalidRequestParameterError(response, "Uri and data is null.");
}
return true;
} else {
mImageService.execute(new Runnable() {
@Override
public void run() {
sendImage(data, response, enumMode, x, y);
}
});
return false;
}
}
};
private final DConnectApi mDeleteImageApi = new DeleteApi() {
@Override
public String getAttribute() {
return ATTRIBUTE_DRAW_IMAGE;
}
@Override
public boolean onRequest(final Intent request, final Intent response) {
String className = getClassnameOfTopActivity();
if (CanvasProfileActivity.class.getName().equals(className)) {
Intent intent = new Intent(CanvasDrawImageObject.ACTION_DELETE_CANVAS);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
setResult(response, DConnectMessage.RESULT_OK);
} else {
MessageUtils.setIllegalDeviceStateError(response, "canvas not display");
}
return true;
}
};
/**
* コンストラクタ.
*/
public HostCanvasProfile() {
addApi(mDrawImageApi);
addApi(mDeleteImageApi);
}
/**
* Send Image.
* @param data binary
* @param response response message
* @param enumMode image mode
* @param x position
* @param y position
*/
private void sendImage(byte[] data, Intent response, CanvasDrawImageObject.Mode enumMode, double x, double y) {
try {
drawImage(response, writeForImage(data), enumMode, x, y);
} catch (OutOfMemoryError e) {
MessageUtils.setIllegalDeviceStateError(response, e.getMessage());
} catch (IOException e) {
MessageUtils.setIllegalDeviceStateError(response, e.getMessage());
}
sendResponse(response);
}
/**
* Start Canvas Activity.
* @param response response message
* @param uri image url
* @param enumMode image mode
* @param x position
* @param y position
*/
private void drawImage(Intent response, String uri, CanvasDrawImageObject.Mode enumMode, double x, double y) {
CanvasDrawImageObject drawObj = new CanvasDrawImageObject(uri, enumMode, x, y);
String className = getClassnameOfTopActivity();
if (CanvasProfileActivity.class.getName().equals(className)) {
Intent intent = new Intent(CanvasDrawImageObject.ACTION_DRAW_CANVAS);
drawObj.setValueToIntent(intent);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
} else {
Intent intent = new Intent();
intent.setClass(getContext(), CanvasProfileActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
drawObj.setValueToIntent(intent);
getContext().startActivity(intent);
}
setResult(response, DConnectMessage.RESULT_OK);
}
/**
* 画面の一番上にでているActivityのクラス名を取得.
*
* @return クラス名
*/
private String getClassnameOfTopActivity() {
ActivityManager activityMgr = (ActivityManager) getContext().getSystemService(Service.ACTIVITY_SERVICE);
return activityMgr.getRunningTasks(1).get(0).topActivity.getClassName();
}
/**
* 画像の保存
* @param data binary
* @return URI
* @throws IOException
* @throws OutOfMemoryError
*/
private String writeForImage(final byte[] data) throws IOException, OutOfMemoryError {
File file = getContext().getCacheDir();
FileOutputStream out = null;
checkAndRemove(file);
File dstFile = File.createTempFile(CANVAS_PREFIX, ".tmp", file);
try {
out = new FileOutputStream(dstFile);
out.write(data);
out.close();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return dstFile.getAbsolutePath();
}
/**
* ファイルをチェックして、中身を削除する.
*
* @param file 削除するファイル
*/
private void checkAndRemove(@NonNull final File file) {
if (file.isDirectory()) {
for (File childFile : file.listFiles()) {
checkAndRemove(childFile);
}
} else if (file.isFile() && file.getName().startsWith(CANVAS_PREFIX)) {
long modified = file.lastModified();
if (System.currentTimeMillis() - modified > mExpire) {
file.delete();
}
}
}
}