
# ViPER4Android FX™ + Dolby Atmos™ REdux on ICE™ functions

require_pie() {
  ui_print "  X Only Android 9.0+ supported"
  ui_print "  X 仅 Android 9.0+ 支持"
  ui_print " "
  exit 1
}

require_64bit() {
  ui_print "  X Only 64-bit devices supported"
  ui_print "  X 仅 64 位的设备支持"
  ui_print " "
  exit 1
}

compatibility() {
  ui_print "  √ Compatibility detected"
  ui_print "  √ 检测到已兼容"
  ui_print " "
  sleep 1
}

incompatibility() {
  ui_print "  X Incompatibility detected"
  ui_print "  X 检测到不兼容"
  sleep 1
  ui_print "  √ Installation will continue"
  ui_print "  √ 安装将继续"
  sleep 1
  ui_print "  ! If not working, run the following in terminal:"
  ui_print "  ! 如果不能工作，请在终端中运行以下操作："
  sleep 1
  ui_print "  $ su -c /vendor/bin/hw/*dolby*"
  ui_print " "
  sleep 1
}

mount_filesystems() {
  ui_print " "
  ui_print " "
  ui_print "• Mounting partitions..."
  ui_print "• 挂载分区..."
  sleep 1
  mount -o rw,remount / 2>/dev/null
  sleep 1
  if [ "$BOOTMODE" ]; then
    mirror=/sbin/.magisk/mirror
    mount -o rw,remount $mirror/system 2>/dev/null
    mount -o rw,remount $mirror/vendor 2>/dev/null
    sysroot=/sbin/.magisk/mirror/system_root
    if [ -d "$sysroot" ]; then
      mount -o rw,remount $sysroot
      if is_mounted $sysroot; then
        ui_print "  √ $sysroot mounted successfully"
        ui_print "  √ $sysroot 挂载成功"
      else
        ui_print "  X $sysroot mounted unsuccessfully"
        ui_print "  X $sysroot 挂载失败"
      fi
      ui_print " "
      sleep 1
      ui_print "• Assigning directory variables..."
      ui_print "• 分配目录变量..."
      sleep 1
      sys=$(realpath $mirror/system)
      ven=$(realpath $mirror/vendor)
      if [ -e "$sys/system/build.prop" ]; then
        sys=$mirror/system/system
      fi
      ui_print "  √ System: $sys"
      sleep 1
      ui_print "  √ Vendor: $sys/vendor"
    else
      sys=$mirror/system
      mount -o rw,remount $sys
      if is_mounted $sys; then
        ui_print "  √ $sys mounted successfully"
        ui_print "  √ $sys 挂载成功"
      else
        ui_print "  X $sys mounted unsuccessfully"
        ui_print "  X $sys 挂载失败"
      fi
      sleep 1
      if [ -L "$mirror/vendor" ]; then
        ven=$sys/vendor
      else
        mount -o rw,remount $mirror/vendor
        ven=$mirror/vendor
        if is_mounted $mirror/vendor; then
          ui_print "  √ $mirror/vendor mounted successfully"
          ui_print "  √ $mirror/vendor 挂载成功"
        else
          ui_print "  X $mirror/vendor mounted unsuccessfully"
          ui_print "  X $mirror/vendor 挂载失败"
        fi
      fi
      ui_print " "
      sleep 1
      ui_print "• Assigning directory variables..."
      ui_print "• 分配目录变量..."
      sleep 1
      sys=$(realpath $mirror/system)
      ven=$(realpath $mirror/vendor)
      if [ -e "$sys/system/build.prop" ]; then
        sys=$mirror/system/system
      fi
      ui_print "  √ System: $sys"
      sleep 1
      ui_print "  √ Vendor: $ven"
    fi
  else
    mount -o rw,remount /system
    sys=/system
    if is_mounted $sys; then
      ui_print "  √ $sys mounted successfully"
      ui_print "  √ $sys 挂载成功"
    else
      ui_print "  X $sys mounted unsuccessfully"
      ui_print "  X $sys 挂载失败"
    fi
    sleep 1
    if [ -L /vendor ]; then
      ven=$sys/vendor
    else
      ven=/vendor
      mount -o rw,remount $ven
      if is_mounted $ven; then
        ui_print "  √ $ven mounted successfully"
        ui_print "  √ $ven 挂载成功"
      else
        ui_print "  √ $ven mounted unsuccessfully"
        ui_print "  X $ven 挂载失败"
      fi
    fi
    sleep 1
    ui_print " "
    ui_print "• Assigning directory variables..."
    ui_print "• 分配目录变量..."
    sleep 1
    if [ -e "$sys/system/build.prop" ]; then
      sys=/system/system
    fi
    ui_print "  √ System: $sys"
    sleep 1
    ui_print "  √ Vendor: $ven"
  fi
  ui_print " "
  sleep 1
}

