Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions AudioOutputSwitch/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use Android.bp instead for future-proofing ?


LOCAL_PACKAGE_NAME := AudioOutputSwitch
LOCAL_MODULE_TAGS := optional
LOCAL_SYSTEM_EXT_MODULE := true
LOCAL_PRIVILEGED_MODULE := true
LOCAL_CERTIFICATE := platform
LOCAL_PRIVATE_PLATFORM_APIS := true

LOCAL_MANIFEST_FILE := AndroidManifest.xml
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res

include $(BUILD_PACKAGE)
56 changes: 56 additions & 0 deletions AudioOutputSwitch/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.lineageos.tv.audiooutput"
android:versionCode="1"
android:versionName="1.0">

<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />

<application
android:allowBackup="false"
android:directBootAware="true"
android:extractNativeLibs="false"
android:icon="@drawable/sound_icon"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AudioOutputTheme"
android:usesNonSdkApi="true">

<activity
android:name=".AudioOutputActivity"
android:exported="true"
android:label="@string/sound_pref_title">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>

<service
android:name=".BootMaintenanceService"
android:directBootAware="true"
android:enabled="true"
android:exported="false" />

<receiver
android:name=".BootReceiver"
android:directBootAware="true"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
</application>
</manifest>
16 changes: 16 additions & 0 deletions AudioOutputSwitch/res/drawable/sound_icon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,18 L15,18 L27,8 L27,40 L15,30 L6,30 Z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M32,16 C35,18 37,21 37,24 C37,27 35,30 32,32 L30,28 C31.8,27 33,25.6 33,24 C33,22.4 31.8,21 30,20 Z" />
<path
android:fillColor="#FFFFFFFF"
android:pathData="M36,9 C42,13 45,18.2 45,24 C45,29.8 42,35 36,39 L34,35 C38.5,32 41,28.2 41,24 C41,19.8 38.5,16 34,13 Z" />
</vector>
4 changes: 4 additions & 0 deletions AudioOutputSwitch/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="audio_output_background">#101318</color>
</resources>
19 changes: 19 additions & 0 deletions AudioOutputSwitch/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Audio Output Switch</string>
<string name="sound_pref_title">Audio output</string>
<string name="sound_pref_summary">Choose the media playback device.</string>
<string name="audio_output_title">Audio output</string>
<string name="audio_output_summary">Select the output device used for media playback.</string>
<string name="system_default">System default</string>
<string name="unknown_device">Unknown audio device</string>
<string name="status_select_device">Choose an output device.</string>
<string name="status_selected">Using %1$s for media playback.</string>
<string name="status_default_selected">Using the system default audio output.</string>
<string name="status_device_unavailable">That audio device is no longer available.</string>
<string name="status_saved_device_cleared">Saved device is not currently safe to use: %1$s. Using system default.</string>
<string name="status_saved_device_missing">Saved device is not currently available: %1$s.</string>
<string name="status_route_rejected">Audio policy did not accept %1$s.</string>
<string name="status_default_rejected">Audio policy did not clear the preferred device.</string>
<string name="status_route_failed">Audio routing failed: %1$s</string>
</resources>
8 changes: 8 additions & 0 deletions AudioOutputSwitch/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AudioOutputTheme" parent="@android:style/Theme.Material.NoActionBar">
<item name="android:windowBackground">@color/audio_output_background</item>
<item name="android:fontFamily">sans</item>
<item name="android:colorAccent">#8AB4F8</item>
</style>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package org.lineageos.tv.audiooutput;

import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

public final class AudioOutputActivity extends Activity {
private RouteAdapter mAdapter;
private ListView mListView;
private TextView mStatusView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
buildUi();
refreshRoutes(getString(R.string.status_select_device));
}

@Override
protected void onResume() {
super.onResume();
refreshRoutes(null);
}

private void buildUi() {
LinearLayout root = new LinearLayout(this);
root.setOrientation(LinearLayout.VERTICAL);
root.setGravity(Gravity.CENTER_HORIZONTAL);
root.setPadding(dp(32), dp(28), dp(32), dp(24));
root.setBackgroundColor(Color.rgb(16, 19, 24));

TextView title = new TextView(this);
title.setText(R.string.audio_output_title);
title.setTextColor(Color.WHITE);
title.setTextSize(28);
title.setGravity(Gravity.START);
title.setPadding(0, 0, 0, dp(8));
root.addView(title, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

TextView summary = new TextView(this);
summary.setText(R.string.audio_output_summary);
summary.setTextColor(Color.rgb(189, 197, 208));
summary.setTextSize(16);
summary.setPadding(0, 0, 0, dp(18));
root.addView(summary, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

mListView = new ListView(this);
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
mListView.setItemsCanFocus(false);
mListView.setSelector(android.R.drawable.list_selector_background);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
AudioRouteManager.RouteItem item = mAdapter.getItem(position);
if (item != null) {
selectRoute(item);
}
}
});
root.addView(mListView, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f));

mStatusView = new TextView(this);
mStatusView.setTextColor(Color.rgb(213, 218, 226));
mStatusView.setTextSize(14);
mStatusView.setMinLines(2);
mStatusView.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
mStatusView.setPadding(0, dp(12), 0, 0);
root.addView(mStatusView, new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

setContentView(root);
}

private void refreshRoutes(String status) {
List<AudioRouteManager.RouteItem> routes = AudioRouteManager.getRouteItems(this);
if (mAdapter == null) {
mAdapter = new RouteAdapter(this, routes);
mListView.setAdapter(mAdapter);
} else {
mAdapter.clear();
mAdapter.addAll(routes);
mAdapter.notifyDataSetChanged();
}

int checked = AudioRouteManager.findSavedRouteIndex(this, routes);
if (checked >= 0) {
mListView.setItemChecked(checked, true);
mListView.setSelection(checked);
}

if (status != null) {
mStatusView.setText(status);
}
}

private void selectRoute(AudioRouteManager.RouteItem item) {
AudioRouteManager.RouteResult result;
if (item.isDefault()) {
result = AudioRouteManager.clearPreferredDeviceForMedia(this);
if (result.success) {
AudioRouteManager.saveDefaultRoute(this);
}
} else {
result = AudioRouteManager.setPreferredDeviceForMedia(this, item.device);
if (result.success) {
AudioRouteManager.saveRoute(this, item);
}
}

String message = result.message;
mStatusView.setText(message);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
refreshRoutes(message);
}

private int dp(int value) {
return (int) (value * getResources().getDisplayMetrics().density + 0.5f);
}

private final class RouteAdapter extends ArrayAdapter<AudioRouteManager.RouteItem> {
RouteAdapter(Context context, List<AudioRouteManager.RouteItem> routes) {
super(context, android.R.layout.simple_list_item_single_choice, routes);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
CheckedTextView text = (CheckedTextView) view.findViewById(android.R.id.text1);
text.setTextColor(Color.WHITE);
text.setTextSize(20);
text.setGravity(Gravity.CENTER_VERTICAL);
text.setMinHeight(dp(58));
text.setPadding(dp(16), 0, dp(16), 0);
return view;
}
}
}
Loading