diff --git a/InCallService/Android.bp b/InCallService/Android.bp
new file mode 100644
index 0000000000000000000000000000000000000000..bf5143e41dfd42377bbea1d43eec1560a63ea0a3
--- /dev/null
+++ b/InCallService/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 bengris32
+ *
+ * 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.
+ */
+
+android_app {
+ name: "MtkInCallService",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ certificate: "platform",
+ platform_apis: true,
+ privileged: true,
+
+ optimize: {
+ enabled: false,
+ }
+}
diff --git a/InCallService/AndroidManifest.xml b/InCallService/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cb5c2bc4040f77b5c2559eb37fd809e88428d306
--- /dev/null
+++ b/InCallService/AndroidManifest.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/InCallService/res/values/strings.xml b/InCallService/res/values/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d71b129470242076bc037ee81d819b7ff8cf5820
--- /dev/null
+++ b/InCallService/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ MTK In-call service
+
diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/GainUtils.java b/InCallService/src/org/lineageos/mediatek/incallservice/GainUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e778fe3f285fc781adb09c92ec0ad3720100926
--- /dev/null
+++ b/InCallService/src/org/lineageos/mediatek/incallservice/GainUtils.java
@@ -0,0 +1,16 @@
+package org.lineageos.mediatek.incallservice;
+
+import android.media.AudioSystem;
+
+import android.util.Log;
+
+public class GainUtils {
+ public static final String LOG_TAG = "MtkInCallService";
+
+ public static void setGainLevel(int audioDevice, int gainIndex, int streamType) {
+ String parameters = String.format("volumeDevice=%d;volumeIndex=%d;volumeStreamType=%d",
+ audioDevice, Math.min(7, gainIndex), streamType);
+ Log.d(LOG_TAG, "Setting audio parameters to: " + parameters);
+ AudioSystem.setParameters(parameters);
+ }
+}
diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/OnLockedBootCompleteReceiver.java b/InCallService/src/org/lineageos/mediatek/incallservice/OnLockedBootCompleteReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..80d7f7d5402a2a9b00b83a2346406cfff3bb5120
--- /dev/null
+++ b/InCallService/src/org/lineageos/mediatek/incallservice/OnLockedBootCompleteReceiver.java
@@ -0,0 +1,19 @@
+package org.lineageos.mediatek.incallservice;
+
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.Context;
+
+import android.util.Log;
+
+public class OnLockedBootCompleteReceiver extends BroadcastReceiver {
+ private static final String LOG_TAG = "MtkInCallService";
+
+ @Override
+ public void onReceive(final Context context, Intent intent) {
+ Log.i(LOG_TAG, "onBoot");
+
+ Intent sIntent = new Intent(context, VolumeChangeService.class);
+ context.startService(sIntent);
+ }
+}
diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java
new file mode 100644
index 0000000000000000000000000000000000000000..b80533db2a7027c3218c9ed8f5c019fc21325d13
--- /dev/null
+++ b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java
@@ -0,0 +1,54 @@
+package org.lineageos.mediatek.incallservice;
+
+import android.content.Intent;
+import android.content.Context;
+import android.content.BroadcastReceiver;
+
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.AudioDeviceInfo;
+
+import android.util.Log;
+
+public class VolumeChangeReceiver extends BroadcastReceiver {
+ public static final String LOG_TAG = "MtkInCallService";
+
+ private AudioManager mAudioManager;
+
+ public VolumeChangeReceiver(AudioManager audioManager) {
+ mAudioManager = audioManager;
+ }
+
+ private void handleVolumeStateChange(Intent intent) {
+ if (intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1) == AudioManager.STREAM_VOICE_CALL) {
+
+ if (!mAudioManager.isSpeakerphoneOn() && !mAudioManager.isBluetoothScoOn()) {
+ // Device is not the built in earpiece, we don't need to do anything.
+ return;
+ }
+
+ AudioDeviceInfo[] allDevices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ AudioDeviceInfo callDevice = null;
+ for (AudioDeviceInfo device: allDevices) {
+ if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
+ callDevice = device;
+ break;
+ }
+ }
+
+ // Try to get volumeIndex
+ int volumeIndex = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
+ if (volumeIndex < 0) {
+ Log.w(LOG_TAG, "Could not get volumeIndex!");
+ return;
+ }
+
+ GainUtils.setGainLevel(callDevice.getPort().type(), volumeIndex, AudioSystem.STREAM_VOICE_CALL);
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleVolumeStateChange(intent);
+ }
+}
diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1cc8dbb30ad0962cbe1240befc990a0974f0e79
--- /dev/null
+++ b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java
@@ -0,0 +1,42 @@
+package org.lineageos.mediatek.incallservice;
+
+import android.media.AudioManager;
+
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.Context;
+import android.app.Service;
+import android.os.IBinder;
+
+import android.util.Log;
+
+public class VolumeChangeService extends Service {
+ public static final String LOG_TAG = "MtkInCallService";
+
+ private Context mContext;
+ private VolumeChangeReceiver mVolumeChangeReceiver;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startid) {
+ mContext = this;
+
+ AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mVolumeChangeReceiver = new VolumeChangeReceiver(audioManager);
+
+ Log.i(LOG_TAG, "Service is starting...");
+
+ this.registerReceiver(mVolumeChangeReceiver,
+ new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));
+ return START_STICKY;
+ }
+}
diff --git a/device.mk b/device.mk
index 08e4638ee76e352f5a005261a3185c7d232ff769..79f5e4a00d54e084a2ba31785628ec42124df0e6 100644
--- a/device.mk
+++ b/device.mk
@@ -188,6 +188,10 @@ PRODUCT_PACKAGES += \
com.android.media.swcodec \
libsfplugin_ccodec
+# MtkInCallService
+PRODUCT_PACKAGES += \
+ MtkInCallService
+
# NFC
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/android.hardware.nfc.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/sku_nfc-st/android.hardware.nfc.xml \