/*
*
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license.
*
* Project Oxford: http://ProjectOxford.ai
*
* Project Oxford Mimicker Alarm Github:
* https://github.com/Microsoft/ProjectOxford-Apps-MimickerAlarm
*
* Copyright (c) Microsoft Corporation
* All rights reserved.
*
* MIT License:
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.microsoft.mimickeralarm.ringing;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.microsoft.mimickeralarm.R;
import com.microsoft.mimickeralarm.utilities.Loggable;
import com.microsoft.mimickeralarm.utilities.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* This class handles the Sharing user experience once a user has successfully completed a Mimic
* game. The class utilizes the system sharing action to allow the user to share with the
* application of their choice.
*/
public class ShareFragment extends Fragment {
public static final String SHARE_FRAGMENT_TAG = "share_fragment";
public static final String SHAREABLE_URI = "shareable-uri";
private final static int SHARE_REQUEST_CODE = 2;
private final static String MIMICKER_FILE_PREFIX = "Mimicker_";
// The time to auto-dismiss share screen if there is no user interaction
private static final int SHARING_FRAGMENT_STAY_DURATION = 60 * 1000; // 1 minute
// The time to auto-dismiss share screen after pressing save button
private static final int SHARING_FRAGMENT_SAVE_STAY_DURATION = 60 * 1000; // 1 minute
// The time to auto-dismiss share screen after pressing share button
private static final int SHARING_FRAGMENT_SHARE_STAY_DURATION = 300 * 1000; // 5 minutes
// Delay to dismiss the toast message
private static final long TOAST_IN_FRAGMENT_DELAY = 1500; // 1.5 seconds
private ShareResultListener mCallback;
private String mShareableUri;
private ImageView mShareableImage;
private Handler mHandler;
private Runnable mSharingFragmentDismissTask;
private Runnable mToastAutoDismiss;
private int mSharingFragmentDismissTaskDelay = SHARING_FRAGMENT_STAY_DURATION;
public static ShareFragment newInstance(String shareableUri) {
ShareFragment fragment = new ShareFragment();
Bundle bundle = new Bundle(1);
bundle.putString(SHAREABLE_URI, shareableUri);
fragment.setArguments(bundle);
return fragment;
}
public static Uri saveShareableBitmap(Context context, Bitmap bitmap, String question) {
drawStamp(context, bitmap, question);
File tempFile;
try {
tempFile = File.createTempFile("mimicker", ".jpg", context.getCacheDir());
tempFile.setReadable(true, false);
tempFile.deleteOnExit();
} catch (IOException ex) {
Logger.trackException(ex);
return null;
}
if (tempFile.canWrite()) {
try {
FileOutputStream stream = new FileOutputStream(tempFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream);
stream.close();
} catch (IOException ex) {
Logger.trackException(ex);
return null;
}
}
return Uri.fromFile(tempFile);
}
private static void drawStamp(Context context, Bitmap bitmap, String question) {
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(bitmap, 0, 0, null);
float opacity = 0.7f;
int horizontalPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics());
int verticalPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, context.getResources().getDisplayMetrics());
int textSize = 16; // defined in SP
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, context.getResources().getDisplayMetrics());
LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setBackgroundResource(R.drawable.rounded_corners);
layout.getBackground().setAlpha((int) (opacity * 255));
layout.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
ImageView logo = new ImageView(context);
logo.setImageDrawable(ContextCompat.getDrawable(context, R.mipmap.ic_launcher_no_bg));
layout.addView(logo);
TextView textView = new TextView(context);
textView.setVisibility(View.VISIBLE);
if (question != null) {
textView.setText(question);
} else {
textView.setText("Mimicker");
}
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize);
textView.setPadding(horizontalPadding, 0, 0, 0);
LinearLayout.LayoutParams centerInParent = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
centerInParent.gravity = Gravity.CENTER_VERTICAL;
layout.addView(textView, centerInParent);
layout.measure(canvas.getWidth(), height);
layout.layout(0, 0, layout.getMeasuredWidth(), layout.getMeasuredHeight());
canvas.translate(horizontalPadding, (float) (canvas.getHeight() * 0.8 - height));
float scale = Math.min(1.0f, canvas.getWidth() / 1080f);
canvas.scale(scale, scale);
layout.draw(canvas);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_shareable, container, false);
mShareableImage = (ImageView) view.findViewById(R.id.shareable_image);
view.findViewById(R.id.finish_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finishShare();
}
});
view.findViewById(R.id.share_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Reset the timer to wait sharing to complete
updateDismissTaskWithDelayDuration(SHARING_FRAGMENT_SHARE_STAY_DURATION);
share();
}
});
view.findViewById(R.id.download_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Reset the timer to wait downloading to complete
updateDismissTaskWithDelayDuration(SHARING_FRAGMENT_SAVE_STAY_DURATION);
download();
}
});
Bundle args = getArguments();
mShareableUri = args.getString(SHAREABLE_URI);
// Set up timer to dismiss the sharing fragment if there is no user interaction with the buttons
mSharingFragmentDismissTask = new Runnable() {
@Override
public void run() {
finishShare();
}
};
mHandler = new Handler();
Logger.init(getActivity());
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mCallback = (ShareResultListener) context;
}
@Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
@Override
public void onPause() {
super.onPause();
mHandler.removeCallbacks(mSharingFragmentDismissTask);
}
@Override
public void onResume() {
super.onResume();
if (mShareableUri != null && mShareableUri.length() > 0) {
Uri shareableUri = Uri.parse(mShareableUri);
mShareableImage.setImageURI(shareableUri);
}
mHandler.postDelayed(mSharingFragmentDismissTask, mSharingFragmentDismissTaskDelay);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mShareableUri != null && mShareableUri.length() > 0) {
new Thread(new Runnable(){
@Override
public void run() {
File deleteFile = new File(mShareableUri);
boolean deleted = deleteFile.delete();
if (!deleted) {
Loggable.AppError appError = new Loggable.AppError(Loggable.Key.APP_ERROR, "Failed to delete shareable");
Logger.track(appError);
}
}
}).start();
}
mHandler.removeCallbacks(mToastAutoDismiss);
}
public void share() {
Loggable.UserAction userAction = new Loggable.UserAction(Loggable.Key.ACTION_SHARE);
Logger.track(userAction);
mCallback.onRequestLaunchShareAction();
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
// this causes issues with gmail
//shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
File file = new File(mShareableUri);
Uri uri = Uri.fromFile(file);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.putExtra(Intent.EXTRA_TEXT, getResources().getString(R.string.share_text_template));
shareIntent.putExtra(Intent.EXTRA_SUBJECT, getResources().getString(R.string.share_subject_template));
shareIntent.setType("image/*");
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(Intent.createChooser(shareIntent, getResources().getString(R.string.share_action_description)), SHARE_REQUEST_CODE);
}
//
// Copy the temporary mimic picture to the camera folder with a filename with timestamp
//
public void download() {
File cameraDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File sourceFile = new File(mShareableUri);
String dateTimeString = (new SimpleDateFormat("yyyy-MM-dd-HHmmss").format(new Date())); // Example: 2015-12-31-193205
String targetFileName = MIMICKER_FILE_PREFIX + dateTimeString + ".jpg" ; // "Mimicker_2015-12-31-193205.jpg
File targetFile = new File(cameraDirectory.getPath(), targetFileName);
try {
copyFile(sourceFile, targetFile);
} catch (IOException ex) {
showToastInFragment(R.string.share_download_failure);
Logger.trackException(ex);
return;
}
// Inform the media store about the new file
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.MediaColumns.DATA, targetFile.getPath());
getActivity().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
showToastInFragment(R.string.share_download_success);
}
public void copyFile(File sourceFile, File targetFile) throws IOException {
InputStream inputStream = new FileInputStream(sourceFile);
OutputStream outputStream = new FileOutputStream(targetFile);
int len;
byte[] buffer = new byte[4096];
while ((len = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len);
}
inputStream.close();
outputStream.close();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SHARE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
finishShare();
}
}
}
public void finishShare() {
mHandler.removeCallbacks(mSharingFragmentDismissTask);
if (mCallback != null) {
mCallback.onShareCompleted();
}
}
public interface ShareResultListener {
void onShareCompleted();
void onRequestLaunchShareAction();
}
// Display the home-made toast message with the specified string resource ID
//
// We create our own toast message, instead of using android.widget.toast, because
// system toast won't work in lock screen.
private void showToastInFragment(int resourceId) {
String message = getResources().getString(resourceId);
final TextView textView = (TextView)getView().findViewById(R.id.share_toast_message);
textView.setText(message);
textView.setVisibility(View.VISIBLE);
Handler handler = new Handler();
mToastAutoDismiss = new Runnable() {
@Override
public void run() {
textView.setVisibility(View.INVISIBLE);
}
};
handler.postDelayed(mToastAutoDismiss, TOAST_IN_FRAGMENT_DELAY);
}
private void updateDismissTaskWithDelayDuration(int delayDuration) {
mHandler.removeCallbacks(mSharingFragmentDismissTask);
mSharingFragmentDismissTaskDelay = delayDuration;
mHandler.postDelayed(mSharingFragmentDismissTask, mSharingFragmentDismissTaskDelay);
}
}