/* ConfirmAuthFramgment.java Copyright (c) 2014 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.localoauth.fragment; import android.annotation.SuppressLint; import android.app.Fragment; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import org.deviceconnect.android.R; import org.deviceconnect.android.localoauth.LocalOAuth2Main; import org.deviceconnect.android.localoauth.LocalOAuth2Service; import org.deviceconnect.android.localoauth.LocalOAuth2Settings; import org.deviceconnect.android.localoauth.ScopeUtil; import org.deviceconnect.android.localoauth.activity.ConfirmAuthActivity; import org.restlet.ext.oauth.internal.AbstractTokenManager; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; /** * 認可ダイアログ. * @author NTT DOCOMO, INC. */ @SuppressLint("HandlerLeak") public class ConfirmAuthFragment extends Fragment { /** 自動クリック処理を実行するまでの時間[msec]. テスト用。 */ private static final long AUTO_CLICK_WAIT_TIME = 3000; /** 自動クリック用タイマー. テスト用。 */ private Timer mAutoClickTimer; /** 呼び出し元のスレッドID. */ private long mThreadId; /** Messenger for communicating with the service. */ private Messenger mService; /** Flag indicating whether we have called bind on the service. */ private boolean mBound; /** 受信用メッセンジャー設定. */ private Messenger mSelfMessenger; /** Flag indicating whether we have done response. */ private boolean mDoneResponse; @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { /* Intentから値取得 */ Intent intent = getActivity().getIntent(); mThreadId = intent.getLongExtra(ConfirmAuthActivity.EXTRA_THREADID, -1); String applicationName = intent.getStringExtra(ConfirmAuthActivity.EXTRA_APPLICATIONNAME); String packageName = intent.getStringExtra(ConfirmAuthActivity.EXTRA_PACKAGE_NAME); String keyword = intent.getStringExtra(ConfirmAuthActivity.EXTRA_KEYWORD); String[] displayScopes = intent.getStringArrayExtra(ConfirmAuthActivity.EXTRA_DISPLAY_SCOPES); String expirePeriod = toStringExpiredPeriod(); boolean isForPlugin = intent.getBooleanExtra(ConfirmAuthActivity.EXTRA_IS_FOR_DEVICEPLUGIN, true); int layoutId; if (isForPlugin) { layoutId = R.layout.confirm_auth_activity_plugin; } else { layoutId = R.layout.confirm_auth_activity_manager; } View view = inflater.inflate(layoutId, container, false); // 有効期限 TextView textViewExpirePeriod = (TextView) view.findViewById(R.id.textViewExpirePeriod); textViewExpirePeriod.setText(expirePeriod); // アプリ名 TextView textViewApplicationName = (TextView) view.findViewById(R.id.textViewAccessToken); textViewApplicationName.setText(applicationName); /* スコープ一覧表示 */ ListView listViewScopes = (ListView) view.findViewById(R.id.listViewScopes); listViewScopes.setAdapter(new ArrayAdapter<String>(getActivity(), R.layout.confirm_auth_scopes_list_item, R.id.textViewScope, displayScopes)); /* 承認ボタン */ Button buttonApproval = (Button) view.findViewById(R.id.buttonApproval); buttonApproval.setOnClickListener(mOnButtonApprovalClickListener); // 拒否ボタン Button buttonReject = (Button) view.findViewById(R.id.buttonReject); buttonReject.setOnClickListener(mOnButtonApprovalClickListener); if (!isForPlugin) { // アプリのアクセス先(=マネージャ)のパッケージ名 TextView textViewPackageName = (TextView) view.findViewById(R.id.textPackageName); textViewPackageName.setText(packageName); // キーワード TextView textViewKeyword = (TextView) view.findViewById(R.id.textKeyword); textViewKeyword.setText(keyword); } /* 受信用メッセンジャー設定 */ mSelfMessenger = new Messenger(new Handler() { @Override public void handleMessage(final Message msg) { if (msg.what == LocalOAuth2Main.MSG_CHECK_THREADID_RESULT) { /* threadIdはキューに存在しないのでActivityを閉じる(残ってしまったアプリ履歴からの起動の場合を想定) */ if (msg.arg1 == 0 && getActivity() != null) { getActivity().finish(); } } } }); /* 自動テストモードの場合は、タイマーを開始する */ if (LocalOAuth2Main.isAutoTestMode()) { if (mAutoClickTimer == null) { TimerTask timerTask = new TimerTask() { @Override public void run() { if (getActivity() != null) { getActivity().runOnUiThread(new Runnable() { @Override public void run() { approvalProc(); } }); } } }; mAutoClickTimer = new Timer(true); mAutoClickTimer.schedule(timerTask, AUTO_CLICK_WAIT_TIME); } } return view; } @Override public void onResume() { super.onResume(); /* ServiceConnectionを渡してServiceとBindする */ Intent intent = new Intent(); intent.setClass(getActivity(), LocalOAuth2Service.class); intent.setPackage(getActivity().getPackageName()); getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override public void onPause() { cancelAutoClickTimer(); super.onPause(); getActivity().unbindService(mConnection); } /** Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(final ComponentName className, final IBinder service) { mService = new Messenger(service); mBound = true; /* Bindが接続されたらthreadId有効チェック */ sendMessageCheckThreadId(mThreadId); } @Override public void onServiceDisconnected(final ComponentName className) { mService = null; mBound = false; } }; /** * Message通知処理. * * @param isApproval true: 許可 / false: 拒否 */ private void sendMessage(final Boolean isApproval) { if (!mBound) { return; } /* Messageを使って許可・拒否のステータスをServiceに送る */ int iIsApproval = ConfirmAuthActivity.DISAPPROVAL; if (isApproval) { iIsApproval = ConfirmAuthActivity.APPROVAL; } Message msg = Message.obtain(null, LocalOAuth2Main.MSG_CONFIRM_APPROVAL, (int) mThreadId, iIsApproval); try { mService.send(msg); } catch (RemoteException e) { // サービスがDeadObjectになっている getActivity().finish(); } } /** * threadId有効チェックメッセージ送信. * @param threadId 判定するスレッドID */ private void sendMessageCheckThreadId(final long threadId) { Message msg = Message.obtain(null, LocalOAuth2Main.MSG_CONFIRM_CHECK_THREADID, (int) threadId, 0); msg.replyTo = mSelfMessenger; try { mService.send(msg); } catch (RemoteException e) { // サービスがDeadObjectになっている getActivity().finish(); } } /** * 許可ボタンをタップしたときの処理を行うリスナー. */ private OnClickListener mOnButtonApprovalClickListener = new OnClickListener() { @Override public void onClick(final View v) { int id = v.getId(); if (id == R.id.buttonApproval) { /* 自動クリックタイマーが起動中なら停止する */ cancelAutoClickTimer(); approvalProc(); } else if (id == R.id.buttonReject) { cancelAutoClickTimer(); notApprovalProc(); } } }; /** * 承認ボタンを押下されたときの処理. * <p> * 既にレスポンスを返却している場合には何もしない。 * </p> */ public synchronized void approvalProc() { if (mDoneResponse) { return; } sendMessage(true); getActivity().finish(); mDoneResponse = true; } /** * 拒否ボタンを押下されたときの処理. * <p> * 既にレスポンスを返却している場合には何もしない。 * </p> */ public synchronized void notApprovalProc() { if (mDoneResponse) { return; } sendMessage(false); getActivity().finish(); mDoneResponse = true; } /** * 有効期限日を文字列で返す. * @param expirePeriodSec 有効期限[秒] * @return 有効期限日を文字列 */ private String toExpirePeriodDateString(final long expirePeriodSec) { Calendar now = Calendar.getInstance(); long expirePeriodDateMSec = now.getTimeInMillis() + expirePeriodSec * LocalOAuth2Settings.MSEC; String s = ScopeUtil.getDisplayExpirePeriodDate(expirePeriodDateMSec); return s; } /** * 有効期限の文字列を取得する. * @return 有効期限の文字列 */ private String toStringExpiredPeriod() { String expirePeriodFormat = getString(R.string.expire_period_format); String expirePeriodValue = toExpirePeriodDateString(AbstractTokenManager.DEFAULT_TOKEN_EXPIRE_PERIOD); String expirePeriod = String.format(expirePeriodFormat, expirePeriodValue); return expirePeriod; } /** * 自動クリックタイマーを停止する. */ private void cancelAutoClickTimer() { if (mAutoClickTimer != null) { mAutoClickTimer.cancel(); mAutoClickTimer = null; } } }