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

Commit 25d4bbea authored by Danny Baumann's avatar Danny Baumann Committed by LuK1337
Browse files

LineageParts: Convert profile trigger list fragment to RecyclerView

Change-Id: I15a0287b8508a65570c6e83e20569d62c12099e5
parent ec3482c3
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    <ViewStub
            android:id="@android:id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

</FrameLayout>
+16 −2
Original line number Diff line number Diff line
@@ -195,13 +195,27 @@
    <string-array name="profile_trigger_wifi_options" translatable="false">
        <item>@string/profile_trigger_connect</item>
        <item>@string/profile_trigger_disconnect</item>
        <item>@string/profile_trigger_a2dp_connect</item>
        <item>@string/profile_trigger_a2dp_disconnect</item>
        <item>@string/profile_trigger_notrigger</item>
    </string-array>

    <!--  Values for profile Wi-Fi triggers.  Do not translate. -->
    <string-array name="profile_trigger_wifi_options_values" translatable="false">
        <item>0</item>
        <item>1</item>
        <item>2</item>
    </string-array>

    <!--  Values for profile BT triggers -->
    <string-array name="profile_trigger_bt_options" translatable="false">
        <item>@string/profile_trigger_connect</item>
        <item>@string/profile_trigger_disconnect</item>
        <item>@string/profile_trigger_a2dp_connect</item>
        <item>@string/profile_trigger_a2dp_disconnect</item>
        <item>@string/profile_trigger_notrigger</item>
    </string-array>

    <!--  Values for profile BT triggers.  Do not translate. -->
    <string-array name="profile_trigger_bt_options_values" translatable="false">
        <item>0</item>
        <item>1</item>
        <item>3</item>
+247 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The LineageOS 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.
 */
package org.lineageos.lineageparts.profiles.triggers;

import android.app.AlertDialog;
import android.app.Fragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.TextView;

import lineageos.app.Profile;
import lineageos.app.ProfileManager;