check_compatibility() {
  ui_print "• Checking ROM compatibility..."
  ui_print "• 检查 ROM 兼容性..."
  hwlib=$(find $sys -type f -name "android.hardware.audio@2.0.so")
  compatible1=$(grep "_ZN7android8hardware7details15gServicePrioMapE" $hwlib)
  compatible2=$(grep "_ZN7android8hardware7details19getBnConstructorMapEv" $hwlib)
  if [ "$API" -lt "28" ]; then
    require_pie
  elif [ "$IS64BIT" == "false" ]; then
    require_64bit
  elif [ ! "$compatible1" ] || [ ! "$compatible2" ]; then
    incompatibility
    sleep 1
  else
    compatibility
    ui_print " "
    sleep 1
  fi
}

restore() {
  backup=.bak
  filecontexts=$ven/etc/selinux/vendor_file_contexts
  servicecontexts=$ven/etc/selinux/vendor_hwservice_contexts
  manifest=$sys/etc/vintf/manifest.xml
  for file in $filecontexts $servicecontexts $manifest; do
    if [ -e "$file$backup" ]; then
      mv -f $file$backup $file
    fi
  done
}

register_contexts() {
  ui_print "• Registering file contexts..."
  ui_print "• 注册文件上下文..."
  sleep 1
  filecontexts=$(find $ven/etc -type f -name "vendor_file_contexts")
  servicecontexts=$(find $ven/etc -type f -name "vendor_hwservice_contexts")
  dlbsvcentry='/(vendor|system/vendor)/bin/hw/vendor\.dolby\.hardware\.dms@1\.0-service	 u:object_r:hal_dms_default_exec:s0'
  dlbfileentry='/data/vendor/dolby(/.*)? u:object_r:vendor_data_file:s0'
  dlbhwsvc='vendor.dolby.hardware.dms::IDms          u:object_r:hal_dms_hwservice:s0'
  selinux=$(dirname $filecontexts)
  mount -o rw, remount $selinux 2>/dev/null
  if [ -e "$filecontexts" ]; then
    ui_print "  √ Found: $filecontexts"
    ui_print "  √ 发现：$filecontexts"
    sleep 1
    dms=$(grep "dms" $filecontexts)
    if [ ! "$dms" ]; then
      if [ ! -e "$filecontexts.bak" ]; then
        cp -f $filecontexts $filecontexts.bak
        if [ -e "$filecontexts.bak" ]; then
          ui_print "  √ Backup: $filecontexts.bak"
          ui_print "  √ 备份：$filecontexts.bak"
        else
          ui_print "  X Backup Failed: $filecontexts.bak"
          ui_print "  X 备份失败：$filecontexts.bak"
        fi
        sleep 1
      fi
      echo $dlbsvcentry >> $filecontexts
      echo $dlbfileentry >> $filecontexts
      dms=$(grep "dms" $filecontexts)
      if [ "$dms" ]; then
        ui_print "  √ Dolby file contexts registered"
        ui_print "  √ 杜比文件上下文注册"
      else
        ui_print "  X Unable to register Dolby file contexts"
        ui_print "  X 无法注册杜比文件上下文"
      fi
    else
      ui_print "  √ Dolby file contexts already registered"
      ui_print "  √ 杜比文件上下文已经注册过"
    fi
  else
    ui_print "  X vendor_file_contexts from ramdisk  not applicable for patching"
    ui_print "  X 来自 ramdisk 的 vendor_file_context 不适用于修补"
  fi
  ui_print " "
  sleep 1
  ui_print "• Registering hwservice context..."
  ui_print "• 注册 hwservice 上下文..."
  sleep 1
  if [ -e "$servicecontexts" ]; then
    ui_print "  √ Found: $servicecontexts"
    ui_print "  √ 发现：$servicecontexts"
    sleep 1
    dms=$(grep "dms" $servicecontexts)
    if [ ! "$dms" ]; then
      if [ ! -e "$servicecontexts.bak" ]; then
        cp -f $servicecontexts $servicecontexts.bak
        if [ -e "$servicecontexts.bak" ]; then
          ui_print "  √ Backup: $servicecontexts.bak"
          ui_print "  √ 备份：$servicecontexts.bak"
        else
          ui_print "  X Backup Failed: $servicecontexts.bak"
          ui_print "  X 备份失败：$servicecontexts.bak"
        fi
        sleep 1
      fi
      echo $dlbhwsvc >> $servicecontexts
      dms=$(grep "dms" $servicecontexts)
      if [ "$dms" ]; then
        ui_print "  √ Dolby hwservice context registered"
        ui_print "  √ 杜比 hwservice 上下文注册"
      else
        ui_print "  X Unable to register Dolby hwservice context"
        ui_print "  X 无法注册杜比 hwservice 上下文"
      fi
    else
      ui_print "  √ Dolby hwservice context already registered"
      ui_print "  √ 杜比 hwservice 上下文已经注册过"
    fi
  else
    ui_print "  X vendor_hwservice_contexts from ramdisk not applicable for patching."
    ui_print "  X 来自 ramdisk 的 vendor_hwservice_context 不适用于修补"
  fi
  ui_print " "
  sleep 1
}

