Extract string resources

This commit is contained in:
Mygod
2018-01-13 19:53:34 +08:00
parent a77beb39db
commit 11a1e793c9
8 changed files with 110 additions and 48 deletions

View File

@@ -5,6 +5,7 @@ import android.app.Application
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.preference.PreferenceManager import android.preference.PreferenceManager
@@ -16,10 +17,19 @@ class App : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
app = this app = this
updateNotificationChannels()
}
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
updateNotificationChannels()
}
private fun updateNotificationChannels() {
if (Build.VERSION.SDK_INT >= 26) @TargetApi(26) { if (Build.VERSION.SDK_INT >= 26) @TargetApi(26) {
val nm = getSystemService(NotificationManager::class.java) val nm = getSystemService(NotificationManager::class.java)
nm.createNotificationChannel(NotificationChannel(RepeaterService.CHANNEL, nm.createNotificationChannel(NotificationChannel(RepeaterService.CHANNEL,
"Repeater Service", NotificationManager.IMPORTANCE_LOW)) getText(R.string.notification_channel_repeater), NotificationManager.IMPORTANCE_LOW))
nm.deleteNotificationChannel("hotspot") // remove old service channel nm.deleteNotificationChannel("hotspot") // remove old service channel
} }
} }

View File

@@ -48,7 +48,7 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
} }
} }
val ssid @Bindable get() = binder?.service?.ssid ?: "Service inactive" val ssid @Bindable get() = binder?.service?.ssid ?: getText(R.string.repeater_inactive)
val password @Bindable get() = binder?.service?.password ?: "" val password @Bindable get() = binder?.service?.password ?: ""
fun onStatusChanged() { fun onStatusChanged() {
@@ -151,12 +151,12 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
override fun onMenuItemClick(item: MenuItem) = when (item.itemId) { override fun onMenuItemClick(item: MenuItem) = when (item.itemId) {
R.id.wps -> if (binder?.active == true) { R.id.wps -> if (binder?.active == true) {
val dialog = AlertDialog.Builder(context!!) val dialog = AlertDialog.Builder(context!!)
.setTitle("Enter PIN") .setTitle(R.string.repeater_wps_dialog_title)
.setView(R.layout.dialog_wps) .setView(R.layout.dialog_wps)
.setPositiveButton(android.R.string.ok, { dialog, _ -> binder?.startWps((dialog as AppCompatDialog) .setPositiveButton(android.R.string.ok, { dialog, _ -> binder?.startWps((dialog as AppCompatDialog)
.findViewById<EditText>(android.R.id.edit)!!.text.toString()) }) .findViewById<EditText>(android.R.id.edit)!!.text.toString()) })
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.setNeutralButton("Push Button", { _, _ -> binder?.startWps(null) }) .setNeutralButton(R.string.repeater_wps_dialog_pbc, { _, _ -> binder?.startWps(null) })
.create() .create()
dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) dialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
dialog.show() dialog.show()
@@ -164,9 +164,10 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
} else false } else false
R.id.resetGroup -> { R.id.resetGroup -> {
AlertDialog.Builder(context!!) AlertDialog.Builder(context!!)
.setTitle("Reset credentials") .setTitle(R.string.repeater_reset_credentials)
.setMessage("Android system will generate new network name and password next time repeater is activated. This is irreversible.") .setMessage(getString(R.string.repeater_reset_credentials_dialog_message))
.setPositiveButton("Reset", { _, _ -> binder?.resetCredentials() }) .setPositiveButton(R.string.repeater_reset_credentials_dialog_reset,
{ _, _ -> binder?.resetCredentials() })
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.show() .show()
true true

View File

@@ -12,6 +12,7 @@ import android.net.wifi.p2p.WifiP2pManager
import android.os.Binder import android.os.Binder
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.support.annotation.StringRes
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v4.content.LocalBroadcastManager import android.support.v4.content.LocalBroadcastManager
@@ -92,10 +93,10 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
} }
p2pManager.startWps(channel, wps, object : WifiP2pManager.ActionListener { p2pManager.startWps(channel, wps, object : WifiP2pManager.ActionListener {
override fun onSuccess() = Toast.makeText(this@RepeaterService, override fun onSuccess() = Toast.makeText(this@RepeaterService,
if (pin == null) "Please use WPS push button within the next 2 minutes to connect your device." if (pin == null) R.string.repeater_wps_success_pbc else R.string.repeater_wps_success_keypad,
else "PIN registered.", Toast.LENGTH_SHORT).show() Toast.LENGTH_SHORT).show()
override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService, override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService,
"Failed to start WPS (reason: ${formatReason(reason)})", Toast.LENGTH_SHORT).show() formatReason(R.string.repeater_wps_failure, reason), Toast.LENGTH_SHORT).show()
}) })
} }
@@ -108,9 +109,9 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
if (netId == TEMPORARY_NET_ID) return if (netId == TEMPORARY_NET_ID) return
p2pManager.deletePersistentGroup(channel, netId, object : WifiP2pManager.ActionListener { p2pManager.deletePersistentGroup(channel, netId, object : WifiP2pManager.ActionListener {
override fun onSuccess() = Toast.makeText(this@RepeaterService, override fun onSuccess() = Toast.makeText(this@RepeaterService,
"Credentials reset.", Toast.LENGTH_SHORT).show() R.string.repeater_reset_credentials_success, Toast.LENGTH_SHORT).show()
override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService, override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService,
"Failed to reset credentials (reason: ${formatReason(reason)})", Toast.LENGTH_SHORT).show() formatReason(R.string.repeater_reset_credentials_failure, reason), Toast.LENGTH_SHORT).show()
}) })
} }
} }
@@ -141,7 +142,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
} }
} }
} }
private val onVpnUnavailable = Runnable { startFailure("VPN unavailable") } private val onVpnUnavailable = Runnable { startFailure(getString(R.string.repeater_vpn_unavailable)) }
val ssid get() = if (status == Status.ACTIVE) group?.networkName else null val ssid get() = if (status == Status.ACTIVE) group?.networkName else null
val password get() = if (status == Status.ACTIVE) group?.passphrase else null val password get() = if (status == Status.ACTIVE) group?.passphrase else null
@@ -157,13 +158,13 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(ACTION_STATUS_CHANGED)) LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(ACTION_STATUS_CHANGED))
} }
private fun formatReason(reason: Int) = when (reason) { private fun formatReason(@StringRes resId: Int, reason: Int) = getString(resId, when (reason) {
WifiP2pManager.ERROR -> "ERROR" WifiP2pManager.ERROR -> getString(R.string.repeater_failure_reason_error)
WifiP2pManager.P2P_UNSUPPORTED -> "P2P_UNSUPPORTED" WifiP2pManager.P2P_UNSUPPORTED -> getString(R.string.repeater_failure_reason_p2p_unsupported)
WifiP2pManager.BUSY -> "BUSY" WifiP2pManager.BUSY -> getString(R.string.repeater_failure_reason_busy)
WifiP2pManager.NO_SERVICE_REQUESTS -> "NO_SERVICE_REQUESTS" WifiP2pManager.NO_SERVICE_REQUESTS -> getString(R.string.repeater_failure_reason_no_service_requests)
else -> "unknown reason: $reason" else -> getString(R.string.repeater_failure_reason_unknown, reason)
} })
override fun onBind(intent: Intent) = binder override fun onBind(intent: Intent) = binder
@@ -196,7 +197,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
Status.STARTING -> { Status.STARTING -> {
val matcher = patternNetworkInfo.matcher(loggerSu("dumpsys ${Context.WIFI_P2P_SERVICE}") ?: "") val matcher = patternNetworkInfo.matcher(loggerSu("dumpsys ${Context.WIFI_P2P_SERVICE}") ?: "")
when { when {
!matcher.find() -> startFailure("Root unavailable") !matcher.find() -> startFailure(getString(R.string.repeater_root_unavailable))
matcher.group(2) == "true" -> { matcher.group(2) == "true" -> {
unregisterReceiver() unregisterReceiver()
registerReceiver(receiver, intentFilter(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION, registerReceiver(receiver, intentFilter(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
@@ -213,7 +214,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
override fun onSuccess() = doStart() override fun onSuccess() = doStart()
override fun onFailure(reason: Int) { override fun onFailure(reason: Int) {
Toast.makeText(this@RepeaterService, Toast.makeText(this@RepeaterService,
"Failed to remove old P2P group (${formatReason(reason)})", formatReason(R.string.repeater_remove_old_group_failure, reason),
Toast.LENGTH_SHORT).show() Toast.LENGTH_SHORT).show()
} }
}) })
@@ -221,7 +222,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
} }
}) })
} }
else -> startFailure("Wi-Fi direct unavailable") else -> startFailure(getString(R.string.repeater_p2p_unavailable))
} }
} }
Status.ACTIVE -> { Status.ACTIVE -> {
@@ -240,7 +241,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
} }
private fun doStart() = p2pManager.createGroup(channel, object : WifiP2pManager.ActionListener { private fun doStart() = p2pManager.createGroup(channel, object : WifiP2pManager.ActionListener {
override fun onFailure(reason: Int) = startFailure("Failed to create P2P group (${formatReason(reason)})") override fun onFailure(reason: Int) = startFailure(formatReason(R.string.repeater_create_group_failure, reason))
override fun onSuccess() { } // wait for WIFI_P2P_CONNECTION_CHANGED_ACTION to fire override fun onSuccess() { } // wait for WIFI_P2P_CONNECTION_CHANGED_ACTION to fire
}) })
private fun doStart(group: WifiP2pGroup) { private fun doStart(group: WifiP2pGroup) {
@@ -260,7 +261,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
this.group = group this.group = group
binder.data?.onGroupChanged() binder.data?.onGroupChanged()
showNotification(group) showNotification(group)
Log.d(TAG, "P2P connection changed: $info\n$net\n$group") debugLog(TAG, "P2P connection changed: $info\n$net\n$group")
} }
private fun onGroupCreated(info: WifiP2pInfo, group: WifiP2pGroup) { private fun onGroupCreated(info: WifiP2pInfo, group: WifiP2pGroup) {
val owner = info.groupOwnerAddress val owner = info.groupOwnerAddress
@@ -293,7 +294,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
val builder = NotificationCompat.Builder(this, CHANNEL) val builder = NotificationCompat.Builder(this, CHANNEL)
.setWhen(0) .setWhen(0)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary)) .setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.setContentTitle(group?.networkName ?: ssid ?: "Connecting...") .setContentTitle(group?.networkName ?: ssid ?: getString(R.string.repeater_connecting))
.setSmallIcon(R.drawable.ic_device_wifi_tethering) .setSmallIcon(R.drawable.ic_device_wifi_tethering)
.setContentIntent(PendingIntent.getActivity(this, 0, .setContentIntent(PendingIntent.getActivity(this, 0,
Intent(this, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT)) Intent(this, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT))
@@ -307,8 +308,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnListener.C
override fun onSuccess() = clean() override fun onSuccess() = clean()
override fun onFailure(reason: Int) { override fun onFailure(reason: Int) {
if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone if (reason == WifiP2pManager.BUSY) clean() else { // assuming it's already gone
Toast.makeText(this@RepeaterService, "Failed to remove P2P group (${formatReason(reason)})", Toast.makeText(this@RepeaterService,
Toast.LENGTH_SHORT).show() formatReason(R.string.repeater_remove_group_failure, reason), Toast.LENGTH_SHORT).show()
status = Status.ACTIVE status = Status.ACTIVE
LocalBroadcastManager.getInstance(this@RepeaterService).sendBroadcast(Intent(ACTION_STATUS_CHANGED)) LocalBroadcastManager.getInstance(this@RepeaterService).sendBroadcast(Intent(ACTION_STATUS_CHANGED))
} }

View File

@@ -42,7 +42,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Network name" android:text="@string/repeater_ssid"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"/> android:textAppearance="@style/TextAppearance.AppCompat.Subhead"/>
<Space <Space
@@ -65,7 +65,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_column="0" android:layout_column="0"
android:layout_row="1" android:layout_row="1"
android:text="Password" android:text="@string/repeater_password"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"/> android:textAppearance="@style/TextAppearance.AppCompat.Subhead"/>
<TextView <TextView
@@ -83,7 +83,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:text="Connected devices" android:text="@string/repeater_connected_devices"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"/> android:textAppearance="@style/TextAppearance.AppCompat.Medium"/>
<View <View

View File

@@ -4,12 +4,12 @@
<item <item
android:id="@+id/navigation_repeater" android:id="@+id/navigation_repeater"
android:icon="@drawable/ic_device_network_wifi" android:icon="@drawable/ic_device_network_wifi"
android:title="Repeater"/> android:title="@string/title_repeater"/>
<item <item
android:id="@+id/navigation_tethering" android:id="@+id/navigation_tethering"
android:icon="@drawable/ic_device_wifi_tethering" android:icon="@drawable/ic_device_wifi_tethering"
android:title="Tethering"/> android:title="@string/title_tethering"/>
<item <item
android:id="@+id/navigation_settings" android:id="@+id/navigation_settings"

View File

@@ -3,8 +3,8 @@
<item <item
android:id="@+id/wps" android:id="@+id/wps"
android:title="WPS"/> android:title="@string/repeater_wps"/>
<item <item
android:id="@+id/resetGroup" android:id="@+id/resetGroup"
android:title="Reset credentials"/> android:title="@string/repeater_reset_credentials"/>
</menu> </menu>

View File

@@ -1,12 +1,62 @@
<resources> <resources>
<string name="app_name">VPN Hotspot</string> <string name="app_name">VPN Hotspot</string>
<string name="title_repeater">Repeater</string>
<string name="title_tethering">Tethering</string>
<string name="title_settings">Settings</string> <string name="title_settings">Settings</string>
<string name="repeater_ssid">Network name</string>
<string name="repeater_password">Password</string>
<string name="repeater_connected_devices">Connected devices</string>
<string name="repeater_wps">WPS</string>
<string name="repeater_wps_dialog_title">Enter PIN</string>
<string name="repeater_wps_dialog_pbc">Push Button</string>
<string name="repeater_wps_success_pbc">Please use WPS push button within the next 2 minutes to connect your
device.</string>
<string name="repeater_wps_success_keypad">PIN registered.</string>
<string name="repeater_wps_failure">Failed to start WPS (reason: %s)</string>
<string name="repeater_reset_credentials">Reset credentials</string>
<string name="repeater_reset_credentials_dialog_message">Android system will generate new network name and password
next time repeater is activated. This is irreversible.</string>
<string name="repeater_reset_credentials_dialog_reset">Reset</string>
<string name="repeater_reset_credentials_success">Credentials reset.</string>
<string name="repeater_reset_credentials_failure">Failed to reset credentials (reason: %s)</string>
<string name="repeater_inactive">Service inactive</string>
<string name="repeater_connecting">Connecting…</string>
<string name="repeater_vpn_unavailable">VPN unavailable, please enable any VPN</string>
<string name="repeater_root_unavailable">Root unavailable</string>
<string name="repeater_p2p_unavailable">Wi-Fi direct unavailable</string>
<string name="repeater_create_group_failure">Failed to create P2P group (reason: %s)</string>
<string name="repeater_remove_group_failure">Failed to remove P2P group (reason: %s)</string>
<string name="repeater_remove_old_group_failure">Failed to remove old P2P group (reason: %s)</string>
<string name="repeater_failure_reason_error">internal error</string>
<string name="repeater_failure_reason_p2p_unsupported">Wi-Fi direct unsupported</string>
<string name="repeater_failure_reason_busy">framework is busy</string>
<string name="repeater_failure_reason_no_service_requests">no service requests added</string>
<string name="repeater_failure_reason_unknown">unknown reason #%d</string>
<string name="tethering_no_interfaces"><![CDATA[To use this feature, turn on any <a href=&quot;#&quot;>system
tethering</a> first.]]></string>
<string name="settings_service">Service</string>
<string name="settings_service_dns">Downstream DNS server:port</string>
<string name="settings_service_clean">Clean routing rules</string>
<string name="settings_service_clean_summary">Only use after having shut down everything</string>
<string name="settings_misc">Misc</string>
<string name="settings_misc_logcat">Export logcat</string>
<string name="settings_misc_logcat_summary">Such useful very wow</string>
<string name="settings_misc_source">View on GitHub</string>
<string name="settings_misc_source_summary">Star, submit issues and contribute</string>
<string name="settings_misc_donate">Donate</string>
<string name="settings_misc_donate_summary">I love money</string>
<string name="notification_channel_repeater">Repeater Service</string>
<plurals name="notification_connected_devices"> <plurals name="notification_connected_devices">
<item quantity="one">1 connected device</item> <item quantity="one">1 connected device</item>
<item quantity="other">%d connected devices</item> <item quantity="other">%d connected devices</item>
</plurals> </plurals>
<string name="exception_interface_not_found">Fatal: Downstream interface not found</string> <string name="exception_interface_not_found">Fatal: Downstream interface not found</string>
<string name="tethering_no_interfaces"><![CDATA[To use this feature, turn on any <a href=&quot;#&quot;>system
tethering</a> first.]]></string>
<string name="noisy_su_failure">Something went wrong, please check logcat.</string> <string name="noisy_su_failure">Something went wrong, please check logcat.</string>
</resources> </resources>

View File

@@ -1,30 +1,30 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory <PreferenceCategory
android:title="Service"> android:title="@string/settings_service">
<AutoSummaryEditTextPreference <AutoSummaryEditTextPreference
android:key="service.dns" android:key="service.dns"
android:title="Downstream DNS server:port" android:title="@string/settings_service_dns"
android:summary="%s" android:summary="%s"
android:defaultValue="8.8.8.8:53"/> android:defaultValue="8.8.8.8:53"/>
<Preference <Preference
android:key="service.clean" android:key="service.clean"
android:title="Clean routing rules" android:title="@string/settings_service_clean"
android:summary="Only use after having shut down everything"/> android:summary="@string/settings_service_clean_summary"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="Misc"> android:title="@string/settings_misc">
<Preference <Preference
android:key="misc.logcat" android:key="misc.logcat"
android:title="Export logcat" android:title="@string/settings_misc_logcat"
android:summary="Such useful very wow"/> android:summary="@string/settings_misc_logcat_summary"/>
<Preference <Preference
android:key="misc.source" android:key="misc.source"
android:title="View on GitHub" android:title="@string/settings_misc_source"
android:summary="Star, submit issues and contribute"/> android:summary="@string/settings_misc_source_summary"/>
<Preference <Preference
android:key="misc.donate" android:key="misc.donate"
android:title="Donate" android:title="@string/settings_misc_donate"
android:summary="I love money"/> android:summary="@string/settings_misc_donate_summary"/>
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>