Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 907cea05 authored by Danny Baumann's avatar Danny Baumann Committed by Danesh M
Browse files

Clean up search code.

Fix up coding style and add a few missing TypedArray.recycle() calls.
Also make filtering code more efficient.

Change-Id: Ie3824b41ae40010686ff3cb6cab7f12d19843834
parent 335ac123
Loading
Loading
Loading
Loading
+40 −18
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The CyanogenMod Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textAutoComplete"
    android:layout_height="?android:attr/listPreferredItemHeightSmall"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:layout_width="fill_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/autocomplete_image"
        android:layout_width="wrap_content"
@@ -11,19 +28,24 @@
        android:padding="5dp"
        android:gravity="center_vertical"
        android:src="@mipmap/ic_launcher_settings"/>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
            android:layout_width="match_parent"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:orientation="vertical">

        <TextView
            android:id="@+id/autocomplete_title"
            android:layout_width="match_parent"
                android:layout_height="match_parent"
            android:layout_height="wrap_content"
            android:lines="2"
            android:scrollHorizontally="true"
            android:ellipsize="end"
                android:textColor="#FFFFFF"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:gravity="center_vertical"/>

    </LinearLayout>

</LinearLayout>
+21 −7
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The CyanogenMod Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
+16 −17
Original line number Diff line number Diff line
@@ -52,7 +52,6 @@ import android.os.UserManager;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.support.v4.view.MenuItemCompat;
import android.text.TextUtils;
import android.telephony.MSimTelephonyManager;
import android.util.Log;
@@ -160,7 +159,6 @@ public class Settings extends PreferenceActivity

    private static final String VOICE_WAKEUP_PACKAGE_NAME = "com.cyanogenmod.voicewakeup";
    private static final String GESTURE_SETTINGS_PACKAGE_NAME = "com.cyanogenmod.settings";
    public static final String NOTIFIER_EXTRA = "notifier";

    static final int DIALOG_ONLY_ONE_HOME = 1;