register_service() {
  ui_print "• Registering Dolby service..."
  ui_print "• 注册杜比服务..."
  sleep 1
  manifest=$(find $sys/etc -type f -name "manifest.xml")
  vintf=$(dirname $manifest)
  mount -o rw, remount $vintf 2>/dev/null
  if [ -e "$manifest" ]; then
    ui_print "  √ Found: $manifest"
    ui_print "  √ 发现：$manifest"
    sleep 1
    dms=$(grep "dms" $manifest)
    if [ ! "$dms" ]; then
      if [ ! -e "$manifest.bak" ]; then
        cp -f $manifest $manifest.bak
        if [ -e "$manifest.bak" ]; then
          ui_print "  √ Backup: $manifest.bak"
          ui_print "  √ 备份：$manifest.bak"
        else
          ui_print "  X Backup Failed: $manifest.bak"
          ui_print "  X 备份失败：$manifest.bak"
        fi
        sleep 1
      fi
      sed -i '1,/^    <hal format=\"hidl\">/s/^    <hal format=\"hidl\">/    <hal format=\"hidl\">\n        <name>vendor.dolby.hardware.dms<\/name>\n        <transport>hwbinder<\/transport>\n        <version>1.0<\/version>\n        <interface>\n            <name>IDms<\/name>\n            <instance>default<\/instance>\n        <\/interface>\n        <fqname>@1.0::IDms\/default<\/fqname>\n    <\/hal>\n    <hal format=\"hidl\">/' $manifest
      dms=$(grep "dms" $manifest)
      if [ "$dms" ]; then
        ui_print "  √ DolbyManagerService registered"
        ui_print "  √ 杜比管理服务已注册"
      else
        ui_print "  X Unable to register DolbyManagerService"
        ui_print "  X 无法注册杜比管理服务"
      fi
    else
      ui_print "  √ DolbyManagerService already registered"
      ui_print "  √ 杜比管理服务已经注册过"
    fi
  fi
  ui_print " "
  sleep 1
}