import org.lineageos.lineageparts.R;
import org.lineageos.lineageparts.profiles.ProfilesSettings;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractTriggerListFragment extends Fragment {
    private ProfileManager mProfileManager;
    private Profile mProfile;

    private List<AbstractTriggerItem> mTriggers = new ArrayList<>();

    private View mEmptyView;
    private RecyclerView mRecyclerView;
    private TriggerAdapter mAdapter;

    private TriggerAdapter.ItemClickListener mItemClickListener = item -> {
        final Resources res = getResources();
        final String[] possibleEntries = res.getStringArray(getOptionArrayResId());
        final String[] possibleValues = res.getStringArray(getOptionValuesArrayResId());
        final ArrayList<Trigger> triggers = new ArrayList<>();
        final TriggerInfo info = onConvertToTriggerInfo(item);

        for (int i = 0; i < possibleEntries.length; i++) {
            Trigger toAdd = new Trigger();
            toAdd.value = Integer.parseInt(possibleValues[i]);
            toAdd.name = possibleEntries[i];
            if (isTriggerStateSupported(info, toAdd.value)) {
                triggers.add(toAdd);
            }
        }

        final String[] entries = new String[triggers.size()];
        final int[] valueInts = new int[triggers.size()];
        int currentTriggerState = mProfile.getTriggerState(info.type, info.id);
        int currentItem = -1;
        for (int i = 0; i < triggers.size(); i++) {
            Trigger t = triggers.get(i);
            entries[i] = t.name;
            valueInts[i] = t.value;
            if (valueInts[i] == currentTriggerState) {
                currentItem = i;
            }
        }

        new AlertDialog.Builder(getActivity())
                .setTitle(R.string.profile_trigger_configure)
                .setSingleChoiceItems(entries, currentItem, (dialog, which) -> {
                    mProfile.setTrigger(info.type, info.id, valueInts[which], info.name);
                    mProfileManager.updateProfile(mProfile);
                    updateTriggerList();
                    dialog.dismiss();
                })
                .show();
    };

    protected static Bundle initArgs(Profile profile) {
        Bundle args = new Bundle();
        args.putParcelable(ProfilesSettings.EXTRA_PROFILE, profile);
        return args;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mProfileManager = ProfileManager.getInstance(getActivity());
        if (getArguments() != null) {
            mProfile = getArguments().getParcelable(ProfilesSettings.EXTRA_PROFILE);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
            ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.profile_trigger_list, container, false);

        ViewStub emptyViewStub = view.findViewById(android.R.id.empty);
        emptyViewStub.setLayoutResource(getEmptyViewLayoutResId());

        mEmptyView = emptyViewStub.inflate();
        mEmptyView.setOnClickListener(v -> startActivity(getEmptyViewClickIntent()));

        mRecyclerView = view.findViewById(android.R.id.list);

        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mAdapter = new TriggerAdapter(mTriggers, mItemClickListener);
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    }

    @Override
    public void onResume() {
        super.onResume();
        updateTriggerList();
    }

    protected abstract void onLoadTriggers(Profile profile, List<AbstractTriggerItem> triggers);
    protected abstract TriggerInfo onConvertToTriggerInfo(AbstractTriggerItem trigger);
    protected abstract boolean isTriggerStateSupported(TriggerInfo info, int triggerState);
    protected abstract int getEmptyViewLayoutResId();
    protected abstract Intent getEmptyViewClickIntent();
    protected abstract int getOptionArrayResId();
    protected abstract int getOptionValuesArrayResId();

    protected void initTriggerItemFromState(AbstractTriggerItem trigger, int state, int iconResId) {
        final String[] values = getResources().getStringArray(getOptionValuesArrayResId());
        for (int i = 0; i < values.length; i++) {
            if (Integer.parseInt(values[i]) == state) {
                trigger.setSummary(getResources().getStringArray(getOptionArrayResId())[i]);
                break;
            }
        }
        trigger.setTriggerState(state);
        trigger.setIcon(iconResId);
    }

    private void updateTriggerList() {
        mTriggers.clear();
        onLoadTriggers(mProfile, mTriggers);
        mAdapter.notifyDataSetChanged();

        mRecyclerView.setVisibility(mTriggers.isEmpty() ? View.GONE : View.VISIBLE);
        mEmptyView.setVisibility(mTriggers.isEmpty() ? View.VISIBLE : View.GONE);
    }

    private static class Trigger {
        int value;
        String name;
    }

    protected static class TriggerInfo {
        final String id;
        final String name;
        final int type;

        protected TriggerInfo(int type, String id, String name) {
            this.type = type;
            this.id = id;
            this.name = name;
        }
    }

    private static class TriggerViewHolder extends RecyclerView.ViewHolder {
        private TextView mTitleView;
        private TextView mDescView;
        private ImageView mIconView;

        public TriggerViewHolder(View view) {
            super(view);
            mTitleView = view.findViewById(R.id.title);
            mDescView = view.findViewById(R.id.desc);
            mIconView = view.findViewById(R.id.icon);
        }

        public void bind(AbstractTriggerItem trigger) {
            mTitleView.setText(trigger.getTitle());
            mDescView.setText(trigger.getSummary());
            mIconView.setImageResource(trigger.getIcon());
        }
    }

    private static class TriggerAdapter extends RecyclerView.Adapter<TriggerViewHolder>
            implements View.OnClickListener {
        interface ItemClickListener {
            void onItemClick(AbstractTriggerItem item);
        }

        private final List<AbstractTriggerItem> mTriggers;
        private final ItemClickListener mItemClickListener;

        public TriggerAdapter(List<AbstractTriggerItem> triggers,
                ItemClickListener itemClickListener) {
            super();
            mTriggers = triggers;
            mItemClickListener = itemClickListener;
        }

        @Override
        public int getItemCount() {
            return mTriggers.size();
        }

        @Override
        public TriggerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            TriggerViewHolder holder = new TriggerViewHolder(
                    inflater.inflate(R.layout.abstract_trigger_row, parent, false));
            holder.itemView.setOnClickListener(this);
            return holder;
        }

        @Override
        public void onBindViewHolder(TriggerViewHolder holder, int position) {
            holder.bind(mTriggers.get(position));
            holder.itemView.setTag(holder);
        }

        @Override
        public void onClick(View view) {
            TriggerViewHolder holder = (TriggerViewHolder) view.getTag();
            int position = holder.getAdapterPosition();
            if (position != RecyclerView.NO_POSITION) {
                mItemClickListener.onItemClick(mTriggers.get(position));
            }
        }
    }
}
+40 −189
Original line number Diff line number Diff line
@@ -16,243 +16,94 @@
 */
package org.lineageos.lineageparts.profiles.triggers;

import android.app.AlertDialog;
import android.app.ListFragment;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import lineageos.app.Profile;
import lineageos.app.ProfileManager;

