UsbModeChooserActivity.java revision 1c3fd76ee08e63d5a12387e21a59f89c431fc17a
17000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich/*
27000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * Copyright (C) 2015 The Android Open Source Project
37000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich *
47000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * Licensed under the Apache License, Version 2.0 (the "License");
57000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * you may not use this file except in compliance with the License.
67000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * You may obtain a copy of the License at
77000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich *
87000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich *      http://www.apache.org/licenses/LICENSE-2.0
97000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich *
107000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * Unless required by applicable law or agreed to in writing, software
117000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * distributed under the License is distributed on an "AS IS" BASIS,
127000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * See the License for the specific language governing permissions and
147000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * limitations under the License.
157000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich */
167000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich
177000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichpackage com.android.settings.deviceinfo;
187000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich
197000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichimport android.annotation.Nullable;
207000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichimport android.app.Activity;
2172aa5379806759fbf8f8402500b69f34eccb1956Guang Zhuimport android.app.ActivityManager;
227000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichimport android.app.AlertDialog;
2393df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbinimport android.content.BroadcastReceiver;
2493df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbinimport android.content.Context;
257000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichimport android.content.DialogInterface;
2693df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbinimport android.content.Intent;
2793df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbinimport android.content.IntentFilter;
281c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shankaimport android.graphics.drawable.Drawable;
291c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shankaimport android.graphics.PorterDuff;
3093df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbinimport android.hardware.usb.UsbManager;
317000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichimport android.os.Bundle;
321c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shankaimport android.os.UserHandle;
331c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shankaimport android.os.UserManager;
3483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monkimport android.view.LayoutInflater;
3583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monkimport android.view.View;
3683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monkimport android.view.View.OnClickListener;
3783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monkimport android.widget.Checkable;
3883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monkimport android.widget.LinearLayout;
3983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monkimport android.widget.TextView;
4072aa5379806759fbf8f8402500b69f34eccb1956Guang Zhu
417000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichimport com.android.settings.R;
421c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shankaimport com.android.settingslib.RestrictedLockUtils;
431c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka
441c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shankaimport static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
457000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich
467000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich/**
477000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich * UI for the USB chooser dialog.
487000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich *
497000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich */
507000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevichpublic class UsbModeChooserActivity extends Activity {
517000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich
5283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    public static final int[] DEFAULT_MODES = {
5383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_NONE,
5483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_NONE,
5583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MTP,
5683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_PTP,
5783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MIDI
5883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    };
5983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk
6083290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    private UsbBackend mBackend;
6183290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    private AlertDialog mDialog;
6283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    private LayoutInflater mLayoutInflater;
631c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka    private EnforcedAdmin mEnforcedAdmin;
647000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich
6593df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    private BroadcastReceiver mDisconnectedReceiver = new BroadcastReceiver() {
6693df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        @Override
6793df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        public void onReceive(Context context, Intent intent) {
6893df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin            String action = intent.getAction();
6993df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin            if (UsbManager.ACTION_USB_STATE.equals(action)) {
7093df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin                boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
7193df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin                if (!connected) {
7293df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin                    mDialog.dismiss();
7393df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin                }
7493df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin            }
7593df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        }
7693df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    };
7793df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin
787000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich    @Override
797000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich    protected void onCreate(@Nullable Bundle savedInstanceState) {
808a9b03f746233fa00d4e32f018acac919c824f6fNick Kralevich
817000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich        super.onCreate(savedInstanceState);
82ec323a0849155302b3b522fe34a2638be74af420Zoltan Szatmary-Ban
8383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        mLayoutInflater = LayoutInflater.from(this);
8483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk
8583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        mDialog = new AlertDialog.Builder(this)
8683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                .setTitle(R.string.usb_use)
8783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                .setView(R.layout.usb_dialog_container)
8883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                .setOnDismissListener(new DialogInterface.OnDismissListener() {
8983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                    @Override
9083290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                    public void onDismiss(DialogInterface dialog) {
9183290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                        finish();
9283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                    }
9383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                })
9483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
957000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich                    @Override
967000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich                    public void onClick(DialogInterface dialog, int which) {
9783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                        finish();
987000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich                    }
9983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                }).create();
10083290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        mDialog.show();
10183290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk
10283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        LinearLayout container = (LinearLayout) mDialog.findViewById(R.id.container);
10383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk
1041c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        mEnforcedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(this,
1051c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                UserManager.DISALLOW_USB_FILE_TRANSFER, UserHandle.myUserId());
10683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        mBackend = new UsbBackend(this);
10783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        int current = mBackend.getCurrentMode();
10883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        for (int i = 0; i < DEFAULT_MODES.length; i++) {
10983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            if (mBackend.isModeSupported(DEFAULT_MODES[i])) {
1101c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                inflateOption(DEFAULT_MODES[i], current == DEFAULT_MODES[i], container,
1111c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                        mBackend.isModeDisallowedByAdmin(DEFAULT_MODES[i]));
1127000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich            }
11383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        }
11483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    }
11583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk
11693df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    @Override
11793df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    public void onStart() {
11893df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        super.onStart();
11993df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin
12093df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
12193df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        registerReceiver(mDisconnectedReceiver, filter);
12293df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    }
12393df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin
12493df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    @Override
12593df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    protected void onStop() {
12693df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        unregisterReceiver(mDisconnectedReceiver);
12793df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin        super.onStop();
12893df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin    }
12993df36a1c7ae91c304e7d7eb55462b84705a49b3Du, Changbin
1301c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka    private void inflateOption(final int mode, boolean selected, LinearLayout container,
1311c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            final boolean disallowedByAdmin) {
13283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        View v = mLayoutInflater.inflate(R.layout.radio_with_summary, container, false);
13383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk
1341c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        TextView titleView = (TextView) v.findViewById(android.R.id.title);
1351c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        titleView.setText(getTitle(mode));
1361c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        TextView summaryView = (TextView) v.findViewById(android.R.id.summary);
1371c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        summaryView.setText(getSummary(mode));
1381c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka
1391c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        if (disallowedByAdmin) {
1401c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            if (mEnforcedAdmin != null) {
1411c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                setDisabledByAdmin(titleView, summaryView);
1421c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            } else {
1431c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                return;
1441c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            }
1451c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        }
14683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk
14783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        v.setOnClickListener(new OnClickListener() {
1487000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich            @Override
14983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            public void onClick(View v) {
1501c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                if (disallowedByAdmin && mEnforcedAdmin != null) {
1511c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
1521c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                            UsbModeChooserActivity.this, mEnforcedAdmin);
1531c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                    return;
1541c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                }
15583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                if (!ActivityManager.isUserAMonkey()) {
15683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                    mBackend.setMode(mode);
15783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                }
15883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                mDialog.dismiss();
15983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                finish();
1607000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich            }
1617000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich        });
16283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        ((Checkable) v).setChecked(selected);
16383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        container.addView(v);
1647000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich    }
1657000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich
1661c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka    private void setDisabledByAdmin(TextView titleView, TextView summaryView) {
1671c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        if (mEnforcedAdmin != null) {
1681c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            titleView.setEnabled(false);
1691c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            summaryView.setEnabled(false);
1701c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            RestrictedLockUtils.setTextViewPadlock(this,
1711c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                    titleView, true /* showPadlock */);
1721c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            Drawable[] compoundDrawables = titleView.getCompoundDrawablesRelative();
1731c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka            compoundDrawables[0 /* start */].mutate().setColorFilter(
1741c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka                    getColor(R.color.disabled_text_color), PorterDuff.Mode.MULTIPLY);
1751c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka        }
1761c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka    }
1771c3fd76ee08e63d5a12387e21a59f89c431fc17aSudheer Shanka
17883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    private static int getSummary(int mode) {
17983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        switch (mode) {
18083290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_NONE:
18183290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_charging_only_desc;
18283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_NONE:
18383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_power_only_desc;
18483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MTP:
18583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_file_transfers_desc;
18683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_PTP:
18783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_photo_transfers_desc;
18883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MIDI:
18983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_MIDI_desc;
1907000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich        }
1917000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich        return 0;
1927000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich    }
1937000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich
19483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk    private static int getTitle(int mode) {
19583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        switch (mode) {
19683290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_NONE:
19783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_charging_only;
19883290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SOURCE | UsbBackend.MODE_DATA_NONE:
19983290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_power_only;
20083290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MTP:
20183290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_file_transfers;
20283290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_PTP:
20383290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_photo_transfers;
20483290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk            case UsbBackend.MODE_POWER_SINK | UsbBackend.MODE_DATA_MIDI:
20583290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk                return R.string.usb_use_MIDI;
2067000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich        }
20783290eef8cfeebc9736f077d78003d78e6bf1320Jason Monk        return 0;
2087000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich    }
2097000d5433880b736bd67cbb44f66df771b64ee1bNick Kralevich}
210