com.mediatek.galleryfeature.stereo.segment.background.StereoBackgroundActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.mediatek.galleryfeature.stereo.segment.background.StereoBackgroundActivity.java

Source

/* Copyright Statement:
 *
 * This software/firmware and related documentation ("MediaTek Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to MediaTek Inc. and/or its licensors. Without
 * the prior written permission of MediaTek inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of MediaTek Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * MediaTek Inc. (C) 2015. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
 * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
 * SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
 * MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
 *
 * The following software/firmware and/or related documentation ("MediaTek
 * Software") have been modified by MediaTek Inc. All revisions are subject to
 * any receiver's applicable license agreements with MediaTek Inc.
 */

package com.mediatek.galleryfeature.stereo.segment.background;

import android.animation.ObjectAnimator;
import android.app.ActionBar;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore.Images.ImageColumns;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
import android.widget.Toast;

import com.android.gallery3d.R;

import com.mediatek.galleryfeature.stereo.segment.ImageSaver;
import com.mediatek.galleryfeature.stereo.segment.ImageShow;
import com.mediatek.galleryfeature.stereo.segment.MainImageMaster;
import com.mediatek.galleryfeature.stereo.segment.StereoSegmentWrapper;
import com.mediatek.galleryframework.util.MtkLog;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;

/**
 * Activity for background substitution.
 */
public class StereoBackgroundActivity extends FragmentActivity {
    // TODO many redundant code in 3 segment Activities
    // I put the in similar places in each Activity for future further work
    private static final String TAG = "MtkGallery2/SegmentApp/StereoBackgroundActivity";

    private static final int ACTIONBAR_BACKGROUND_COLOR = 0x99333333;
    private static final String BACKGROUNDTHUMB_FRAGMENT_TAG = "MainPanel";
    static final int REQUEST_CODE_PICK_FROM_GALLERY = 211;
    private static final int REQUEST_CODE_REFINE = 10;
    private static final int THUMBNAIL_TRACK_ANIMATION_DURATION = 500;
    private static final int SAVE_QUALITY = 100;

    private MainImageMaster mMasterImage;
    private StereoSegmentWrapper mMaskSimulator;
    private LoadBitmapTask mLoadBitmapTask;
    private WeakReference<ProgressDialog> mSavingProgressDialog;
    private ActionBar mActionBar;
    private Menu mMenu;
    private String mAbsoluteFilePath;
    private Uri mSelectedImageUri;

    private View mSaveButton;
    private View mButtonCollapse;
    private View mBackgroundThumbnailList;
    private View mBackgroundStrip;
    private ImageShow mImageShowBackground;
    private BackgroundThumbAdapter mThumbAdapter;
    private MenuItem mMenuRefineOriginal;
    private Uri mOriginalRefineImage; // == mSelectedUri
    private ForegroundSegmenterParameter mForegroundSegmenterParameter;
    private Bitmap mBitmapCollapse;
    private Bitmap mBitmapExpand;

    private boolean mLoadingVisible = true;
    private boolean mIsDepthImage; // useless
    // exit if file to edit has been deleted
    private boolean mNeedCheckInvalid = true;

    private boolean mIsBottomStripIn = true;

    /**
     * Async task to load main bitmap for ImageShow.
     */
    private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
        private int mBitmapSize;

        public LoadBitmapTask() {
            DisplayMetrics outMetrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
            mBitmapSize = Math.max(outMetrics.heightPixels, outMetrics.widthPixels);
        }

        @Override
        protected Boolean doInBackground(Uri... params) {
            if (!mMasterImage.loadBitmap(params[0], mBitmapSize)) {
                return false;
            }
            mBitmapCollapse = BitmapFactory.decodeResource(getResources(), R.drawable.m_hide_bgthumbs);
            Matrix matrix = new Matrix();
            matrix.postScale(1, -1);
            mBitmapExpand = Bitmap.createBitmap(mBitmapCollapse, 0, 0, mBitmapCollapse.getWidth(),
                    mBitmapCollapse.getHeight(), matrix, true);
            return true;
        }