import org.lineageos.lineageparts.R;
import org.lineageos.lineageparts.profiles.ProfilesSettings;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class BluetoothTriggerFragment extends ListFragment {

public class BluetoothTriggerFragment extends AbstractTriggerListFragment {
    private BluetoothAdapter mBluetoothAdapter;

    Profile mProfile;
    ProfileManager mProfileManager;

    private View mEmptyView;

    private List<BluetoothTrigger> mTriggers = new ArrayList<BluetoothTrigger>();
    private BluetoothTriggerAdapter mListAdapter;

    public static BluetoothTriggerFragment newInstance(Profile profile) {
        BluetoothTriggerFragment fragment = new BluetoothTriggerFragment();

        Bundle extras = new Bundle();
        extras.putParcelable(ProfilesSettings.EXTRA_PROFILE, profile);

        fragment.setArguments(extras);
        fragment.setArguments(initArgs(profile));
        return fragment;
    }

    public BluetoothTriggerFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mProfileManager = ProfileManager.getInstance(getActivity());
        if (getArguments() != null) {
            mProfile = getArguments().getParcelable(ProfilesSettings.EXTRA_PROFILE);
        }
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    @Override
    public void onResume() {
        super.onResume();
        reloadTriggerListItems();
    }
    protected void onLoadTriggers(Profile profile, List<AbstractTriggerItem> triggers) {
        final Resources res = getResources();
        final Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

    private void initPreference(AbstractTriggerItem pref, int state, Resources res, int icon) {
        String[] values = res.getStringArray(R.array.profile_trigger_wifi_options_values);
        for (int i = 0; i < values.length; i++) {
            if (Integer.parseInt(values[i]) == state) {
                pref.setSummary(res.getStringArray(R.array.profile_trigger_wifi_options)[i]);
                break;
            }
        if (!pairedDevices.isEmpty()) {
            for (BluetoothDevice device : pairedDevices) {
                BluetoothTrigger bt = new BluetoothTrigger(device);
                int state = profile.getTriggerState(
                        Profile.TriggerType.BLUETOOTH, bt.getAddress());
                initTriggerItemFromState(bt, state, R.drawable.ic_settings_bluetooth);
                triggers.add(bt);
            }
        pref.setTriggerState(state);
        pref.setIcon(icon);
        } else {
            final List<Profile.ProfileTrigger> origTriggers =
                    profile.getTriggersFromType(Profile.TriggerType.BLUETOOTH);
            for (Profile.ProfileTrigger trigger : origTriggers) {
                BluetoothTrigger bt = new BluetoothTrigger(trigger.getName(), trigger.getId());
                initTriggerItemFromState(bt, trigger.getState(), R.drawable.ic_settings_bluetooth);
                triggers.add(bt);
            }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        final String triggerId;
        final String triggerName;
        final int triggerType;

        String[] entries = getResources().getStringArray(R.array.profile_trigger_wifi_options);
        String[] values =
                getResources().getStringArray(R.array.profile_trigger_wifi_options_values);

        List<Trigger> triggers = new ArrayList<Trigger>(entries.length);
        for (int i = 0; i < entries.length; i++) {
            Trigger toAdd = new Trigger();
            toAdd.value = Integer.parseInt(values[i]);
            toAdd.name = entries[i];
            triggers.add(toAdd);
        }

        BluetoothTrigger btpref = mListAdapter.getItem(position);
        triggerName = btpref.getTitle();
        triggerId = btpref.getAddress();
        triggerType = Profile.TriggerType.BLUETOOTH;
        BluetoothDevice dev = mBluetoothAdapter.getRemoteDevice(triggerId);
        if (!dev.getBluetoothClass().doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
            removeTrigger(triggers, Profile.TriggerState.ON_A2DP_CONNECT);
            removeTrigger(triggers, Profile.TriggerState.ON_A2DP_DISCONNECT);
    }

        entries = new String[triggers.size()];
        final int[] valueInts = new int[triggers.size()];
        int currentTriggerState = mProfile.getTriggerState(triggerType, triggerId);
        int currentItem = -1;
        for (int i = 0; i < triggers.size(); i++) {
            Trigger t = triggers.get(i);
            entries[i] = t.name;
            valueInts[i] = t.value;
            if (valueInts[i] == currentTriggerState) {
                currentItem = i;
            }
    @Override
    protected TriggerInfo onConvertToTriggerInfo(AbstractTriggerItem trigger) {
        BluetoothTrigger bt = (BluetoothTrigger) trigger;
        return new TriggerInfo(Profile.TriggerType.BLUETOOTH, bt.getAddress(), bt.getTitle());
    }

        new AlertDialog.Builder(getActivity())
                .setTitle(R.string.profile_trigger_configure)
                .setSingleChoiceItems(entries, currentItem, new DialogInterface.OnClickListener() {
    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        mProfile.setTrigger(triggerType, triggerId, valueInts[which], triggerName);
                        mProfileManager.updateProfile(mProfile);
                        reloadTriggerListItems();
                        dialog.dismiss();
    protected boolean isTriggerStateSupported(TriggerInfo info, int triggerState) {
        if (triggerState != Profile.TriggerState.ON_A2DP_CONNECT
                && triggerState != Profile.TriggerState.ON_A2DP_DISCONNECT) {
            return true;
        }
                })
                .show();
        BluetoothDevice dev = mBluetoothAdapter.getRemoteDevice(info.id);
        return dev.getBluetoothClass().doesClassMatch(BluetoothClass.PROFILE_A2DP);
    }

    @Override
    public void onStart() {
        super.onStart();
        getListView().setEmptyView(mEmptyView);
        getListView().setDivider(null);
    protected int getEmptyViewLayoutResId() {
        return R.layout.profile_bluetooth_empty_view;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mEmptyView = inflater.inflate(R.layout.profile_bluetooth_empty_view, container, false);
        mEmptyView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent bluetoothSettings = new Intent();
                bluetoothSettings.setAction(
                        Settings.ACTION_BLUETOOTH_SETTINGS);
                startActivity(bluetoothSettings);
            }
        });

        ViewGroup view = (ViewGroup) super.onCreateView(inflater, container, savedInstanceState);
        view.addView(mEmptyView);
        return view;
    protected Intent getEmptyViewClickIntent() {
        return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        reloadTriggerListItems();
        mListAdapter = new BluetoothTriggerAdapter(getActivity());
        setListAdapter(mListAdapter);
    }

    private void removeTrigger(List<Trigger> triggers, int value) {
        for (Trigger t : triggers) {
            if (t.value == value) {
                triggers.remove(t);
                return;
            }
        }
    }

    private void reloadTriggerListItems() {
        mTriggers.clear();
        final Resources res = getResources();

        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
        if (!pairedDevices.isEmpty()) {
            for (BluetoothDevice device : pairedDevices) {
                BluetoothTrigger bt =
                        new BluetoothTrigger(device);
                int state = mProfile.getTriggerState(
                        Profile.TriggerType.BLUETOOTH, bt.getAddress());
                initPreference(bt, state, res, R.drawable.ic_settings_bluetooth);
                mTriggers.add(bt);
            }
        } else {
            final List<Profile.ProfileTrigger> triggers =
                    mProfile.getTriggersFromType(Profile.TriggerType.BLUETOOTH);
            for (Profile.ProfileTrigger trigger : triggers) {
                BluetoothTrigger bt = new BluetoothTrigger(trigger.getName(), trigger.getId());
                initPreference(bt, trigger.getState(), res, R.drawable.ic_settings_bluetooth);
                mTriggers.add(bt);
            }
        }

        if (mListAdapter != null) {
            mListAdapter.notifyDataSetChanged();
        }
    }

    private class Trigger {
        int value;
        String name;
    }

    private class BluetoothTriggerAdapter extends ArrayAdapter<BluetoothTrigger> {
        public BluetoothTriggerAdapter(Context context) {
            super(context, R.layout.abstract_trigger_row, R.id.title, mTriggers);
    protected int getOptionArrayResId() {
        return R.array.profile_trigger_bt_options;
    }

    @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            LayoutInflater inflater = LayoutInflater.from(getContext());
            View rowView = inflater.inflate(R.layout.abstract_trigger_row, viewGroup, false);
            TextView title = (TextView) rowView.findViewById(R.id.title);
            TextView desc = (TextView) rowView.findViewById(R.id.desc);
            ImageView imageView = (ImageView) rowView.findViewById(R.id.icon);

            BluetoothTrigger trigger = getItem(i);

            title.setText(trigger.getTitle());
            desc.setText(trigger.getSummary());
            imageView.setImageResource(trigger.getIcon());

            return rowView;
        }
    protected int getOptionValuesArrayResId() {
        return R.array.profile_trigger_bt_options_values;
    }

    public static class BluetoothTrigger extends AbstractTriggerItem {
+37 −187

File changed.

Preview size limit exceeded, changes collapsed.