10cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard/**
20cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * Copyright (C) 2011 The Android Open Source Project
30cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard *
40cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * Licensed under the Apache License, Version 2.0 (the "License"); you may not
50cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * use this file except in compliance with the License. You may obtain a copy
60cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * of the License at
70cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard *
80cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * http://www.apache.org/licenses/LICENSE-2.0
90cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard *
100cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * Unless required by applicable law or agreed to in writing, software
110cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
120cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
130cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * License for the specific language governing permissions and limitations
140cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * under the License.
150cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard */
160cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
170cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardpackage com.android.inputmethod.dictionarypack;
180cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
190cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardimport android.content.Context;
200cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardimport android.content.SharedPreferences;
2141f505dc3e6ba7aa850e0c4dbe2d6093ddd6fc2dJean Chalardimport android.preference.Preference;
220cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardimport android.util.Log;
230cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardimport android.view.View;
240cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardimport android.view.ViewGroup;
25f8014eea341040f8d155e071e4e0c915a7ebd61dJean Chalardimport android.view.ViewParent;
26f8014eea341040f8d155e071e4e0c915a7ebd61dJean Chalardimport android.widget.ListView;
27ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalardimport android.widget.TextView;
280cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
290cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardimport com.android.inputmethod.latin.R;
300cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
310cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalardimport java.util.Locale;
320cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
330cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard/**
340cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * A preference for one word list.
350cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard *
360cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * This preference refers to a single word list, as available in the dictionary
370cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * pack. Upon being pressed, it displays a menu to allow the user to install, disable,
380cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard * enable or delete it as appropriate for the current state of the word list.
390cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard */
4041f505dc3e6ba7aa850e0c4dbe2d6093ddd6fc2dJean Chalardpublic final class WordListPreference extends Preference {
415f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static final String TAG = WordListPreference.class.getSimpleName();
420cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
430cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    // What to display in the "status" field when we receive unknown data as a status from
440cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    // the content provider. Empty string sounds sensible.
455f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static final String NO_STATUS_MESSAGE = "";
460cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
470cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    /// Actions
485f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static final int ACTION_UNKNOWN = 0;
495f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static final int ACTION_ENABLE_DICT = 1;
505f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static final int ACTION_DISABLE_DICT = 2;
515f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private static final int ACTION_DELETE_DICT = 3;
520cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
530cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    // Members
540cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    // The metadata word list id and version of this word list.
550cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    public final String mWordlistId;
560cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    public final int mVersion;
57a2ec5e8338c82f1e49c3d98f502dcc30c9c12fb0Jean Chalard    public final Locale mLocale;
58a2ec5e8338c82f1e49c3d98f502dcc30c9c12fb0Jean Chalard    public final String mDescription;
595f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka
605f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    // The id of the client for which this preference is.
615f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    private final String mClientId;
620cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    // The status
6326f489493eb3a1ccb9cb0ab55627bee4c74a6fd2Jean Chalard    private int mStatus;
64ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard    // The size of the dictionary file
65ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard    private final int mFilesize;
660cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
67c017f18a59a6b0ba1905a67193057b5b70410e06Jean Chalard    private final DictionaryListInterfaceState mInterfaceState;
680cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
69c017f18a59a6b0ba1905a67193057b5b70410e06Jean Chalard    public WordListPreference(final Context context,
70c017f18a59a6b0ba1905a67193057b5b70410e06Jean Chalard            final DictionaryListInterfaceState dictionaryListInterfaceState, final String clientId,
71c017f18a59a6b0ba1905a67193057b5b70410e06Jean Chalard            final String wordlistId, final int version, final Locale locale,
72ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard            final String description, final int status, final int filesize) {
730cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        super(context, null);
74c017f18a59a6b0ba1905a67193057b5b70410e06Jean Chalard        mInterfaceState = dictionaryListInterfaceState;
750cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        mClientId = clientId;
760cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        mVersion = version;
770cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        mWordlistId = wordlistId;
78ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard        mFilesize = filesize;
79a2ec5e8338c82f1e49c3d98f502dcc30c9c12fb0Jean Chalard        mLocale = locale;
80a2ec5e8338c82f1e49c3d98f502dcc30c9c12fb0Jean Chalard        mDescription = description;
810cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
820cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        setLayoutResource(R.layout.dictionary_line);
830cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
840cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        setTitle(description);
850cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        setStatus(status);
860cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        setKey(wordlistId);
870cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
880cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
8926f489493eb3a1ccb9cb0ab55627bee4c74a6fd2Jean Chalard    public void setStatus(final int status) {
900cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        if (status == mStatus) return;
910cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        mStatus = status;
920cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        setSummary(getSummary(status));
930cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
940cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
95a7e3e74ddd714b7e22d5e5feb7e136dcb5dc1edaJean Chalard    public boolean hasStatus(final int status) {
96a7e3e74ddd714b7e22d5e5feb7e136dcb5dc1edaJean Chalard        return status == mStatus;
97a7e3e74ddd714b7e22d5e5feb7e136dcb5dc1edaJean Chalard    }
98a7e3e74ddd714b7e22d5e5feb7e136dcb5dc1edaJean Chalard
992b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard    @Override
1002b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard    public View onCreateView(final ViewGroup parent) {
1012b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard        final View orphanedView = mInterfaceState.findFirstOrphanedView();
1022b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard        if (null != orphanedView) return orphanedView; // Will be sent to onBindView
1032b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard        final View newView = super.onCreateView(parent);
1042b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard        return mInterfaceState.addToCacheAndReturnView(newView);
1052b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard    }
1062b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard
10726f489493eb3a1ccb9cb0ab55627bee4c74a6fd2Jean Chalard    public boolean hasPriorityOver(final int otherPrefStatus) {
10826f489493eb3a1ccb9cb0ab55627bee4c74a6fd2Jean Chalard        // Both of these should be one of MetadataDbHelper.STATUS_*
10926f489493eb3a1ccb9cb0ab55627bee4c74a6fd2Jean Chalard        return mStatus > otherPrefStatus;
11026f489493eb3a1ccb9cb0ab55627bee4c74a6fd2Jean Chalard    }
11126f489493eb3a1ccb9cb0ab55627bee4c74a6fd2Jean Chalard
1120cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    private String getSummary(final int status) {
1135f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final Context context = getContext();
1140cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        switch (status) {
1155f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // If we are deleting the word list, for the user it's like it's already deleted.
1165f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // It should be reinstallable. Exposing to the user the whole complexity of
1175f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // the delayed deletion process between the dictionary pack and Android Keyboard
1185f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // would only be confusing.
1195f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case MetadataDbHelper.STATUS_DELETING:
1205f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case MetadataDbHelper.STATUS_AVAILABLE:
1215f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            return context.getString(R.string.dictionary_available);
1225f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case MetadataDbHelper.STATUS_DOWNLOADING:
1235f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            return context.getString(R.string.dictionary_downloading);
1245f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case MetadataDbHelper.STATUS_INSTALLED:
1255f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            return context.getString(R.string.dictionary_installed);
1265f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case MetadataDbHelper.STATUS_DISABLED:
1275f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            return context.getString(R.string.dictionary_disabled);
1285f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        default:
1295f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            return NO_STATUS_MESSAGE;
1300cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        }
1310cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
1320cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
1332d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard    // The table below needs to be kept in sync with MetadataDbHelper.STATUS_* since it uses
1342d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard    // the values as indices.
1350cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    private static final int sStatusActionList[][] = {
1360cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // MetadataDbHelper.STATUS_UNKNOWN
1370cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        {},
1380cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // MetadataDbHelper.STATUS_AVAILABLE
1392d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard        { ButtonSwitcher.STATUS_INSTALL, ACTION_ENABLE_DICT },
1400cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // MetadataDbHelper.STATUS_DOWNLOADING
1412d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard        { ButtonSwitcher.STATUS_CANCEL, ACTION_DISABLE_DICT },
1420cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // MetadataDbHelper.STATUS_INSTALLED
1432d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard        { ButtonSwitcher.STATUS_DELETE, ACTION_DELETE_DICT },
1440cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // MetadataDbHelper.STATUS_DISABLED
1452d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard        { ButtonSwitcher.STATUS_DELETE, ACTION_DELETE_DICT },
1460cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // MetadataDbHelper.STATUS_DELETING
1470cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // We show 'install' because the file is supposed to be deleted.
1480cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // The user may reinstall it.
1492d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard        { ButtonSwitcher.STATUS_INSTALL, ACTION_ENABLE_DICT }
1500cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    };
1510cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
1525f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    static int getButtonSwitcherStatus(final int status) {
1530cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        if (status >= sStatusActionList.length) {
1540cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            Log.e(TAG, "Unknown status " + status);
1552d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard            return ButtonSwitcher.STATUS_NO_BUTTON;
1560cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        }
1572d72590ced449e1ba0065bf63c311dae805c8290Jean Chalard        return sStatusActionList[status][0];
1580cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
1590cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
1605f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    static int getActionIdFromStatusAndMenuEntry(final int status) {
1610cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        if (status >= sStatusActionList.length) {
1620cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            Log.e(TAG, "Unknown status " + status);
1630cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            return ACTION_UNKNOWN;
1640cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        }
1650cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        return sStatusActionList[status][1];
1660cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
1670cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
1680cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    private void disableDict() {
1695f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final Context context = getContext();
1705f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final SharedPreferences prefs = CommonPreferences.getCommonPreferences(context);
1710cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        CommonPreferences.disable(prefs, mWordlistId);
1725f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        UpdateHandler.markAsUnused(context, mClientId, mWordlistId, mVersion, mStatus);
1730cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        if (MetadataDbHelper.STATUS_DOWNLOADING == mStatus) {
1740cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            setStatus(MetadataDbHelper.STATUS_AVAILABLE);
1750cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        } else if (MetadataDbHelper.STATUS_INSTALLED == mStatus) {
1760cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            // Interface-wise, we should no longer be able to come here. However, this is still
1770cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            // the right thing to do if we do come here.
1780cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            setStatus(MetadataDbHelper.STATUS_DISABLED);
1790cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        } else {
1800cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            Log.e(TAG, "Unexpected state of the word list for disabling " + mStatus);
1810cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        }
1820cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
1835f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka
1840cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    private void enableDict() {
1855f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final Context context = getContext();
1865f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final SharedPreferences prefs = CommonPreferences.getCommonPreferences(context);
1870cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        CommonPreferences.enable(prefs, mWordlistId);
1880cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        // Explicit enabling by the user : allow downloading on metered data connection.
1895f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        UpdateHandler.markAsUsed(context, mClientId, mWordlistId, mVersion, mStatus, true);
1900cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        if (MetadataDbHelper.STATUS_AVAILABLE == mStatus) {
1910cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            setStatus(MetadataDbHelper.STATUS_DOWNLOADING);
1920cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        } else if (MetadataDbHelper.STATUS_DISABLED == mStatus
1930cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard                || MetadataDbHelper.STATUS_DELETING == mStatus) {
1940cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            // If the status is DELETING, it means Android Keyboard
1950cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            // has not deleted the word list yet, so we can safely
1960cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            // turn it to 'installed'. The status DISABLED is still supported internally to
1970cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            // avoid breaking older installations and all but there should not be a way to
1980cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            // disable a word list through the interface any more.
1990cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            setStatus(MetadataDbHelper.STATUS_INSTALLED);
2000cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        } else {
2010cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard            Log.e(TAG, "Unexpected state of the word list for enabling " + mStatus);
2020cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        }
2030cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
2045f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka
2050cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    private void deleteDict() {
2065f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final Context context = getContext();
2075f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final SharedPreferences prefs = CommonPreferences.getCommonPreferences(context);
2080cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        CommonPreferences.disable(prefs, mWordlistId);
2090cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        setStatus(MetadataDbHelper.STATUS_DELETING);
2105f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        UpdateHandler.markAsDeleting(context, mClientId, mWordlistId, mVersion, mStatus);
2110cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
2120cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
2130cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    @Override
2140cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    protected void onBindView(final View view) {
2150cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        super.onBindView(view);
2160cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        ((ViewGroup)view).setLayoutTransition(null);
217ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard
218d282ebfb71ff5bdb855508b7b546dba786d7d85aJean Chalard        final DictionaryDownloadProgressBar progressBar =
219d282ebfb71ff5bdb855508b7b546dba786d7d85aJean Chalard                (DictionaryDownloadProgressBar)view.findViewById(R.id.dictionary_line_progress_bar);
220ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard        final TextView status = (TextView)view.findViewById(android.R.id.summary);
221d282ebfb71ff5bdb855508b7b546dba786d7d85aJean Chalard        progressBar.setIds(mClientId, mWordlistId);
222ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard        progressBar.setMax(mFilesize);
223ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard        final boolean showProgressBar = (MetadataDbHelper.STATUS_DOWNLOADING == mStatus);
224a7e3e74ddd714b7e22d5e5feb7e136dcb5dc1edaJean Chalard        setSummary(getSummary(mStatus));
225ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard        status.setVisibility(showProgressBar ? View.INVISIBLE : View.VISIBLE);
226ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard        progressBar.setVisibility(showProgressBar ? View.VISIBLE : View.INVISIBLE);
227ab0c66b9d1f732a0dc372abd6d113d2cac33b8acJean Chalard
2285f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final ButtonSwitcher buttonSwitcher = (ButtonSwitcher)view.findViewById(
2295f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                R.id.wordlist_button_switcher);
2302b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard        // We need to clear the state of the button switcher, because we reuse views; if we didn't
2312b34b4eab6b04299205f47a92311d4d00f9d805fJean Chalard        // reset it would animate from whatever its old state was.
2326912342a48b9ebf6f4dcd714b697eadac48afbdeJean Chalard        buttonSwitcher.reset(mInterfaceState);
233513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard        if (mInterfaceState.isOpen(mWordlistId)) {
234513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard            // The button is open.
235513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard            final int previousStatus = mInterfaceState.getStatus(mWordlistId);
236513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard            buttonSwitcher.setStatusAndUpdateVisuals(getButtonSwitcherStatus(previousStatus));
237513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard            if (previousStatus != mStatus) {
238513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard                // We come here if the status has changed since last time. We need to animate
239513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard                // the transition.
240513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard                buttonSwitcher.setStatusAndUpdateVisuals(getButtonSwitcherStatus(mStatus));
241513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard                mInterfaceState.setOpen(mWordlistId, mStatus);
242513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard            }
243513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard        } else {
244513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard            // The button is closed.
245513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard            buttonSwitcher.setStatusAndUpdateVisuals(ButtonSwitcher.STATUS_NO_BUTTON);
246513c63e877320bca4860dadc88e3a14ffb861e36Jean Chalard        }
2475f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        buttonSwitcher.setInternalOnClickListener(new View.OnClickListener() {
2485f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            @Override
2495f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            public void onClick(final View v) {
2505f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                onActionButtonClicked();
2515f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            }
2525f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        });
2535f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        view.setOnClickListener(new View.OnClickListener() {
2545f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            @Override
2555f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            public void onClick(final View v) {
2565f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                onWordListClicked(v);
2575f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            }
2585f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        });
2590cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
2600cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard
2615f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void onWordListClicked(final View v) {
2625f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // Note : v is the preference view
2635f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final ViewParent parent = v.getParent();
2645f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // Just in case something changed in the framework, test for the concrete class
2655f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        if (!(parent instanceof ListView)) return;
2665f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final ListView listView = (ListView)parent;
2675f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final int indexToOpen;
2685f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // Close all first, we'll open back any item that needs to be open.
2695f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final boolean wasOpen = mInterfaceState.isOpen(mWordlistId);
2705f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        mInterfaceState.closeAll();
2715f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        if (wasOpen) {
2725f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            // This button being shown. Take note that we don't want to open any button in the
2735f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            // loop below.
2745f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            indexToOpen = -1;
2755f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        } else {
2765f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            // This button was not being shown. Open it, and remember the index of this
2775f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            // child as the one to open in the following loop.
2785f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            mInterfaceState.setOpen(mWordlistId, mStatus);
2795f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            indexToOpen = listView.indexOfChild(v);
2805f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        }
2815f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final int lastDisplayedIndex =
2825f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                listView.getLastVisiblePosition() - listView.getFirstVisiblePosition();
2835f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        // The "lastDisplayedIndex" is actually displayed, hence the <=
2845f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        for (int i = 0; i <= lastDisplayedIndex; ++i) {
2855f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            final ButtonSwitcher buttonSwitcher = (ButtonSwitcher)listView.getChildAt(i)
2865f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                    .findViewById(R.id.wordlist_button_switcher);
2875f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            if (i == indexToOpen) {
2885f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                buttonSwitcher.setStatusAndUpdateVisuals(getButtonSwitcherStatus(mStatus));
289d98f406dd31c9f72ba3273b10b521a1a77136ac3Jean Chalard            } else {
2905f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                buttonSwitcher.setStatusAndUpdateVisuals(ButtonSwitcher.STATUS_NO_BUTTON);
291d98f406dd31c9f72ba3273b10b521a1a77136ac3Jean Chalard            }
292f8014eea341040f8d155e071e4e0c915a7ebd61dJean Chalard        }
293f8014eea341040f8d155e071e4e0c915a7ebd61dJean Chalard    }
294f8014eea341040f8d155e071e4e0c915a7ebd61dJean Chalard
2955f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void onActionButtonClicked() {
2965f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        switch (getActionIdFromStatusAndMenuEntry(mStatus)) {
2975f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case ACTION_ENABLE_DICT:
2985f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            enableDict();
2995f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            break;
3005f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case ACTION_DISABLE_DICT:
3015f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            disableDict();
3025f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            break;
3035f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        case ACTION_DELETE_DICT:
3045f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            deleteDict();
3055f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            break;
3065f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        default:
3075f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            Log.e(TAG, "Unknown menu item pressed");
3080cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard        }
3090cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard    }
3100cc0544a2995c7eb54a830ae54db60af89d4073dJean Chalard}
311