        @Override
        protected void onProgressUpdate(Boolean... values) {
            super.onProgressUpdate(values);
            if (isCancelled()) {
                return;
            }
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (mLoadingVisible) {
                stopLoadingIndicator();
            }
            if (isCancelled()) {
                return;
            }

            if (!result) {
                cannotLoadImage();
                return;
            }

            StereoSegmentWrapper segmenter = getSegmentWrapper();
            if (segmenter != null) {
                mImageShowBackground.setSegmenter(segmenter);
                mImageShowBackground.setVisibility(View.VISIBLE);
                onImageChange();
            }

            mLoadBitmapTask = null;

            super.onPostExecute(result);
        }
    }

    /**
     * Helper data structure for quick segment restore.
     */
    private class ForegroundSegmenterParameter {
        final int mOriginalWidth;
        final int mOriginalHeight;
        final String mFilePath;
        final Bitmap mBitmap;

        public ForegroundSegmenterParameter(int originalWidth, int originalHeight, String filePath, Bitmap bitmap) {
            mOriginalWidth = originalWidth;
            mOriginalHeight = originalHeight;
            mFilePath = filePath;
            mBitmap = bitmap;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_ACTION_BAR);
        requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);

        // exit if file to edit has been deleted @{
        // it mainly aims to handle language switch or LCA case here
        boolean needExit = finishIfInvalidUri();
        mNeedCheckInvalid = false;
        if (needExit) {
            return;
        }

        // avoid flash when launching
        getWindow().setBackgroundDrawable(new ColorDrawable(0));

        loadXML();

        mMasterImage = new MainImageMaster(this);
        mImageShowBackground.setImageMaster(mMasterImage);

        loadMainBitmapAsync();

        loadThumbnails();

        loadMainPanel();
    }

    @Override
    protected void onDestroy() {
        hideSavingProgress();

        if (mLoadBitmapTask != null) {
            mLoadBitmapTask.cancel(false);
        }

        if (mMaskSimulator != null) {
            mMaskSimulator.release();
            mMaskSimulator = null;
        }

        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.m_stereo_refine_activity_menu, menu);
        mMenu = menu;
        setupMenu();
        return true;
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        finishIfInvalidUri();
        mNeedCheckInvalid = true;

        Fragment panel = getSupportFragmentManager().findFragmentByTag(BACKGROUNDTHUMB_FRAGMENT_TAG);
        if (panel != null) {
            if (panel instanceof MainPanel) {
                MainPanel mainPanel = (MainPanel) panel;
                mainPanel.loadBackgroundThumbPanel(true);
                MtkLog.d(TAG, "<onResume> loadCategoryLookPanel");
            }
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            onBackPressed();
            return true;
        default:
            return false;
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        // TODO do we really need to response onConfigurationChange?
        mImageShowBackground.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
        mImageShowBackground.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
        super.onConfigurationChanged(newConfig);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        MtkLog.d(TAG, "<onActivityResult>, requestCode:" + requestCode);
        if (requestCode == REQUEST_CODE_PICK_FROM_GALLERY) {
            if (resultCode == RESULT_OK) {
                Uri selectedImageUri = data.getData();
                changeBitmap(selectedImageUri);
                updateRecentBackground(selectedImageUri);
            }
        } else if (requestCode == REQUEST_CODE_REFINE) {
            mMaskSimulator = new StereoSegmentWrapper(mForegroundSegmenterParameter.mOriginalWidth,
                    mForegroundSegmenterParameter.mOriginalHeight, mForegroundSegmenterParameter.mBitmap.getWidth(),
                    mForegroundSegmenterParameter.mBitmap.getHeight());
            boolean isSegmentValid = mMaskSimulator.initSegment(mForegroundSegmenterParameter.mFilePath,
                    mForegroundSegmenterParameter.mBitmap);
            if (!isSegmentValid) {
                mImageShowBackground.setSegmenter(null);
                errorHandle();
                return;
            }
            mImageShowBackground.setSegmenter(mMaskSimulator);
            mImageShowBackground.invalidate();
        }
    }

    void changeBitmap(Uri uri) {
        if (uri == null) {
            uri = mOriginalRefineImage;
            if (uri == null) {
                return;
            }
        }
        if (mOriginalRefineImage == null) {
            mOriginalRefineImage = mSelectedImageUri;
            MtkLog.d(TAG, "<changeBitmap> mOriginalRefineImage = " + mOriginalRefineImage);
        }
        if (uri.equals(mOriginalRefineImage)) {
            mSaveButton.setVisibility(View.INVISIBLE);
            mImageShowBackground.setZoomPanSupported(false);
        }
        mLoadBitmapTask = new LoadBitmapTask();
        mLoadBitmapTask.execute(uri);
    }

    BackgroundThumbAdapter getBackgroundThumbAdapter() {
        return mThumbAdapter;
    }

    private void onImageChange() {
        boolean isCurrentOriginal = ((mOriginalRefineImage == null)
                || (mMasterImage.getUri().equals(mOriginalRefineImage)));
        if (mImageShowBackground != null) {
            mMasterImage.setTranslation(new Point(0, 0));
            mMasterImage.setScaleFactor(1);
            mImageShowBackground.invalidate();
            mImageShowBackground.setZoomPanSupported(!isCurrentOriginal);
        }
        if (mSaveButton != null) {
            if (isCurrentOriginal) {
                mSaveButton.setVisibility(View.INVISIBLE);
            } else {
                mSaveButton.setVisibility(View.VISIBLE);
            }
        }
    }

    private StereoSegmentWrapper getSegmentWrapper() {
        if (mIsDepthImage && mMaskSimulator == null) {
            mMaskSimulator = new StereoSegmentWrapper(mMasterImage.getOriginalBounds().width(),
                    mMasterImage.getOriginalBounds().height(), mMasterImage.getBitmap().getWidth(),
                    mMasterImage.getBitmap().getHeight());
            boolean isSegmentValid = mMaskSimulator.initSegment(mAbsoluteFilePath, mMasterImage.getBitmap());
            if (!isSegmentValid) {
                errorHandle();
                return null;
            }
            mForegroundSegmenterParameter = new ForegroundSegmenterParameter(
                    mMasterImage.getOriginalBounds().width(), mMasterImage.getOriginalBounds().height(),
                    mAbsoluteFilePath, mMasterImage.getBitmap());
        }
        return mMaskSimulator;
    }

    private boolean finishIfInvalidUri() {
        if (!mNeedCheckInvalid) {
            return false;
        }
        Uri uri = (mMasterImage != null) ? mMasterImage.getUri() : null;
        Intent intent = getIntent();
        if ((uri == null) && (intent != null)) {
            uri = intent.getData();
        }
        MtkLog.d(TAG, "<finishIfInvalidUri> uri:" + uri);
        if (uri != null) {
            if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
                return false;
            }
            // fix cursor leak
            final String[] projection = new String[] { ImageColumns.DATA, ImageColumns.CAMERA_REFOCUS };
            android.database.Cursor cursor = null;
            cursor = getContentResolver().query(uri, projection, null, null, null);
            if (cursor == null) {
                MtkLog.d(TAG, "<finishIfInvalidUri> cannot get cursor for:" + uri);
                return true;
            }
            try {
                if (cursor.moveToNext()) {
                    mAbsoluteFilePath = cursor.getString(0);
                    MtkLog.d(TAG, "<finishIfInvalidUri> mAbsoluteFilePath = " + mAbsoluteFilePath);
                    mIsDepthImage = (cursor.getInt(1) == 1);
                    MtkLog.d(TAG, "<finishIfInvalidUri> mIsDepthImage = " + mIsDepthImage);
                } else {
                    MtkLog.d(TAG, "<finishIfInvalidUri> cannot find data for: " + uri);
                    return true;
                }
            } finally {
                cursor.close();
            }
        }
        return false;
    }

    private void showSavingProgress(String albumName) {
        ProgressDialog progress;
        if (mSavingProgressDialog != null) {
            progress = mSavingProgressDialog.get();
            if (progress != null) {
                progress.show();
                return;
            }
        }
        // TODO: Allow cancellation of the saving process
        String progressText;
        if (albumName == null) {
            progressText = getString(R.string.saving_image);
        } else {
            progressText = getString(R.string.filtershow_saving_image, albumName);
        }
        progress = ProgressDialog.show(this, "", progressText, true, false);
        mSavingProgressDialog = new WeakReference<ProgressDialog>(progress);
    }

    private void hideSavingProgress() {
        if (mSavingProgressDialog != null) {
            ProgressDialog progress = mSavingProgressDialog.get();
            if (progress != null) {
                progress.dismiss();
            }
        }
    }

    private void startLoadingIndicator() {
        final View loading = findViewById(R.id.loading);
        mLoadingVisible = true;
        loading.setVisibility(View.VISIBLE);
    }

    private void stopLoadingIndicator() {
        final View loading = findViewById(R.id.loading);
        loading.setVisibility(View.GONE);
        mLoadingVisible = false;
    }

    private void startLoadBitmap(Uri uri) {
        mImageShowBackground.setVisibility(View.INVISIBLE);
        startLoadingIndicator();
        mLoadBitmapTask = new LoadBitmapTask();
        mLoadBitmapTask.execute(uri);
    }

    private void cannotLoadImage() {
        Toast.makeText(this, R.string.cannot_load_image, Toast.LENGTH_SHORT).show();
        finish();
    }

    private void loadMainBitmapAsync() {
        Intent intent = getIntent();
        mSelectedImageUri = intent.getData();
        if (mSelectedImageUri != null) {
            startLoadBitmap(mSelectedImageUri);
        }
    }

    private void setActionBarDisplayOptions(ActionBar actionBar, boolean displayHomeAsUp, boolean showTitle) {
        if (actionBar == null) {
            return;
        }
        int options = 0;
        if (displayHomeAsUp) {
            options |= ActionBar.DISPLAY_HOME_AS_UP;
        }
        if (showTitle) {
            options |= ActionBar.DISPLAY_SHOW_TITLE;
        }

        actionBar.setDisplayOptions(options, ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE);
        actionBar.setHomeButtonEnabled(displayHomeAsUp);
        actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
        actionBar.setTitle(R.string.m_save);
    }

    private void loadXML() {
        setContentView(R.layout.m_stereo_background_activity);

        mActionBar = getActionBar();
        mActionBar.setBackgroundDrawable(new ColorDrawable(ACTIONBAR_BACKGROUND_COLOR));
        mActionBar.setSubtitle(null);
        mActionBar.setCustomView(R.layout.m_stereo_actionbar);
        mSaveButton = mActionBar.getCustomView();
        View clickableRegion = mSaveButton.findViewById(R.id.stereo_segment_save);
        clickableRegion.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                saveSynthedImage();
            }
        });

        setActionBarDisplayOptions(mActionBar, true, true);

        mImageShowBackground = (ImageShow) findViewById(R.id.imageShowBackground);
        mButtonCollapse = findViewById(R.id.collapse);
        mBackgroundThumbnailList = findViewById(R.id.main_panel_container);
        mBackgroundStrip = findViewById(R.id.mainPanel);

        mButtonCollapse.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mIsBottomStripIn) {
                    ((ImageView) (mButtonCollapse)).setImageBitmap(mBitmapExpand);
                    ObjectAnimator animator = ObjectAnimator.ofFloat(mBackgroundStrip, "translationY",
                            mBackgroundThumbnailList.getHeight());
                    animator.setDuration(THUMBNAIL_TRACK_ANIMATION_DURATION).start();
                    mIsBottomStripIn = false;
                } else {
                    ((ImageView) (mButtonCollapse)).setImageBitmap(mBitmapCollapse);
                    ObjectAnimator animator = ObjectAnimator.ofFloat(mBackgroundStrip, "translationY", 0);
                    animator.setDuration(THUMBNAIL_TRACK_ANIMATION_DURATION).start();
                    mIsBottomStripIn = true;
                }
            }
        });
    }

    private void setupMenu() {
        if (mMenu == null || mMasterImage == null) {
            return;
        }

        mMenuRefineOriginal = mMenu.findItem(R.id.refine_refine_foreground);
        mMenuRefineOriginal.setVisible(true);

        mMenuRefineOriginal.setOnMenuItemClickListener(new OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Intent intent = new Intent("action_stereo_pick");
                intent.setDataAndType(getIntent().getData(), getIntent().getType())
                        .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

                if (mMaskSimulator != null) {
                    mMaskSimulator.release();
                    mMaskSimulator = null;
                }

                startActivityForResult(intent, REQUEST_CODE_REFINE);

                return false;
            }
        });
    }

    private void errorHandle() {
        Toast.makeText(this, getString(R.string.m_general_err_tip), Toast.LENGTH_LONG).show();
        finish();
    }

    private void saveSynthedImage() {
        new Thread(new Runnable() {
            public void run() {
                runOnUiThread(new Runnable() {
                    public void run() {
                        showSavingProgress(/* "..." */null);
                    }
                });

                Bitmap toSaveBitmap = ((ImageShowBackground) (mImageShowBackground)).getSynthBitmap();

                File target = ImageSaver.getNewFile(StereoBackgroundActivity.this, mSelectedImageUri);
                try {
                    FileOutputStream fos = new FileOutputStream(target);
                    toSaveBitmap.compress(CompressFormat.JPEG, SAVE_QUALITY, fos);
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                long time = System.currentTimeMillis();
                final Uri dstUri = ImageSaver.linkNewFileToUri(StereoBackgroundActivity.this, mSelectedImageUri,
                        target, toSaveBitmap, time);
                toSaveBitmap.recycle();
                runOnUiThread(new Runnable() {
                    public void run() {
                        hideSavingProgress();
                        MtkLog.d(TAG, "<saveSynthedImage> uri:" + dstUri);
                        setResult(RESULT_OK, new Intent().setData(dstUri));
                        StereoBackgroundActivity.this.finish();
                    }
                });
            }
        }).start();
    }

    private void loadMainPanel() {
        if (findViewById(R.id.main_panel_container) == null) {
            return;
        }
        MainPanel panel = new MainPanel();
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.main_panel_container, panel, BACKGROUNDTHUMB_FRAGMENT_TAG);
        transaction.commitAllowingStateLoss();
    }

    private void loadThumbnails() {
        MtkLog.d(TAG, "<loadThumbnails>");
        if (mThumbAdapter != null) {
            mThumbAdapter.clear();
        }
        mThumbAdapter = new BackgroundThumbAdapter(this);
        int verticalItemHeight = (int) getResources().getDimension(R.dimen.action_item_height);
        mThumbAdapter.loadActions(this, verticalItemHeight);
    }

    private void updateRecentBackground(Uri bgUri) {
        BackgroundThumbAction action = new BackgroundThumbAction(this, BackgroundThumbAction.FULL_VIEW);
        action.setOriginal(false);
        action.setUri(bgUri.toString());
        mThumbAdapter.addFront(action);
        mThumbAdapter.saveActions();
    }
}