gts3l-common: audio: Implement audio rotation handler app×service

Originally this patch is made for Galaxy Tab S5e But I cherry-picked
this to our Galaxy Tab S3 device comes with editing the parameter key,
values.

Thanks LuK1337 for this amazing patch.

Change-Id: Ibc053edf1fa7e797f6457dfead416b177da57ab6
This commit is contained in:
LuK1337 2019-08-20 15:37:25 +02:00 committed by Deokgyu Yang
parent 55414cbde4
commit cbd81cde70
13 changed files with 333 additions and 1 deletions

View file

@ -0,0 +1,17 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := AudioRotationMonitor
LOCAL_CERTIFICATE := platform
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
include $(BUILD_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.lineageos.audiorotationmonitor"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="21" />
<application
android:label="AudioRotationMonitor"
android:persistent="true">
<receiver android:name="org.lineageos.audiorotationmonitor.BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:name="org.lineageos.audiorotationmonitor.DisplayListenerService"
android:permission="AudioRotationMonitorService">
</service>
</application>
</manifest>

View file

@ -0,0 +1,3 @@
-keep class org.lineageos.audiorotationmonitor.* {
*;
}

View file

@ -0,0 +1,14 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := set-audio-rotation
LOCAL_MODULE_TAGS := optional
LOCAL_INIT_RC := set-audio-rotation.rc
LOCAL_SRC_FILES := \
set-audio-rotation.cpp
LOCAL_SHARED_LIBRARIES := \
libbase \
libtinyalsa
include $(BUILD_EXECUTABLE)

View file

@ -0,0 +1,79 @@
/*
* Copyright (C) 2019 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.
*/
#define LOG_TAG "set-audio-rotation"
#include <android-base/logging.h>
#include <tinyalsa/asoundlib.h>
constexpr int SLOT_POSITIONS_0[] = { 0, 1, 0, 1 };
constexpr int SLOT_POSITIONS_90[] = { 1, 1, 0, 0 };
constexpr int SLOT_POSITIONS_180[] = { 1, 0, 1, 0 };
constexpr int SLOT_POSITIONS_270[] = { 0, 0, 1, 1 };
void setMixerValueByName(mixer *mixer, const char *name, int value) {
const auto ctl = mixer_get_ctl_by_name(mixer, name);
if (ctl == nullptr) {
LOG(ERROR) << "Failed to find mixer ctl for " << name;
return;
}
if (mixer_ctl_set_value(ctl, 0, value) < 0) {
LOG(ERROR) << "Failed to set ctl value " << value << " for " << name;
return;
}
}
void setSlotPositions(const int *values) {
const auto mixer = mixer_open(0);
if (mixer == nullptr) {
LOG(ERROR) << "Failed to open mixer";
return;
}
setMixerValueByName(mixer, "ExtSPK LL TDM_ADC_SEL", values[0]);
setMixerValueByName(mixer, "ExtSPK LR TDM_ADC_SEL", values[1]);
setMixerValueByName(mixer, "ExtSPK UL TDM_ADC_SEL", values[2]);
setMixerValueByName(mixer, "ExtSPK UR TDM_ADC_SEL", values[3]);
setMixerValueByName(mixer, "ExtSPK LL TDM_DAC_SEL", values[0]);
setMixerValueByName(mixer, "ExtSPK LR TDM_DAC_SEL", values[1]);
setMixerValueByName(mixer, "ExtSPK UL TDM_DAC_SEL", values[2]);
setMixerValueByName(mixer, "ExtSPK UR TDM_DAC_SEL", values[3]);
mixer_close(mixer);
};
int main(int argc, char **argv) {
if (argc != 2) {
return -1;
}
if (strcmp(argv[1], "0") == 0) {
setSlotPositions(SLOT_POSITIONS_0);
} else if (strcmp(argv[1], "1") == 0) {
setSlotPositions(SLOT_POSITIONS_90);
} else if (strcmp(argv[1], "2") == 0) {
setSlotPositions(SLOT_POSITIONS_180);
} else if (strcmp(argv[1], "3") == 0) {
setSlotPositions(SLOT_POSITIONS_270);
} else {
return -1;
}
return 0;
}

View file

@ -0,0 +1,2 @@
on property:sys.audio.rotation=*
exec - root audio -- /system/bin/set-audio-rotation ${sys.audio.rotation}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2019 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.audiorotationmonitor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootCompletedReceiver extends BroadcastReceiver {
private static final String TAG = "AudioRotationMonitor";
@Override
public void onReceive(final Context context, Intent intent) {
Log.d(TAG, "Starting");
context.startService(new Intent(context, DisplayListenerService.class));
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2019 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.audiorotationmonitor;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.SystemProperties;
import android.util.Log;
import android.view.Surface;
import android.view.WindowManager;
public class DisplayListener implements DisplayManager.DisplayListener {
private static final boolean DEBUG = true;
private static final String TAG = "DisplayListener";
private static final String AUDIO_ROTATION_PROP = "sys.audio.rotation";
private Context mContext;
private Handler mHandler;
private DisplayManager mDisplayManager;
private WindowManager mWindowManager;
private final Object mRotationLock = new Object();
private int mDeviceRotation = Surface.ROTATION_0;
public DisplayListener(Context context) {
mContext = context;
mHandler = new Handler();
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mWindowManager = mContext.getSystemService(WindowManager.class);
}
@Override
public void onDisplayAdded(int displayId) {
if (DEBUG) Log.d(TAG, "onDisplayAdded");
}
@Override
public void onDisplayRemoved(int displayId) {
if (DEBUG) Log.d(TAG, "onDisplayRemoved");
}
@Override
public void onDisplayChanged(int displayId) {
if (DEBUG) Log.d(TAG, "onDisplayChanged");
updateOrientation();
}
private void updateOrientation() {
// Even though we're responding to device orientation events,
// use display rotation so audio stays in sync with video/dialogs
int newRotation = mWindowManager.getDefaultDisplay().getRotation();
synchronized (mRotationLock) {
if (newRotation != mDeviceRotation) {
mDeviceRotation = newRotation;
SystemProperties.set(AUDIO_ROTATION_PROP, String.valueOf(mDeviceRotation));
}
}
}
public void enable() {
if (DEBUG) Log.d(TAG, "Enabling");
mDisplayManager.registerDisplayListener(this, mHandler);
updateOrientation();
}
public void disable() {
if (DEBUG) Log.d(TAG, "Disabling");
mDisplayManager.unregisterDisplayListener(this);
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2019 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.audiorotationmonitor;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class DisplayListenerService extends Service {
private static final String TAG = "DisplayListenerService";
private static final boolean DEBUG = true;
private DisplayListener mDisplayListener;
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mDisplayListener = new DisplayListener(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
mDisplayListener.enable();
return START_STICKY;
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
mDisplayListener.disable();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

View file

@ -101,7 +101,9 @@ PRODUCT_PACKAGES += \
libqcomvoiceprocessing \
libvolumelistener \
tinymix \
libaudioprimary_shim
libaudioprimary_shim \
AudioRotationMonitor \
set-audio-rotation
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/audio/audio/audio_policy_configuration.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio/audio_policy_configuration.xml \

View file

@ -17,6 +17,7 @@
# Binaries
/(vendor|system/vendor)/bin/hw/macloader u:object_r:macloader_exec:s0
/(vendor|system/vendor)/bin/secril_config_svc u:object_r:secril_config_svc_exec:s0
/system/bin/set-audio-rotation u:object_r:set-audio-rotation_exec:s0
# Data files
/data/camera(/.*)? u:object_r:camera_socket:s0

View file

@ -32,6 +32,7 @@ ro.vendor.camera.wrapper.hal3TrebleMinorVersion u:object_r:sec_camera_prop:s0
ro.vendor.multisim. u:object_r:vendor_radio_prop:s0
ro.vendor.radio. u:object_r:vendor_radio_prop:s0
service.camera. u:object_r:sec_camera_prop:s0
sys.audio.rotation u:object_r:exported_system_prop:s0
sys.cameramode. u:object_r:sec_camera_prop:s0
system.camera.CC. u:object_r:sec_camera_prop:s0
vendor.bluetooth_fw_ver u:object_r:vendor_bluetooth_prop:s0

View file

@ -0,0 +1,8 @@
type set-audio-rotation, domain, coredomain;
type set-audio-rotation_exec, exec_type, file_type;
init_daemon_domain(set-audio-rotation)
# Allow set-audio-rotation to read and write to audio_device
allow set-audio-rotation audio_device:dir r_dir_perms;
allow set-audio-rotation audio_device:chr_file rw_file_perms;