@@ -248,9 +246,8 @@ public class Settings extends PreferenceActivity
        final InputMethodManager imm =
                (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

        mSearchBar = (SettingsAutoCompleteTextView) MenuItemCompat.getActionView(mSearchItem);

        MenuItemCompat.setOnActionExpandListener(mSearchItem, new MenuItemCompat.OnActionExpandListener() {
        mSearchBar = (SettingsAutoCompleteTextView) mSearchItem.getActionView();
        mSearchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) {
                mSearchBar.clearFocus();
@@ -283,8 +280,7 @@ public class Settings extends PreferenceActivity
            AsyncTask<Void, Void, ArrayList<SearchInfo>> {
        @Override
        protected ArrayList<SearchInfo> doInBackground(Void... param) {
            final ArrayList<SearchInfo> infos = SearchPopulator.getTitles(Settings.this);
            return infos;
            return SearchPopulator.loadSearchData(Settings.this);
        }

        @Override
@@ -312,9 +308,8 @@ public class Settings extends PreferenceActivity
            getWindow().setUiOptions(getIntent().getIntExtra(EXTRA_UI_OPTIONS, 0));
        }

        Intent i = new Intent(this, SearchPopulator.class);
        i.putExtra(NOTIFIER_EXTRA, new SearchNotifier(new Handler()));
        startService(i);
        startPopulatingSearchData();

        mActionBar = getActionBar();
        mActionBar.setDisplayShowCustomEnabled(true);

@@ -401,12 +396,10 @@ public class Settings extends PreferenceActivity

    @Override
    public void onBackPressed() {
        if (mSearchBar != null) {
            if (mSearchBar.hasFocus()) {
        if (mSearchBar != null && mSearchBar.hasFocus()) {
            mSearchBar.clearFocus();
            return;
        }
        }
        super.onBackPressed();
    }

@@ -434,6 +427,7 @@ public class Settings extends PreferenceActivity
        mDevelopmentPreferencesListener = null;
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mSearchBar.clearFocus();
@@ -590,6 +584,12 @@ public class Settings extends PreferenceActivity
        }
    }

    private void startPopulatingSearchData() {
        Intent i = new Intent(this, SearchPopulator.class);
        i.putExtra(SearchPopulator.EXTRA_NOTIFIER, new SearchNotifier(new Handler()));
        startService(i);
    }

    @Override
    public Intent getIntent() {
        Intent superIntent = super.getIntent();
@@ -967,8 +967,7 @@ public class Settings extends PreferenceActivity
    }

    @Override
    public void onItemClick(AdapterView<?> parent,
                            View view, int position, long l) {
    public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
        SearchInfo info = (SearchInfo) parent.getItemAtPosition(position);
        mSearchBar.setText("");
        mSearchBar.clearFocus();
+157 −138
Original line number Diff line number Diff line
@@ -16,20 +16,6 @@

package com.android.settings.search;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.search.SettingsSearchFilterAdapter.SearchInfo;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.app.IntentService;
import android.content.ContentValues;
import android.content.Context;
@@ -53,24 +39,40 @@ import android.util.TypedValue;
import android.util.Xml;

import com.android.internal.util.XmlUtils;
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.search.SettingsSearchFilterAdapter.SearchInfo;

public class SearchPopulator extends IntentService {
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class SearchPopulator extends IntentService {
    private static final String TAG = SearchPopulator.class.getSimpleName();

    public static final String EXTRA_NOTIFIER = "notifier";

    private static final String LAST_PACKAGE_HASH = "last_package_hash";
    private ResultReceiver mNotifier;

    public SearchPopulator() {
        super(SearchPopulator.class.getSimpleName());
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        mNotifier = intent.getParcelableExtra(Settings.NOTIFIER_EXTRA);
        mNotifier = intent.getParcelableExtra(EXTRA_NOTIFIER);

        SharedPreferences sharedPreferences = getSharedPreferences(
                getPackageName(), Context.MODE_PRIVATE);
        int lastHash = sharedPreferences.getInt(LAST_PACKAGE_HASH, -1);
        int currentHash = getPackageHashCode();
        int currentHash = getPackageHashCode(getBasePackageName());

        if (lastHash != currentHash) {
            populateDatabase();
@@ -89,10 +91,10 @@ public class SearchPopulator extends IntentService {
            AttributeSet attrs = Xml.asAttributeSet(parser);

            int type;
            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && type != XmlPullParser.START_TAG) {
            do {
                type = parser.next();
                // Parse next until start tag is found
            }
            } while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG);

            String nodeName = parser.getName();
            if (!"preference-headers".equals(nodeName)) {
@@ -101,8 +103,6 @@ public class SearchPopulator extends IntentService {
                        + nodeName + " at " + parser.getPositionDescription());
            }

            Bundle curBundle = null;

            final int outerDepth = parser.getDepth();
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -112,17 +112,55 @@ public class SearchPopulator extends IntentService {

                nodeName = parser.getName();
                if ("header".equals(nodeName)) {
                    // Fetch xml the fragment inflates
                    TypedArray se = getResources().obtainAttributes(attrs,
                            com.android.settings.R.styleable.SearchableInfo);
                    int xmlResId = se.getResourceId(
                            com.android.settings.R.styleable.SearchableInfo_includeXmlForSearch, 0);
                    boolean excludeFromSearch = se.getBoolean(
                            com.android.settings.R.styleable.SearchableInfo_excludeFromSearch,
                            false);

                    se.recycle();

                    if (excludeFromSearch) {
                        continue;
                    }

                    Header header = parseHeader(parser, attrs);
                    if (TextUtils.isEmpty(header.fragment)) {
                        continue;
                    }

                    dbHelper.insertHeader(header);
                    if (xmlResId != 0) {
                        populateFromXml(xmlResId, header, 1, header.iconRes,
                                header.fragment, header.titleRes);
                    }
                } else {
                    XmlUtils.skipCurrentTag(parser);
                }
            }
        } catch (XmlPullParserException e) {
            throw new RuntimeException("Error parsing headers", e);
        } catch (IOException e) {
            throw new RuntimeException("Error parsing headers", e);
        } finally {
            if (parser != null) parser.close();
        }
    }

    private Header parseHeader(XmlResourceParser parser, AttributeSet attrs)
            throws XmlPullParserException, IOException {
        Header header = new Header();

        TypedArray sa = getResources().obtainAttributes(attrs,
                com.android.internal.R.styleable.PreferenceHeader);
                    header.id = sa.getResourceId(
                            com.android.internal.R.styleable.PreferenceHeader_id,
        header.id = sa.getResourceId(com.android.internal.R.styleable.PreferenceHeader_id,
                (int) PreferenceActivity.HEADER_ID_UNDEFINED);

        // Fetch title
                    TypedValue tv = sa.peekValue(
                            com.android.internal.R.styleable.PreferenceHeader_title);
        TypedValue tv = sa.peekValue(com.android.internal.R.styleable.PreferenceHeader_title);
        if (tv != null && tv.type == TypedValue.TYPE_STRING) {
            if (tv.resourceId != 0) {
                header.titleRes = tv.resourceId;
@@ -132,8 +170,7 @@ public class SearchPopulator extends IntentService {
        }

        // Fetch breadcrumb title
                    tv = sa.peekValue(
                            com.android.internal.R.styleable.PreferenceHeader_breadCrumbTitle);
        tv = sa.peekValue(com.android.internal.R.styleable.PreferenceHeader_breadCrumbTitle);
        if (tv != null && tv.type == TypedValue.TYPE_STRING) {
            if (tv.resourceId != 0) {
                header.breadCrumbTitleRes = tv.resourceId;
@@ -143,8 +180,7 @@ public class SearchPopulator extends IntentService {
        }

        // Fetch breadcrumb short title
                    tv = sa.peekValue(
                            com.android.internal.R.styleable.PreferenceHeader_breadCrumbShortTitle);
        tv = sa.peekValue(com.android.internal.R.styleable.PreferenceHeader_breadCrumbShortTitle);
        if (tv != null && tv.type == TypedValue.TYPE_STRING) {
            if (tv.resourceId != 0) {
                header.breadCrumbShortTitleRes = tv.resourceId;
@@ -161,26 +197,14 @@ public class SearchPopulator extends IntentService {
        }

        // Fetch fragment
                    header.fragment = sa.getString(
                            com.android.internal.R.styleable.PreferenceHeader_fragment);
                    sa.recycle();

                    if (curBundle == null) {
                        curBundle = new Bundle();
                    }

                    // Fetch xml the fragment inflates
                    TypedArray se = getResources().obtainAttributes(attrs,
                            com.android.settings.R.styleable.SearchableInfo);
                    int xmlResId = se.getResourceId(
                            com.android.settings.R.styleable.SearchableInfo_includeXmlForSearch, 0);
        header.fragment = sa.getString(com.android.internal.R.styleable.PreferenceHeader_fragment);

                    boolean excludeFromSearch = se.getBoolean(com.android.settings.R.styleable.SearchableInfo_excludeFromSearch, false);
                    if (excludeFromSearch) {
                        continue;
                    }
        sa.recycle();

        Bundle args = new Bundle();
        final int innerDepth = parser.getDepth();
        int type;

        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -189,45 +213,25 @@ public class SearchPopulator extends IntentService {

            String innerNodeName = parser.getName();
            if (innerNodeName.equals("extra")) {
                            getResources().parseBundleExtra("extra", attrs, curBundle);
                getResources().parseBundleExtra("extra", attrs, args);
                XmlUtils.skipCurrentTag(parser);

            } else if (innerNodeName.equals("intent")) {
                header.intent = Intent.parseIntent(getResources(), parser, attrs);

            } else {
                XmlUtils.skipCurrentTag(parser);
            }
        }

                    if (curBundle.size() > 0) {
                        header.fragmentArguments = curBundle;
                        curBundle = null;
        if (args.size() > 0) {
            header.fragmentArguments = args;
        }

                    if (TextUtils.isEmpty(header.fragment)) {
                        continue;
                    }

                    dbHelper.insertHeader(header);
                    if (xmlResId != 0) {
                        populateFromXml(xmlResId, header, 1, header.iconRes, header.fragment, header.titleRes);
                    }
                } else {
                    XmlUtils.skipCurrentTag(parser);
                }
            }
        } catch (XmlPullParserException e) {
            throw new RuntimeException("Error parsing headers", e);
        } catch (IOException e) {
            throw new RuntimeException("Error parsing headers", e);
        } finally {
            if (parser != null) parser.close();
        }
        return header;
    }

    private void populateFromXml(int xmlResId, Header header,
                                 int level, int iconRes, String prefFragment, int titleRes) {
            int level, int iconRes, String prefFragment, int titleRes)
            throws XmlPullParserException {
        SettingsSearchDatabaseHelper dbHelper = SettingsSearchDatabaseHelper.getInstance(this);
        AttributeSet attributeSet;
        int type;
@@ -235,10 +239,10 @@ public class SearchPopulator extends IntentService {

        try {
            xmlParser = getResources().getXml(xmlResId);
            while ((type=xmlParser.next()) != XmlPullParser.END_DOCUMENT
                    && type != XmlPullParser.START_TAG) {
            do {
                type = xmlParser.next();
                // Parse next until start tag is found
            }
            } while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG);

            String tagName = xmlParser.getName();
            if (!"PreferenceScreen".equals(tagName)) {
@@ -276,43 +280,58 @@ public class SearchPopulator extends IntentService {
                    if (title.resourceId != 0) {
                        preferenceTitle = getResources().getString(title.resourceId);
                    } else {
                        preferenceTitle = (String) title.string;
                        preferenceTitle = title.string.toString();
                    }
                }

                boolean excludeFromSearch = se.getBoolean(com.android.settings.R.styleable.SearchableInfo_excludeFromSearch, false);
                boolean excludeFromSearch = se.getBoolean(
                        com.android.settings.R.styleable.SearchableInfo_excludeFromSearch, false);
                if (excludeFromSearch) {
                    continue;
                }

                String fragment = sa.getString(com.android.internal.R.styleable.Preference_fragment);
                int subXmlId = se.getResourceId(
                        com.android.settings.R.styleable.SearchableInfo_includeXmlForSearch, 0);

                if (subXmlId != 0 && !TextUtils.isEmpty(fragment)) {
                    populateFromXml(subXmlId, null, level + 1, header.iconRes, fragment, title.resourceId);
                    dbHelper.insertEntry(preferenceTitle, level, fragment, header.iconRes, getString(titleRes));
                    populateFromXml(subXmlId, null, level + 1, header.iconRes,
                            fragment, title.resourceId);
                    dbHelper.insertEntry(preferenceTitle, level, fragment,
                            header.iconRes, getString(titleRes));
                } else if (header != null) {
                    header.title = preferenceTitle;
                    header.titleRes = 0;
                    dbHelper.insertHeader(header);
                } else {
                    dbHelper.insertEntry(preferenceTitle, level, prefFragment, iconRes, getString(titleRes));
                    dbHelper.insertEntry(preferenceTitle, level, prefFragment,
                            iconRes, getString(titleRes));
                }

                sa.recycle();
                se.recycle();
            }
        } catch(IOException v38) {
            v38.printStackTrace();
        } catch(Throwable v3) {
            v3.printStackTrace();
        } catch (IOException e) {
            // ignored
        }
    }

    public static ArrayList<SearchInfo> getTitles(Context ctx) {
        SettingsSearchDatabaseHelper dbHelper = SettingsSearchDatabaseHelper.getInstance(ctx);
    public static ArrayList<SearchInfo> loadSearchData(Context context) {
        SettingsSearchDatabaseHelper dbHelper = SettingsSearchDatabaseHelper.getInstance(context);
        SQLiteDatabase database = dbHelper.getReadableDatabase();
        Cursor c = database.query(DatabaseContract.TABLE_NAME, null, null, null, null, null, null);
        ArrayList<SearchInfo> infos = new ArrayList<SearchInfo>();

        if (c != null) {
            int levelIndex = c.getColumnIndex(DatabaseContract.Settings.ACTION_LEVEL);
            int fragmentIndex = c.getColumnIndex(DatabaseContract.Settings.ACTION_FRAGMENT);
            int titleIndex = c.getColumnIndex(DatabaseContract.Settings.ACTION_TITLE);
            int iconIndex = c.getColumnIndex(DatabaseContract.Settings.ACTION_ICON);
            int parentIndex = c.getColumnIndex(DatabaseContract.Settings.ACTION_PARENT_TITLE);
            int headerIndex = c.getColumnIndex(DatabaseContract.Settings.ACTION_HEADER);

            while (c.moveToNext()) {
                byte[] data = c.getBlob(c.getColumnIndex(DatabaseContract.Settings.ACTION_HEADER));
                byte[] data = c.getBlob(headerIndex);
                SearchInfo info = new SearchInfo();
                if (data != null) {
                    Parcel p = Parcel.obtain();
@@ -323,29 +342,29 @@ public class SearchPopulator extends IntentService {
                    h.readFromParcel(p);
                    info.header = h;
                }
                info.level = c.getInt(c.getColumnIndex(DatabaseContract.Settings.ACTION_LEVEL));
                info.fragment = c.getString(c.getColumnIndex(DatabaseContract.Settings.ACTION_FRAGMENT));
                info.title = c.getString(c.getColumnIndex(DatabaseContract.Settings.ACTION_TITLE));
                info.iconRes = c.getInt(c.getColumnIndex(DatabaseContract.Settings.ACTION_ICON));
                info.parentTitle = c.getString(c.getColumnIndex(DatabaseContract.Settings.ACTION_PARENT_TITLE));
                info.level = c.getInt(levelIndex);
                info.fragment = c.getString(fragmentIndex);
                info.title = c.getString(titleIndex);
                info.iconRes = c.getInt(iconIndex);
                info.parentTitle = c.getString(parentIndex);
                infos.add(info);
            }
            c.close();
        }

        return infos;
    }

    /**
     * Get a 32 bit hashcode for the given package.
     * @param pkg
     * @param packageName
     * @return
     */
    private int getPackageHashCode() {
    private int getPackageHashCode(String packageName) {
        PackageInfo pInfo;
        try {
            pInfo = getPackageManager().getPackageInfo(getBasePackageName(), 0);
            pInfo = getPackageManager().getPackageInfo(packageName, 0);
        } catch (NameNotFoundException e) {
            e.printStackTrace();
            return 0;
        }

@@ -368,7 +387,7 @@ public class SearchPopulator extends IntentService {
            long crc = entry.getCrc();
            if (crc == -1) Log.e(TAG, "Unable to get CRC for " + path);
            return ByteBuffer.allocate(8).putLong(crc).array();
        } catch (Exception e) {
        } catch (IOException e) {
        } finally {
            if (zfile != null) {
                try {
+6 −10
Original line number Diff line number Diff line
@@ -46,11 +46,9 @@ public class SettingsAutoCompleteTextView extends AutoCompleteTextView
    }

    private void create() {
        mClearButton = getResources().getDrawable(
                R.drawable.ic_action_content_remove);
        mClearButton = getResources().getDrawable(R.drawable.ic_action_content_remove);

        this.setCompoundDrawablesWithIntrinsicBounds(null, null,
                mClearButton, null);
        setCompoundDrawablesWithIntrinsicBounds(null, null, mClearButton, null);

        // set touch listener
        setOnTouchListener(this);
@@ -58,16 +56,14 @@ public class SettingsAutoCompleteTextView extends AutoCompleteTextView

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        SettingsAutoCompleteTextView settingsAutoCompleteTextView = SettingsAutoCompleteTextView.this;

        if (motionEvent.getAction() != MotionEvent.ACTION_UP)
            return false;

        if (motionEvent.getX() > settingsAutoCompleteTextView.getWidth()
                - settingsAutoCompleteTextView.getPaddingRight()
                - mClearButton.getIntrinsicWidth()) {
        int clearButtonStart = getWidth() - getPaddingRight()
                - mClearButton.getIntrinsicWidth();
        if (motionEvent.getX() > clearButtonStart) {
            // clear text
            settingsAutoCompleteTextView.setText("");
            setText("");
        }
        return false;
    }
Loading