aboutsummaryrefslogtreecommitdiff
path: root/parts/src/org/lineageos
diff options
context:
space:
mode:
Diffstat (limited to 'parts/src/org/lineageos')
-rw-r--r--parts/src/org/lineageos/settings/BootCompletedReceiver.java37
-rw-r--r--parts/src/org/lineageos/settings/speaker/ClearSpeakerActivity.java43
-rw-r--r--parts/src/org/lineageos/settings/speaker/ClearSpeakerFragment.java118
-rw-r--r--parts/src/org/lineageos/settings/thermal/ThermalActivity.java45
-rw-r--r--parts/src/org/lineageos/settings/thermal/ThermalService.java102
-rw-r--r--parts/src/org/lineageos/settings/thermal/ThermalSettingsFragment.java433
-rw-r--r--parts/src/org/lineageos/settings/thermal/ThermalUtils.java170
-rw-r--r--parts/src/org/lineageos/settings/utils/FileUtils.java166
8 files changed, 1114 insertions, 0 deletions
diff --git a/parts/src/org/lineageos/settings/BootCompletedReceiver.java b/parts/src/org/lineageos/settings/BootCompletedReceiver.java
new file mode 100644
index 0000000..1652bc0
--- /dev/null
+++ b/parts/src/org/lineageos/settings/BootCompletedReceiver.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The CyanogenMod Project
+ * 2017-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.settings;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import org.lineageos.settings.thermal.ThermalUtils;
+
+public class BootCompletedReceiver extends BroadcastReceiver {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "XiaomiParts";
+
+ @Override
+ public void onReceive(final Context context, Intent intent) {
+ if (DEBUG) Log.d(TAG, "Received boot completed intent");
+ ThermalUtils.startService(context);
+ }
+}
diff --git a/parts/src/org/lineageos/settings/speaker/ClearSpeakerActivity.java b/parts/src/org/lineageos/settings/speaker/ClearSpeakerActivity.java
new file mode 100644
index 0000000..5ac5b35
--- /dev/null
+++ b/parts/src/org/lineageos/settings/speaker/ClearSpeakerActivity.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 Paranoid Android
+ *
+ * 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.settings.speaker;
+
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
+import com.android.settingslib.collapsingtoolbar.R;
+
+public class ClearSpeakerActivity extends CollapsingToolbarBaseActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getFragmentManager().beginTransaction()
+ .replace(R.id.content_frame, new ClearSpeakerFragment())
+ .commit();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/parts/src/org/lineageos/settings/speaker/ClearSpeakerFragment.java b/parts/src/org/lineageos/settings/speaker/ClearSpeakerFragment.java
new file mode 100644
index 0000000..7f12fd9
--- /dev/null
+++ b/parts/src/org/lineageos/settings/speaker/ClearSpeakerFragment.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 Paranoid Android
+ *
+ * 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.settings.speaker;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioManager;
+import android.media.AudioAttributes;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceFragment;
+import androidx.preference.SwitchPreference;
+
+import org.lineageos.settings.R;
+
+import java.io.IOException;
+
+public class ClearSpeakerFragment extends PreferenceFragment implements
+ Preference.OnPreferenceChangeListener {
+
+ private static final String TAG = ClearSpeakerFragment.class.getSimpleName();
+
+ private static final String PREF_CLEAR_SPEAKER = "clear_speaker_pref";
+
+ private AudioManager mAudioManager;
+ private Handler mHandler;
+ private MediaPlayer mMediaPlayer;
+ private SwitchPreference mClearSpeakerPref;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.clear_speaker_settings);
+
+ mClearSpeakerPref = (SwitchPreference) findPreference(PREF_CLEAR_SPEAKER);
+ mClearSpeakerPref.setOnPreferenceChangeListener(this);
+
+ mHandler = new Handler();
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if (preference == mClearSpeakerPref) {
+ boolean value = (Boolean) newValue;
+ if (value) {
+ if (startPlaying()) {
+ mHandler.removeCallbacksAndMessages(null);
+ mHandler.postDelayed(() -> {
+ stopPlaying();
+ }, 30000);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void onStop() {
+ stopPlaying();
+ super.onStop();
+ }
+
+ public boolean startPlaying() {
+ mAudioManager.setParameters("status_earpiece_clean=on");
+ mMediaPlayer = new MediaPlayer();
+ getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
+ mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mMediaPlayer.setLooping(true);
+ try {
+ AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.clear_speaker_sound);
+ try {
+ mMediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength());
+ } finally {
+ file.close();
+ }
+ mClearSpeakerPref.setEnabled(false);
+ mMediaPlayer.setVolume(1.0f, 1.0f);
+ mMediaPlayer.prepare();
+ mMediaPlayer.start();
+ } catch (IOException ioe) {
+ Log.e(TAG, "Failed to play speaker clean sound!", ioe);
+ return false;
+ }
+ return true;
+ }
+
+ public void stopPlaying() {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.stop();
+ mMediaPlayer.reset();
+ mMediaPlayer.release();
+ }
+ mAudioManager.setParameters("status_earpiece_clean=off");
+ mClearSpeakerPref.setEnabled(true);
+ mClearSpeakerPref.setChecked(false);
+ }
+}
diff --git a/parts/src/org/lineageos/settings/thermal/ThermalActivity.java b/parts/src/org/lineageos/settings/thermal/ThermalActivity.java
new file mode 100644
index 0000000..16df382
--- /dev/null
+++ b/parts/src/org/lineageos/settings/thermal/ThermalActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.settings.thermal;
+
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
+import com.android.settingslib.collapsingtoolbar.R;
+
+public class ThermalActivity extends CollapsingToolbarBaseActivity {
+
+ private static final String TAG_THERMAL = "thermal";
+ private static final String THERMAL_SCONFIG = "/sys/class/thermal/thermal_message/sconfig";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getFragmentManager().beginTransaction().replace(R.id.content_frame,
+ new ThermalSettingsFragment(), TAG_THERMAL).commit();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/parts/src/org/lineageos/settings/thermal/ThermalService.java b/parts/src/org/lineageos/settings/thermal/ThermalService.java
new file mode 100644
index 0000000..cba9044
--- /dev/null
+++ b/parts/src/org/lineageos/settings/thermal/ThermalService.java
@@ -0,0 +1,102 @@
+/*
+ * 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.settings.thermal;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.ActivityTaskManager.RootTaskInfo;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
+import android.app.Service;
+import android.app.TaskStackListener;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+public class ThermalService extends Service {
+
+ private static final String TAG = "ThermalService";
+ private static final boolean DEBUG = false;
+
+ private String mPreviousApp;
+ private ThermalUtils mThermalUtils;
+
+ private IActivityTaskManager mActivityTaskManager;
+
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mPreviousApp = "";
+ mThermalUtils.setDefaultThermalProfile();
+ }
+ };
+
+ @Override
+ public void onCreate() {
+ if (DEBUG) Log.d(TAG, "Creating service");
+ try {
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mActivityTaskManager.registerTaskStackListener(mTaskListener);
+ } catch (RemoteException e) {
+ // Do nothing
+ }
+ mThermalUtils = new ThermalUtils(this);
+ registerReceiver();
+ super.onCreate();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (DEBUG) Log.d(TAG, "Starting service");
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ private void registerReceiver() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ this.registerReceiver(mIntentReceiver, filter);
+ }
+
+ private final TaskStackListener mTaskListener = new TaskStackListener() {
+ @Override
+ public void onTaskStackChanged() {
+ try {
+ final RootTaskInfo info = mActivityTaskManager.getFocusedRootTaskInfo();
+ if (info == null || info.topActivity == null) {
+ return;
+ }
+
+ String foregroundApp = info.topActivity.getPackageName();
+ if (!foregroundApp.equals(mPreviousApp)) {
+ mThermalUtils.setThermalProfile(foregroundApp);
+ mPreviousApp = foregroundApp;
+ }
+ } catch (Exception e) {}
+ }
+ };
+}
diff --git a/parts/src/org/lineageos/settings/thermal/ThermalSettingsFragment.java b/parts/src/org/lineageos/settings/thermal/ThermalSettingsFragment.java
new file mode 100644
index 0000000..6f4e402
--- /dev/null
+++ b/parts/src/org/lineageos/settings/thermal/ThermalSettingsFragment.java
@@ -0,0 +1,433 @@
+/**
+ * Copyright (C) 2020 The LineageOS Project
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.settings.thermal;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.SectionIndexer;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.preference.PreferenceFragment;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.LinearLayoutManager;
+
+import com.android.settingslib.applications.ApplicationsState;
+
+import org.lineageos.settings.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ThermalSettingsFragment extends PreferenceFragment
+ implements ApplicationsState.Callbacks {
+
+ private AllPackagesAdapter mAllPackagesAdapter;
+ private ApplicationsState mApplicationsState;
+ private ApplicationsState.Session mSession;
+ private ActivityFilter mActivityFilter;
+ private Map<String, ApplicationsState.AppEntry> mEntryMap =
+ new HashMap<String, ApplicationsState.AppEntry>();
+
+ private RecyclerView mAppsRecyclerView;
+
+ private ThermalUtils mThermalUtils;
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
+ mSession = mApplicationsState.newSession(this);
+ mSession.onResume();
+ mActivityFilter = new ActivityFilter(getActivity().getPackageManager());
+
+ mAllPackagesAdapter = new AllPackagesAdapter(getActivity());
+
+ mThermalUtils = new ThermalUtils(getActivity());
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.thermal_layout, container, false);
+ }
+
+ @Override
+ public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mAppsRecyclerView = view.findViewById(R.id.thermal_rv_view);
+ mAppsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
+ mAppsRecyclerView.setAdapter(mAllPackagesAdapter);
+ }
+
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ getActivity().setTitle(getResources().getString(R.string.thermal_title));
+ rebuild();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ mSession.onPause();
+ mSession.onDestroy();
+ }
+
+ @Override
+ public void onPackageListChanged() {
+ mActivityFilter.updateLauncherInfoList();
+ rebuild();
+ }
+
+ @Override
+ public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> entries) {
+ if (entries != null) {
+ handleAppEntries(entries);
+ mAllPackagesAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onLoadEntriesCompleted() {
+ rebuild();
+ }
+
+ @Override
+ public void onAllSizesComputed() {
+ }
+
+ @Override
+ public void onLauncherInfoChanged() {
+ }
+
+ @Override
+ public void onPackageIconChanged() {
+ }
+
+ @Override
+ public void onPackageSizeChanged(String packageName) {
+ }
+
+ @Override
+ public void onRunningStateChanged(boolean running) {
+ }
+
+ private void handleAppEntries(List<ApplicationsState.AppEntry> entries) {
+ final ArrayList<String> sections = new ArrayList<String>();
+ final ArrayList<Integer> positions = new ArrayList<Integer>();
+ final PackageManager pm = getActivity().getPackageManager();
+ String lastSectionIndex = null;
+ int offset = 0;
+
+ for (int i = 0; i < entries.size(); i++) {
+ final ApplicationInfo info = entries.get(i).info;
+ final String label = (String) info.loadLabel(pm);
+ final String sectionIndex;
+
+ if (!info.enabled) {
+ sectionIndex = "--"; // XXX
+ } else if (TextUtils.isEmpty(label)) {
+ sectionIndex = "";
+ } else {
+ sectionIndex = label.substring(0, 1).toUpperCase();
+ }
+
+ if (lastSectionIndex == null ||
+ !TextUtils.equals(sectionIndex, lastSectionIndex)) {
+ sections.add(sectionIndex);
+ positions.add(offset);
+ lastSectionIndex = sectionIndex;
+ }
+
+ offset++;
+ }
+
+ mAllPackagesAdapter.setEntries(entries, sections, positions);
+ mEntryMap.clear();
+ for (ApplicationsState.AppEntry e : entries) {
+ mEntryMap.put(e.info.packageName, e);
+ }
+ }
+
+ private void rebuild() {
+ mSession.rebuild(mActivityFilter, ApplicationsState.ALPHA_COMPARATOR);
+ }
+
+ private int getStateDrawable(int state) {
+ switch (state) {
+ case ThermalUtils.STATE_BENCHMARK:
+ return R.drawable.ic_thermal_benchmark;
+ case ThermalUtils.STATE_BROWSER:
+ return R.drawable.ic_thermal_browser;
+ case ThermalUtils.STATE_CAMERA:
+ return R.drawable.ic_thermal_camera;
+ case ThermalUtils.STATE_DIALER:
+ return R.drawable.ic_thermal_dialer;
+ case ThermalUtils.STATE_GAMING:
+ return R.drawable.ic_thermal_gaming;
+ case ThermalUtils.STATE_STREAMING:
+ return R.drawable.ic_thermal_streaming;
+ case ThermalUtils.STATE_DEFAULT:
+ default:
+ return R.drawable.ic_thermal_default;
+ }
+ }
+
+ private class ViewHolder extends RecyclerView.ViewHolder {
+ private TextView title;
+ private Spinner mode;
+ private ImageView icon;
+ private View rootView;
+ private ImageView stateIcon;
+
+ private ViewHolder(View view) {
+ super(view);
+ this.title = view.findViewById(R.id.app_name);
+ this.mode = view.findViewById(R.id.app_mode);
+ this.icon = view.findViewById(R.id.app_icon);
+ this.stateIcon = view.findViewById(R.id.state);
+ this.rootView = view;
+
+ view.setTag(this);
+ }
+ }
+
+ private class ModeAdapter extends BaseAdapter {
+
+ private final LayoutInflater inflater;
+ private final int[] items = {
+ R.string.thermal_default,
+ R.string.thermal_benchmark,
+ R.string.thermal_browser,
+ R.string.thermal_camera,
+ R.string.thermal_dialer,
+ R.string.thermal_gaming,
+ R.string.thermal_streaming
+ };
+
+ private ModeAdapter(Context context) {
+ inflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public int getCount() {
+ return items.length;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return items[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView view;
+ if (convertView != null) {
+ view = (TextView) convertView;
+ } else {
+ view = (TextView) inflater.inflate(android.R.layout.simple_spinner_dropdown_item,
+ parent, false);
+ }
+
+ view.setText(items[position]);
+ view.setTextSize(14f);
+
+ return view;
+ }
+ }
+
+ private class AllPackagesAdapter extends RecyclerView.Adapter<ViewHolder>
+ implements AdapterView.OnItemSelectedListener, SectionIndexer {
+
+ private List<ApplicationsState.AppEntry> mEntries = new ArrayList<>();
+ private String[] mSections;
+ private int[] mPositions;
+
+ public AllPackagesAdapter(Context context) {
+ mActivityFilter = new ActivityFilter(context.getPackageManager());
+ }
+
+ @Override
+ public int getItemCount() {
+ return mEntries.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return mEntries.get(position).id;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ ViewHolder holder = new ViewHolder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.thermal_list_item, parent, false));
+ Context context = holder.itemView.getContext();
+ holder.mode.setAdapter(new ModeAdapter(context));
+ holder.mode.setOnItemSelectedListener(this);
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ ApplicationsState.AppEntry entry = mEntries.get(position);
+
+ if (entry == null) {
+ return;
+ }
+
+ holder.title.setText(entry.label);
+ holder.title.setOnClickListener(v -> holder.mode.performClick());
+ mApplicationsState.ensureIcon(entry);
+ holder.icon.setImageDrawable(entry.icon);
+ int packageState = mThermalUtils.getStateForPackage(entry.info.packageName);
+ holder.mode.setSelection(packageState, false);
+ holder.mode.setTag(entry);
+ holder.stateIcon.setImageResource(getStateDrawable(packageState));
+ }
+
+ private void setEntries(List<ApplicationsState.AppEntry> entries,
+ List<String> sections, List<Integer> positions) {
+ mEntries = entries;
+ mSections = sections.toArray(new String[sections.size()]);
+ mPositions = new int[positions.size()];
+ for (int i = 0; i < positions.size(); i++) {
+ mPositions[i] = positions.get(i);
+ }
+ notifyDataSetChanged();
+ }
+
+
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ final ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) parent.getTag();
+ int currentState = mThermalUtils.getStateForPackage(entry.info.packageName);
+ if (currentState != position) {
+ mThermalUtils.writePackage(entry.info.packageName, position);
+ notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+
+ @Override
+ public int getPositionForSection(int section) {
+ if (section < 0 || section >= mSections.length) {
+ return -1;
+ }
+
+ return mPositions[section];
+ }
+
+ @Override
+ public int getSectionForPosition(int position) {
+ if (position < 0 || position >= getItemCount()) {
+ return -1;
+ }
+
+ final int index = Arrays.binarySearch(mPositions, position);
+
+ /*
+ * Consider this example: section positions are 0, 3, 5; the supplied
+ * position is 4. The section corresponding to position 4 starts at
+ * position 3, so the expected return value is 1. Binary search will not
+ * find 4 in the array and thus will return -insertPosition-1, i.e. -3.
+ * To get from that number to the expected value of 1 we need to negate
+ * and subtract 2.
+ */
+ return index >= 0 ? index : -index - 2;
+ }
+
+ @Override
+ public Object[] getSections() {
+ return mSections;
+ }
+ }
+
+ private class ActivityFilter implements ApplicationsState.AppFilter {
+
+ private final PackageManager mPackageManager;
+ private final List<String> mLauncherResolveInfoList = new ArrayList<String>();
+
+ private ActivityFilter(PackageManager packageManager) {
+ this.mPackageManager = packageManager;
+
+ updateLauncherInfoList();
+ }
+
+ public void updateLauncherInfoList() {
+ Intent i = new Intent(Intent.ACTION_MAIN);
+ i.addCategory(Intent.CATEGORY_LAUNCHER);
+ List<ResolveInfo> resolveInfoList = mPackageManager.queryIntentActivities(i, 0);
+
+ synchronized (mLauncherResolveInfoList) {
+ mLauncherResolveInfoList.clear();
+ for (ResolveInfo ri : resolveInfoList) {
+ mLauncherResolveInfoList.add(ri.activityInfo.packageName);
+ }
+ }
+ }
+
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(ApplicationsState.AppEntry entry) {
+ boolean show = !mAllPackagesAdapter.mEntries.contains(entry.info.packageName);
+ if (show) {
+ synchronized (mLauncherResolveInfoList) {
+ show = mLauncherResolveInfoList.contains(entry.info.packageName);
+ }
+ }
+ return show;
+ }
+ }
+}
diff --git a/parts/src/org/lineageos/settings/thermal/ThermalUtils.java b/parts/src/org/lineageos/settings/thermal/ThermalUtils.java
new file mode 100644
index 0000000..79510ed
--- /dev/null
+++ b/parts/src/org/lineageos/settings/thermal/ThermalUtils.java
@@ -0,0 +1,170 @@
+/*
+ * 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.settings.thermal;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.UserHandle;
+
+import androidx.preference.PreferenceManager;
+
+import org.lineageos.settings.utils.FileUtils;
+
+public final class ThermalUtils {
+
+ protected static final int STATE_DEFAULT = 0;
+ protected static final int STATE_BENCHMARK = 1;
+ protected static final int STATE_BROWSER = 2;
+ protected static final int STATE_CAMERA = 3;
+ protected static final int STATE_DIALER = 4;
+ protected static final int STATE_GAMING = 5;
+ protected static final int STATE_STREAMING = 6;
+ private static final String THERMAL_CONTROL = "thermal_control";
+ private static final String THERMAL_STATE_DEFAULT = "0";
+ private static final String THERMAL_STATE_BENCHMARK = "10";
+ private static final String THERMAL_STATE_BROWSER = "11";
+ private static final String THERMAL_STATE_CAMERA = "12";
+ private static final String THERMAL_STATE_DIALER = "8";
+ private static final String THERMAL_STATE_GAMING = "9";
+ private static final String THERMAL_STATE_STREAMING = "14";
+
+ private static final String THERMAL_BENCHMARK = "thermal.benchmark=";
+ private static final String THERMAL_BROWSER = "thermal.browser=";
+ private static final String THERMAL_CAMERA = "thermal.camera=";
+ private static final String THERMAL_DIALER = "thermal.dialer=";
+ private static final String THERMAL_GAMING = "thermal.gaming=";
+ private static final String THERMAL_STREAMING = "thermal.streaming=";
+
+ private static final String THERMAL_SCONFIG = "/sys/class/thermal/thermal_message/sconfig";
+
+ private SharedPreferences mSharedPrefs;
+
+ protected ThermalUtils(Context context) {
+ mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
+ }
+
+ public static void startService(Context context) {
+ if (FileUtils.fileExists(THERMAL_SCONFIG)) {
+ context.startServiceAsUser(new Intent(context, ThermalService.class),
+ UserHandle.CURRENT);
+ }
+ }
+
+ private void writeValue(String profiles) {
+ mSharedPrefs.edit().putString(THERMAL_CONTROL, profiles).apply();
+ }
+
+ private String getValue() {
+ String value = mSharedPrefs.getString(THERMAL_CONTROL, null);
+
+ if (value != null) {
+ String[] modes = value.split(":");
+ if (modes.length < 5) value = null;
+ }
+
+ if (value == null || value.isEmpty()) {
+ value = THERMAL_BENCHMARK + ":" + THERMAL_BROWSER + ":" + THERMAL_CAMERA + ":" +
+ THERMAL_DIALER + ":" + THERMAL_GAMING + ":" + THERMAL_STREAMING;
+ writeValue(value);
+ }
+ return value;
+ }
+
+ protected void writePackage(String packageName, int mode) {
+ String value = getValue();
+ value = value.replace(packageName + ",", "");
+ String[] modes = value.split(":");
+ String finalString;
+
+ switch (mode) {
+ case STATE_BENCHMARK:
+ modes[0] = modes[0] + packageName + ",";
+ break;
+ case STATE_BROWSER:
+ modes[1] = modes[1] + packageName + ",";
+ break;
+ case STATE_CAMERA:
+ modes[2] = modes[2] + packageName + ",";
+ break;
+ case STATE_DIALER:
+ modes[3] = modes[3] + packageName + ",";
+ break;
+ case STATE_GAMING:
+ modes[4] = modes[4] + packageName + ",";
+ break;
+ case STATE_STREAMING:
+ modes[5] = modes[5] + packageName + ",";
+ break;
+ }
+
+ finalString = modes[0] + ":" + modes[1] + ":" + modes[2] + ":" + modes[3] + ":" +
+ modes[4] + ":" + modes[5];
+
+ writeValue(finalString);
+ }
+
+ protected int getStateForPackage(String packageName) {
+ String value = getValue();
+ String[] modes = value.split(":");
+ int state = STATE_DEFAULT;
+ if (modes[0].contains(packageName + ",")) {
+ state = STATE_BENCHMARK;
+ } else if (modes[1].contains(packageName + ",")) {
+ state = STATE_BROWSER;
+ } else if (modes[2].contains(packageName + ",")) {
+ state = STATE_CAMERA;
+ } else if (modes[3].contains(packageName + ",")) {
+ state = STATE_DIALER;
+ } else if (modes[4].contains(packageName + ",")) {
+ state = STATE_GAMING;
+ } else if (modes[5].contains(packageName + ",")) {
+ state = STATE_STREAMING;
+ }
+
+ return state;
+ }
+
+ protected void setDefaultThermalProfile() {
+ FileUtils.writeLine(THERMAL_SCONFIG, THERMAL_STATE_DEFAULT);
+ }
+
+ protected void setThermalProfile(String packageName) {
+ String value = getValue();
+ String modes[];
+ String state = THERMAL_STATE_DEFAULT;
+
+ if (value != null) {
+ modes = value.split(":");
+
+ if (modes[0].contains(packageName + ",")) {
+ state = THERMAL_STATE_BENCHMARK;
+ } else if (modes[1].contains(packageName + ",")) {
+ state = THERMAL_STATE_BROWSER;
+ } else if (modes[2].contains(packageName + ",")) {
+ state = THERMAL_STATE_CAMERA;
+ } else if (modes[3].contains(packageName + ",")) {
+ state = THERMAL_STATE_DIALER;
+ } else if (modes[4].contains(packageName + ",")) {
+ state = THERMAL_STATE_GAMING;
+ } else if (modes[5].contains(packageName + ",")) {
+ state = THERMAL_STATE_STREAMING;
+ }
+ }
+ FileUtils.writeLine(THERMAL_SCONFIG, state);
+ }
+}
diff --git a/parts/src/org/lineageos/settings/utils/FileUtils.java b/parts/src/org/lineageos/settings/utils/FileUtils.java
new file mode 100644
index 0000000..2228ff8
--- /dev/null
+++ b/parts/src/org/lineageos/settings/utils/FileUtils.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package org.lineageos.settings.utils;
+
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public final class FileUtils {
+ private static final String TAG = "FileUtils";
+
+ private FileUtils() {
+ // This class is not supposed to be instantiated
+ }
+
+ /**
+ * Reads the first line of text from the given file.
+ * Reference {@link BufferedReader#readLine()} for clarification on what a
+ * line is
+ *
+ * @return the read line contents, or null on failure
+ */
+ public static String readOneLine(String fileName) {
+ String line = null;
+ BufferedReader reader = null;
+
+ try {
+ reader = new BufferedReader(new FileReader(fileName), 512);
+ line = reader.readLine();
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "No such file " + fileName + " for reading", e);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not read from file " + fileName, e);
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (IOException e) {
+ // Ignored, not much we can do anyway
+ }
+ }
+
+ return line;
+ }
+
+ /**
+ * Writes the given value into the given file
+ *
+ * @return true on success, false on failure
+ */
+ public static boolean writeLine(String fileName, String value) {
+ BufferedWriter writer = null;
+
+ try {
+ writer = new BufferedWriter(new FileWriter(fileName));
+ writer.write(value);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "No such file " + fileName + " for writing", e);
+ return false;
+ } catch (IOException e) {
+ Log.e(TAG, "Could not write to file " + fileName, e);
+ return false;
+ } finally {
+ try {
+ if (writer != null) {
+ writer.close();
+ }
+ } catch (IOException e) {
+ // Ignored, not much we can do anyway
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks whether the given file exists
+ *
+ * @return true if exists, false if not
+ */
+ public static boolean fileExists(String fileName) {
+ final File file = new File(fileName);
+ return file.exists();
+ }
+
+ /**
+ * Checks whether the given file is readable
+ *
+ * @return true if readable, false if not
+ */
+ public static boolean isFileReadable(String fileName) {
+ final File file = new File(fileName);
+ return file.exists() && file.canRead();
+ }
+
+ /**
+ * Checks whether the given file is writable
+ *
+ * @return true if writable, false if not
+ */
+ public static boolean isFileWritable(String fileName) {
+ final File file = new File(fileName);
+ return file.exists() && file.canWrite();
+ }
+
+ /**
+ * Deletes an existing file
+ *
+ * @return true if the delete was successful, false if not
+ */
+ public static boolean delete(String fileName) {
+ final File file = new File(fileName);
+ boolean ok = false;
+ try {
+ ok = file.delete();
+ } catch (SecurityException e) {
+ Log.w(TAG, "SecurityException trying to delete " + fileName, e);
+ }
+ return ok;
+ }
+
+ /**
+ * Renames an existing file
+ *
+ * @return true if the rename was successful, false if not
+ */
+ public static boolean rename(String srcPath, String dstPath) {
+ final File srcFile = new File(srcPath);
+ final File dstFile = new File(dstPath);
+ boolean ok = false;
+ try {
+ ok = srcFile.renameTo(dstFile);
+ } catch (SecurityException e) {
+ Log.w(TAG,
+ "SecurityException trying to rename " + srcPath + " to " + dstPath,
+ e);
+ } catch (NullPointerException e) {
+ Log.e(TAG,
+ "NullPointerException trying to rename " + srcPath + " to " +
+ dstPath,
+ e);
+ }
+ return ok;
+ }
+}