prepare_module() {
  ui_print "• Preparing module..."
  ui_print "• 准备模块..."
  unzip -qq "$ZIPFILE" 'common/*' -d $TMPDIR >&2
  cp -rf $TMPDIR/common/* $MODPATH
  cp -f $TMPDIR/viperfx/system/app/ViPER4AndroidFX/*.apk /data/local/tmp/
  modsys=$MODPATH/system
  modetc=$MODPATH/system/etc
  modven=$MODPATH/system/vendor
  modbin=$MODPATH/system/vendor/bin
  modsvetc=$MODPATH/system/vendor/etc
  modlib=$MODPATH/system/vendor/lib
  modlib64=$MODPATH/system/vendor/lib64
  conflictapp=/data/app/com.pittvandewitt.viperfx*
  viperfx=com.audlabs.viperfx
  viperfxapk=/data/local/tmp/ViPER4AndroidFX.apk
  viperfxapp=/data/app/com.audlabs.viperfx*
  stdc=libstdc++.so
  if [ -d "$conflictapp" ]; then
    pm uninstall com.pittvandewitt.viperfx
  fi
  if [ -d "$viperfxapp" ]; then
    pm uninstall $viperfx
  fi
  if [ ! -e "$ven/lib/$stdc" ] && [ -e "$sys/lib/$stdc" ]; then
    cp -f $sys/lib/$stdc $modlib/
    cp -f $ven/lib64/$stdc $modlib64/
  fi
  ui_print " "
  sleep 1
}

configure_fx() {
  ui_print "• Configuring Dolby Atmos™ , ViPER4Android FX™ and ICE™ effect..."
  ui_print "• 配置杜比全景声，蝰蛇音效和 ICE 的音效数据库文件..."
  acdb=/data/adb/modules*/acdb
  etc=$sys/etc
  svetc=$sys/vendor/etc
  vetc=$ven/etc
  conf=*effects.conf
  xml=*effects.xml
  fx=*effects.*
  if [ ! -d "$acdb" ]; then
    for fxconfig in $etc/$conf; do
      if [ -e "$fxconfig" ]; then
        mkdir -p $modetc
        cp -f $fxconfig $modetc/
      fi
    done
    for fxconfig in $vetc/$conf $vetc/$xml; do
      if [ -e "$fxconfig" ]; then
        cp -f $fxconfig $modsvetc/
      fi
    done
    conf=$(find /data/adb/modules* -type f -name "*audio_effects*.conf")
    xml=$(find /data/adb/modules* -type f -name "*audio_effects*.xml") 
    libraryid=$(cat $MODPATH/acdb.conf | sed -n -e 's/^libraryid=//p')
    libraryname=$(cat $MODPATH/acdb.conf | sed -n -e 's/^libraryname=//p')
    effectid=$(cat $MODPATH/acdb.conf | sed -n -e 's/^effectid=//p')
    effectuuid=$(cat $MODPATH/acdb.conf | sed -n -e 's/^effectuuid=//p')
    libraryid0=$(cat $MODPATH/acdb.conf | sed -n -e 's/^libraryid0=//p')
    libraryname0=$(cat $MODPATH/acdb.conf | sed -n -e 's/^libraryname0=//p')
    effectid0=$(cat $MODPATH/acdb.conf | sed -n -e 's/^effectid0=//p')
    effectuuid0=$(cat $MODPATH/acdb.conf | sed -n -e 's/^effectuuid0=//p')
    libraryid1=$(cat $MODPATH/acdb.conf | sed -n -e 's/^libraryid1=//p')
    libraryname1=$(cat $MODPATH/acdb.conf | sed -n -e 's/^libraryname1=//p')
    effectid1=$(cat $MODPATH/acdb.conf | sed -n -e 's/^effectid1=//p')
    effectuuid1=$(cat $MODPATH/acdb.conf | sed -n -e 's/^effectuuid1=//p')
    musicstream=$(grep "musicstream=true" $MODPATH/acdb.conf)
    for fxconfig in $xml; do
      if [ -e "$fxconfig" ]; then
        effect=$(grep $effectuuid $effectuuid0 $effectuuid1 $fxconfig)
        if [ ! "$effect" ]; then
          sed -i "1,/^    <\/libraries>/s/^    <\/libraries>/        <library name=\"$libraryid\" path=\"$libraryname\"\/>\n    <\/libraries>/" $fxconfig
          sed -i "1,/^    <\/effects>/s/^    <\/effects>/        <effect name=\"$effectid\" library=\"$libraryid\" uuid=\"$effectuuid\"\/>\n    <\/effects>/" $fxconfig
          sed -i "1,/^    <\/libraries>/s/^    <\/libraries>/        <library name=\"$libraryid0\" path=\"$libraryname0\"\/>\n    <\/libraries>/" $fxconfig
          sed -i "1,/^    <\/effects>/s/^    <\/effects>/        <effect name=\"$effectid0\" library=\"$libraryid0\" uuid=\"$effectuuid0\"\/>\n    <\/effects>/" $fxconfig
          sed -i "1,/^    <\/libraries>/s/^    <\/libraries>/        <library name=\"$libraryid1\" path=\"$libraryname1\"\/>\n    <\/libraries>/" $fxconfig
          sed -i "1,/^    <\/effects>/s/^    <\/effects>/        <effect name=\"$effectid1\" library=\"$libraryid1\" uuid=\"$effectuuid1\"\/>\n    <\/effects>/" $fxconfig
          sed -i "1,/^            <apply effect=\"music\_helper\"\/>/s/^            <apply effect=\"music\_helper\"\/>/            <!-- apply effect=\"music\_helper\"\/ -->/" $fxconfig
          sed -i "1,/^            <apply effect=\"notification\_helper\"\/>/s/^            <apply effect=\"notification\_helper\"\/>/            <!-- apply effect=\"notification\_helper\"\/ -->/" $fxconfig
          sa3d=$(grep "sa3d" $fxconfig)
          if [ "$sa3d" ]; then
            sed -i "s/^            <apply effect=\"sa3d\"\/>/            <apply effect=\"sa3d\"\/>\n            <apply effect=\"$effectid\"\/>/g" $fxconfig
            sed -i "s/^            <apply effect=\"sa3d\"\/>/            <apply effect=\"sa3d\"\/>\n            <apply effect=\"$effectid0\"\/>/g" $fxconfig
            sed -i "s/^            <apply effect=\"sa3d\"\/>/            <apply effect=\"sa3d\"\/>\n            <apply effect=\"$effectid1\"\/>/g" $fxconfig
          elif [ "$musicstream" ]; then
            sed -i "s/^        <stream type=\"music\">/        <stream type=\"music\">\n            <apply effect=\"$effectid\"\/>/g" $fxconfig
            sed -i "s/^        <stream type=\"music\">/        <stream type=\"music\">\n            <apply effect=\"$effectid0\"\/>/g" $fxconfig
            sed -i "s/^        <stream type=\"music\">/        <stream type=\"music\">\n            <apply effect=\"$effectid1\"\/>/g" $fxconfig
          fi
        fi
      fi
    done
    for fxconfig in $conf; do
      if [ -e "$fxconfig" ]; then
        effect=$(grep $effectuuid $effectuuid0 $effectuuid1 $fxconfig)
        if [ ! "$effect" ]; then
          sed -i "s/^libraries {/libraries {\n  $libraryid {\n    path \/vendor\/lib\/soundfx\/$libraryname\n  }/" $fxconfig
          sed -i "s/^effects {/effects {\n  $effectid {\n    library $libraryid\n    uuid $effectuuid\n  }/" $fxconfig
          sed -i "s/^libraries {/libraries {\n  $libraryid0 {\n    path \/vendor\/lib\/soundfx\/$libraryname0\n  }/" $fxconfig
          sed -i "s/^effects {/effects {\n  $effectid0 {\n    library $libraryid0\n    uuid $effectuuid0\n  }/" $fxconfig
          sed -i "s/^libraries {/libraries {\n  $libraryid1 {\n    path \/vendor\/lib\/soundfx\/$libraryname1\n  }/" $fxconfig
          sed -i "s/^effects {/effects {\n  $effectid1 {\n    library $libraryid1\n    uuid $effectuuid1\n  }/" $fxconfig
          sed -i "/^        music_helper {/ {;N s/        music_helper {\n        }/#        music_helper {\n#        }/}" $fxconfig
          sed -i "/^        notification_helper {/ {;N s/        notification_helper {\n        }/#        notification_helper {\n#        }/}" $fxconfig
        fi
      fi
    done
  fi
  ui_print " "
  sleep 1
}

finalize_module() {
  ui_print "• Set permissions..."
  ui_print "• 设置权限..."
  set_perm_recursive $MODPATH 0 0 0755 0644
  set_perm_recursive $modbin 0 2000 0755 0755
  chown 0:2000 $modsvetc $modsvetc/dolby $modlib $modlib/soundfx $modlib64 $modlib64/soundfx
  chcon -R u:object_r:vendor_file:s0 $modven
  chcon -R u:object_r:vendor_configs_file:s0 $modsvetc
  chcon u:object_r:hal_dms_default_exec:s0 $modbin/hw/*dolby*
  ui_print " "
  sleep 1
}

tidy_up() {
  ui_print "• Tidying up..."
  ui_print "• 整理..."
  rm -rf $MODPATH/META-INF 2>/dev/null
  rm -f $MODPATH/customize.sh 2>/dev/null
  rm -f $viperfxapk 2>/dev/null
  ui_print " "
  ui_print " "
  sleep 2
}

go() {
  mount_filesystems
  check_compatibility
  restore
  register_contexts
  register_service
  prepare_module
  configure_fx
  finalize_module
  tidy_up
  ui_print "• Done!"
  ui_print "• 完成！"
  sleep 1 && exit 0
}
