119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh/* 219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * Copyright (C) 2011 The Android Open Source Project 319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * 419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * you may not use this file except in compliance with the License. 619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * You may obtain a copy of the License at 719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * 819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * 1019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software 1119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 1219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * See the License for the specific language governing permissions and 1419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh * limitations under the License. 1519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh */ 1619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 1719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehpackage com.android.vpndialogs; 1819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 1919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.content.Context; 2019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.content.DialogInterface; 2119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.content.Intent; 2219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.content.pm.ApplicationInfo; 2319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.content.pm.PackageManager; 24f530da67b4f9ffa55bb8a1c05390c6f7f87fe4baChia-chi Yehimport android.net.IConnectivityManager; 2519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.os.Handler; 2619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.os.Message; 27f530da67b4f9ffa55bb8a1c05390c6f7f87fe4baChia-chi Yehimport android.os.ServiceManager; 2819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.os.SystemClock; 2919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.util.Log; 3019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.view.View; 3119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.widget.Button; 3219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.widget.CompoundButton; 3319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.widget.ImageView; 3419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport android.widget.TextView; 3519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 36ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yehimport com.android.internal.app.AlertActivity; 3742bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yehimport com.android.internal.net.VpnConfig; 3842bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh 3919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport java.io.DataInputStream; 4019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yehimport java.io.FileInputStream; 4119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 42ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yehpublic class ManageDialog extends AlertActivity implements 43ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh DialogInterface.OnClickListener, Handler.Callback { 4419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh private static final String TAG = "VpnManage"; 4519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 4642bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh private VpnConfig mConfig; 4719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 48f530da67b4f9ffa55bb8a1c05390c6f7f87fe4baChia-chi Yeh private IConnectivityManager mService; 4919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 5019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh private TextView mDuration; 5119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh private TextView mDataTransmitted; 5219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh private TextView mDataReceived; 53b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh private boolean mDataRowsHidden; 5419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 5542bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh private Handler mHandler; 5619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 5719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh @Override 5819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh protected void onResume() { 5919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh super.onResume(); 60339abf1fbac25321cea9d39de14b6a6b4e326120Chia-chi Yeh 61339abf1fbac25321cea9d39de14b6a6b4e326120Chia-chi Yeh if (getCallingPackage() != null) { 62339abf1fbac25321cea9d39de14b6a6b4e326120Chia-chi Yeh Log.e(TAG, getCallingPackage() + " cannot start this activity"); 63339abf1fbac25321cea9d39de14b6a6b4e326120Chia-chi Yeh finish(); 64339abf1fbac25321cea9d39de14b6a6b4e326120Chia-chi Yeh return; 65339abf1fbac25321cea9d39de14b6a6b4e326120Chia-chi Yeh } 66339abf1fbac25321cea9d39de14b6a6b4e326120Chia-chi Yeh 6719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh try { 6819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 69f530da67b4f9ffa55bb8a1c05390c6f7f87fe4baChia-chi Yeh mService = IConnectivityManager.Stub.asInterface( 70f530da67b4f9ffa55bb8a1c05390c6f7f87fe4baChia-chi Yeh ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); 7119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 72bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker mConfig = mService.getVpnConfig(); 73bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker 74bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker // mConfig can be null if we are a restricted user, in that case don't show this dialog 75bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker if (mConfig == null) { 76bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker finish(); 77bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker return; 78bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker } 79bf6ff2c025405a3af496fe558dfc4468a9b45cc8Chad Brubaker 8019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh View view = View.inflate(this, R.layout.manage, null); 8134e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh if (mConfig.session != null) { 8234e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh ((TextView) view.findViewById(R.id.session)).setText(mConfig.session); 8319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 8419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh mDuration = (TextView) view.findViewById(R.id.duration); 8519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted); 8619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh mDataReceived = (TextView) view.findViewById(R.id.data_received); 87b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh mDataRowsHidden = true; 8819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 89899223b97c9b0ae56a8211a46600914c0ecfd854Jeff Sharkey if (mConfig.legacy) { 90ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mIconId = android.R.drawable.ic_dialog_info; 91ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mTitle = getText(R.string.legacy_title); 925db03df1fff4900eb485304d4fd185110bea1a0cChia-chi Yeh } else { 935db03df1fff4900eb485304d4fd185110bea1a0cChia-chi Yeh PackageManager pm = getPackageManager(); 94fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0); 95ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mIcon = app.loadIcon(pm); 96ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mTitle = app.loadLabel(pm); 975db03df1fff4900eb485304d4fd185110bea1a0cChia-chi Yeh } 985db03df1fff4900eb485304d4fd185110bea1a0cChia-chi Yeh if (mConfig.configureIntent != null) { 99ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mPositiveButtonText = getText(R.string.configure); 100ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mPositiveButtonListener = this; 10142bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh } 102ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mNeutralButtonText = getText(R.string.disconnect); 103ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mNeutralButtonListener = this; 104ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mNegativeButtonText = getText(android.R.string.cancel); 105ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mNegativeButtonListener = this; 106ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh mAlertParams.mView = view; 107ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh setupAlert(); 10819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 10942bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh if (mHandler == null) { 11042bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh mHandler = new Handler(this); 11142bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh } 11242bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh mHandler.sendEmptyMessage(0); 11319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } catch (Exception e) { 11419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh Log.e(TAG, "onResume", e); 11519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh finish(); 11619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 11719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 11819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 11919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh @Override 12019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh protected void onPause() { 12119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh super.onPause(); 122ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh if (!isFinishing()) { 123ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh finish(); 12419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 12519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 12619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 12719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh @Override 12819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh public void onClick(DialogInterface dialog, int which) { 12919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh try { 130ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh if (which == DialogInterface.BUTTON_POSITIVE) { 1315db03df1fff4900eb485304d4fd185110bea1a0cChia-chi Yeh mConfig.configureIntent.send(); 132ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh } else if (which == DialogInterface.BUTTON_NEUTRAL) { 13382f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey if (mConfig.legacy) { 13482f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); 13582f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } else { 13682f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN); 13782f8521d386f3109147c477d04e5e90e5c715fa0Jeff Sharkey } 13819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 13919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } catch (Exception e) { 14019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh Log.e(TAG, "onClick", e); 14142bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh finish(); 14219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 14319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 14419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 14519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh @Override 14642bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh public boolean handleMessage(Message message) { 14742bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh mHandler.removeMessages(0); 14842bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh 149ae380fb89dedaa03597d031370a18aa153a6a645Chia-chi Yeh if (!isFinishing()) { 1502b862e5e75ad419f17a4cea185b9349e0da70e7bVinit Deshapnde if (mConfig.startTime != -1) { 15142bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000; 15242bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh mDuration.setText(String.format("%02d:%02d:%02d", 15342bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh seconds / 3600, seconds / 60 % 60, seconds % 60)); 15442bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh } 15519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 156b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh String[] numbers = getNumbers(); 15742bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh if (numbers != null) { 158b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh // First unhide the related data rows. 159b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh if (mDataRowsHidden) { 160b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh findViewById(R.id.data_transmitted_row).setVisibility(View.VISIBLE); 161b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh findViewById(R.id.data_received_row).setVisibility(View.VISIBLE); 162b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh mDataRowsHidden = false; 163b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh } 164b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh 16542bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh // [1] and [2] are received data in bytes and packets. 16642bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh mDataReceived.setText(getString(R.string.data_value_format, 16742bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh numbers[1], numbers[2])); 16819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 16942bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh // [9] and [10] are transmitted data in bytes and packets. 17042bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh mDataTransmitted.setText(getString(R.string.data_value_format, 17142bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh numbers[9], numbers[10])); 17219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 17342bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh mHandler.sendEmptyMessageDelayed(0, 1000); 17419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 17542bd53a9ff3f6358485e37df970754833aab2629Chia-chi Yeh return true; 17619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 17719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 178b0736abca910fbba8c31c002d7335360f5bc0929Chia-chi Yeh private String[] getNumbers() { 17919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh DataInputStream in = null; 18019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh try { 18119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh // See dev_seq_printf_stats() in net/core/dev.c. 18219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh in = new DataInputStream(new FileInputStream("/proc/net/dev")); 18334e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh String prefix = mConfig.interfaze + ':'; 18419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh 18519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh while (true) { 18619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh String line = in.readLine().trim(); 18719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh if (line.startsWith(prefix)) { 18819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh String[] numbers = line.substring(prefix.length()).split(" +"); 18972fddaa5d9b295571b63ec6bc28dcdd9eda482b1Chia-chi Yeh for (int i = 1; i < 17; ++i) { 19072fddaa5d9b295571b63ec6bc28dcdd9eda482b1Chia-chi Yeh if (!numbers[i].equals("0")) { 19172fddaa5d9b295571b63ec6bc28dcdd9eda482b1Chia-chi Yeh return numbers; 19272fddaa5d9b295571b63ec6bc28dcdd9eda482b1Chia-chi Yeh } 19319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 19419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh break; 19519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 19619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 19719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } catch (Exception e) { 19819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh // ignore 19919f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } finally { 20019f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh try { 20119f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh in.close(); 20219f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } catch (Exception e) { 20319f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh // ignore 20419f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 20519f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 20619f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh return null; 20719f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh } 20819f054b0f69b2f56ea0e98a3bb7e0e62b90ff480Chia-chi Yeh} 209