/* * Copyright 2012-2015 One Platform Foundation * * Licensed 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 org.onepf.opfiab.android; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; import android.view.WindowManager; import org.onepf.opfiab.OPFIab; import org.onepf.opfiab.model.ComponentState; import org.onepf.opfiab.model.event.android.ActivityLifecycleEvent; import org.onepf.opfiab.model.event.android.ActivityNewIntentEvent; import org.onepf.opfiab.model.event.android.ActivityResult; import org.onepf.opfutils.OPFLog; /** * Untouchable activity without UI. * <p> * Intended to intercept {@link Activity#onActivityResult(int, int, Intent)} callback, * or to be used as Activity {@link Context} when one is not available. */ @SuppressLint("Registered") public class OPFIabActivity extends Activity { /** * If activity is not expecting {@link #onActivityResult(int, int, Intent)} call, it will * auto-finish after this timeout. */ protected static final long FINISH_DELAY = 1000L; /** * Start new instance of this activity. * * @param context Can't be null. Context object witch will be used to start new instance of * {@link OPFIabActivity}. If passed object is not <code>instanceof</code> * {@link Activity}, new activity will be started with * {@link Intent#FLAG_ACTIVITY_NEW_TASK} flag. */ public static void start(@NonNull final Context context) { final Intent intent = new Intent(context, OPFIabActivity.class); final int flags = Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_NO_ANIMATION; if (context instanceof Activity) { intent.setFlags(flags); } else { intent.setFlags(flags | Intent.FLAG_ACTIVITY_NEW_TASK); } OPFLog.d("Starting OPFIabActivity with " + context + " as context"); context.startActivity(intent); } protected final Handler handler = new Handler(Looper.getMainLooper()); /** * Used to finish activity if for some reason it wasn't used by library. */ protected final Runnable finishTask = new Runnable() { @Override public void run() { if (!isFinishing()) { OPFLog.e("OPFIabActivity wasn't utilised! Finishing: %s", OPFIabActivity.this); finish(); } } }; /** * Used to schedule {@link #finishTask} call after timeout. * <p> * Resets timeout if task has been already scheduled. * * @param schedule True if finish should be scheduled, false otherwise. */ protected void scheduleFinish(final boolean schedule) { handler.removeCallbacks(finishTask); if (schedule) { handler.postDelayed(finishTask, FINISH_DELAY); } } @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); OPFLog.d("onCreate: %s, task: %d", this, getTaskId()); // Don't handle any touch events getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); OPFIab.post(new ActivityLifecycleEvent(ComponentState.CREATE, this)); onNewIntent(getIntent()); } @Override protected void onNewIntent(final Intent intent) { super.onNewIntent(intent); OPFLog.d("onNewIntent: %s, task: %d, Intent: %s", this, getTaskId(), intent); scheduleFinish(true); OPFIab.post(new ActivityNewIntentEvent(this, intent)); } @Override protected void onDestroy() { OPFLog.d("onDestroy: %s, task: %d", this, getTaskId()); super.onDestroy(); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); OPFLog.d("onActivityResult: %s, task: %d", this, getTaskId()); // Result event subscriber should finish activity when it's done with it. OPFIab.post(new ActivityResult(this, requestCode, resultCode, data)); } @Override public void finish() { OPFLog.d("finish: %s, task: %d", this, getTaskId()); scheduleFinish(false); super.finish(); } @Override public void startActivityForResult(final Intent intent, final int requestCode) { scheduleFinish(false); super.startActivityForResult(intent, requestCode); } @Override public void startActivityForResult(final Intent intent, final int requestCode, final Bundle options) { scheduleFinish(false); super.startActivityForResult(intent, requestCode, options); } @Override public void startIntentSenderForResult(final IntentSender intent, final int requestCode, final Intent fillInIntent, final int flagsMask, final int flagsValues, final int extraFlags) throws IntentSender.SendIntentException { scheduleFinish(false); super.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask, flagsValues, extraFlags); } @Override public void startIntentSenderForResult(final IntentSender intent, final int requestCode, final Intent fillInIntent, final int flagsMask, final int flagsValues, final int extraFlags, final Bundle options) throws IntentSender.SendIntentException { scheduleFinish(false); super.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask, flagsValues, extraFlags, options); } @Override public void onBackPressed() { // ignore } }