11a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov/*
21a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * Copyright (C) 2011 The Android Open Source Project
31a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov *
41a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License");
51a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * you may not use this file except in compliance with the License.
61a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * You may obtain a copy of the License at
71a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov *
81a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov *      http://www.apache.org/licenses/LICENSE-2.0
91a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov *
101a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * Unless required by applicable law or agreed to in writing, software
111a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS,
121a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * See the License for the specific language governing permissions and
141a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * limitations under the License.
151a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov */
161a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
171a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovpackage com.android.settings;
181a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
191a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.content.Context;
201a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.content.res.TypedArray;
211a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.os.Parcel;
221a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.os.Parcelable;
231a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.preference.DialogPreference;
241a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.provider.Settings;
251a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.util.AttributeSet;
261a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.view.View;
271a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent;
281a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovimport android.view.accessibility.AccessibilityManager;
291a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
301a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov/**
311a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * Preference for enabling accessibility script injection. It displays a warning
321a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov * dialog before enabling the preference.
331a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov */
341a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganovpublic class AccessibilityEnableScriptInjectionPreference extends DialogPreference {
351a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
361a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    private boolean mInjectionAllowed;
371a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    private boolean mSendClickAccessibilityEvent;
381a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
391a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    public AccessibilityEnableScriptInjectionPreference(Context context, AttributeSet attrs) {
401a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        super(context, attrs);
411a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        updateSummary();
421a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
431a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
441a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    public void setInjectionAllowed(boolean injectionAllowed) {
451a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        if (mInjectionAllowed != injectionAllowed) {
461a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            mInjectionAllowed = injectionAllowed;
471a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            persistBoolean(injectionAllowed);
481a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            updateSummary();
491a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
501a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
511a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
521a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    public boolean isInjectionAllowed() {
531a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        return mInjectionAllowed;
541a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
551a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
561a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    @Override
571a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    protected void onBindView(View view) {
581a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        super.onBindView(view);
591a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        View summaryView = view.findViewById(com.android.internal.R.id.summary);
601a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        sendAccessibilityEvent(summaryView);
611a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
621a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
631a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    private void sendAccessibilityEvent(View view) {
641a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        // Since the view is still not attached we create, populate,
651a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        // and send the event directly since we do not know when it
661a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        // will be attached and posting commands is not as clean.
671a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(getContext());
681a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        if (mSendClickAccessibilityEvent && accessibilityManager.isEnabled()) {
691a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            AccessibilityEvent event = AccessibilityEvent.obtain();
701a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            event.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
711a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            view.onInitializeAccessibilityEvent(event);
721a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            view.dispatchPopulateAccessibilityEvent(event);
731a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            accessibilityManager.sendAccessibilityEvent(event);
741a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
751a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        mSendClickAccessibilityEvent = false;
761a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
771a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
781a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    @Override
791a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    protected void onClick() {
801a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        if (isInjectionAllowed()) {
811a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            setInjectionAllowed(false);
821a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            // Update the system setting only upon user action.
831a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            setSystemSetting(false);
841a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            mSendClickAccessibilityEvent = true;
851a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        } else {
861a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            super.onClick();
871a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            mSendClickAccessibilityEvent = false;
881a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
891a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
901a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
911a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    @Override
921a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    protected Object onGetDefaultValue(TypedArray a, int index) {
931a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        return a.getBoolean(index, false);
941a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
951a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
961a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    @Override
971a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
981a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        setInjectionAllowed(restoreValue
991a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                ? getPersistedBoolean(mInjectionAllowed)
1001a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                : (Boolean) defaultValue);
1011a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
1021a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1031a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    @Override
1041a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    protected void onDialogClosed(boolean result) {
1051a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        setInjectionAllowed(result);
1061a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        if (result) {
1071a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            // Update the system setting only upon user action.
1081a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            setSystemSetting(true);
1091a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
1101a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
1111a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1121a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    @Override
1131a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    protected Parcelable onSaveInstanceState() {
1141a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        Parcelable superState = super.onSaveInstanceState();
1151a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        if (isPersistent()) {
1161a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            return superState;
1171a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
1181a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        SavedState myState = new SavedState(superState);
1191a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        myState.mInjectionAllowed = mInjectionAllowed;
1201a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        return myState;
1211a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
1221a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1231a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    @Override
1241a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    protected void onRestoreInstanceState(Parcelable state) {
1251a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        if (state == null || !state.getClass().equals(SavedState.class)) {
1261a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            super.onRestoreInstanceState(state);
1271a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            return;
1281a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
1291a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        SavedState myState = (SavedState) state;
1301a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        super.onRestoreInstanceState(myState.getSuperState());
1311a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        setInjectionAllowed(myState.mInjectionAllowed);
1321a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
1331a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1341a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    private void updateSummary() {
1351a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        setSummary(mInjectionAllowed
1361a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                ? getContext().getString(R.string.accessibility_script_injection_allowed)
1371a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                : getContext().getString(R.string.accessibility_script_injection_disallowed));
1381a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
1391a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1401a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    private void setSystemSetting(boolean enabled) {
1411a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        Settings.Secure.putInt(getContext().getContentResolver(),
1421a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0);
1431a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
1441a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1451a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    private static class SavedState extends BaseSavedState {
1461a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        private boolean mInjectionAllowed;
1471a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1481a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        public SavedState(Parcel source) {
1491a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            super(source);
1501a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            mInjectionAllowed = (source.readInt() == 1);
1511a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
1521a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1531a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        @Override
1541a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        public void writeToParcel(Parcel parcel, int flags) {
1551a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            super.writeToParcel(parcel, flags);
1561a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            parcel.writeInt(mInjectionAllowed ? 1 : 0);
1571a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
1581a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1591a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        public SavedState(Parcelable superState) {
1601a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            super(superState);
1611a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        }
1621a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1631a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        @SuppressWarnings("all")
1641a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        public static final Parcelable.Creator<SavedState> CREATOR =
1651a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                new Parcelable.Creator<SavedState>() {
1661a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            public SavedState createFromParcel(Parcel in) {
1671a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                return new SavedState(in);
1681a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            }
1691a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov
1701a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            public SavedState[] newArray(int size) {
1711a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov                return new SavedState[size];
1721a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov            }
1731a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov        };
1741a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov    }
1751a97fa13d03d0966ccaa1480c33d8bedce734407Svetoslav Ganov}
176