Skip to content

Commit

Permalink
Quick Setting Tile (#7)
Browse files Browse the repository at this point in the history
* Move to feature packages

* Add Quick Settings Tile to help toggle the proxy faster

* Use Proxy Stub object

* Add TODO

* Use real proxy in tests until we have a way to manually set it up
  • Loading branch information
fmontesino authored Jul 2, 2020
1 parent 065aeab commit e0b4afe
Show file tree
Hide file tree
Showing 19 changed files with 474 additions and 52 deletions.
15 changes: 14 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
</intent-filter>
</activity>

<receiver android:name=".widget.ToggleWidgetProvider">
<!-- Home Screen Widget -->
<receiver android:name=".feature.widget.ToggleWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.ACTION_WIDGET_RECEIVER" />
Expand All @@ -32,6 +33,18 @@
android:name="android.appwidget.provider"
android:resource="@xml/toggle_widget" />
</receiver>

<!-- Quick Settings Tile -->
<service
android:name=".feature.tile.ProxyTileService"
android:icon="@drawable/ic_proxy"
android:label="Custom Proxy"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">

<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kinandcarta.create.proxytoggle.broadcast

import com.kinandcarta.create.proxytoggle.feature.widget.broadcast.WidgetProxyUpdateListener
import javax.inject.Inject

class ProxyUpdateListenerProviderImpl @Inject constructor(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.kinandcarta.create.proxytoggle.view.manager
package com.kinandcarta.create.proxytoggle.feature.manager.view

sealed class ProxyManagerEvent {
object InvalidAddress : ProxyManagerEvent()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.kinandcarta.create.proxytoggle.feature.manager.view

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.kinandcarta.create.proxytoggle.databinding.FragmentProxyManagerBinding
import com.kinandcarta.create.proxytoggle.feature.manager.viewmodel.ProxyManagerViewModel
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class ProxyManagerFragment : Fragment() {

companion object {
fun newInstance() =
ProxyManagerFragment()

const val FI_ADDRESS = "192.168.1.215"
const val FI_PORT = "8888"
}

private val binding by lazy { FragmentProxyManagerBinding.inflate(layoutInflater) }
private val viewModel: ProxyManagerViewModel by viewModels()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = binding.root

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.proxyState.observe(viewLifecycleOwner, Observer { proxyState ->
when (proxyState) {
is ProxyState.Enabled -> showProxyEnabled(proxyState.address, proxyState.port)
is ProxyState.Disabled -> showProxyDisabled()
}
})
}

private fun showProxyEnabled(proxyAddress: String, proxyPort: String) {
with(binding) {
address.text = proxyAddress
port.text = proxyPort
status.text = "Enabled"
button.text = "Disable proxy"
button.setOnClickListener { viewModel.disableProxy() }
}
}

private fun showProxyDisabled() {
with(binding) {
status.text = "Disabled"
button.text = "Enable proxy"
button.setOnClickListener {
viewModel.enableProxy(
FI_ADDRESS,
FI_PORT
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.kinandcarta.create.proxytoggle.view.manager
package com.kinandcarta.create.proxytoggle.feature.manager.view

sealed class ProxyState {
data class Enabled(val address: String, val port: String) : ProxyState()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.kinandcarta.create.proxytoggle.viewmodel
package com.kinandcarta.create.proxytoggle.feature.manager.viewmodel

import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.Transformations
Expand All @@ -7,8 +7,8 @@ import com.kinandcarta.create.proxytoggle.android.DeviceSettingsManager
import com.kinandcarta.create.proxytoggle.android.ProxyValidator
import com.kinandcarta.create.proxytoggle.extensions.SingleLiveEvent
import com.kinandcarta.create.proxytoggle.model.Proxy
import com.kinandcarta.create.proxytoggle.view.manager.ProxyManagerEvent
import com.kinandcarta.create.proxytoggle.view.manager.ProxyState
import com.kinandcarta.create.proxytoggle.feature.manager.view.ProxyManagerEvent
import com.kinandcarta.create.proxytoggle.feature.manager.view.ProxyState

class ProxyManagerViewModel @ViewModelInject constructor(
private val deviceSettingsManager: DeviceSettingsManager,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.kinandcarta.create.proxytoggle.feature.tile

import android.os.Build
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import androidx.annotation.RequiresApi
import com.kinandcarta.create.proxytoggle.android.DeviceSettingsManager
import com.kinandcarta.create.proxytoggle.model.Proxy
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@RequiresApi(Build.VERSION_CODES.N)
@AndroidEntryPoint
class ProxyTileService : TileService() {

@Inject
lateinit var deviceSettingsManager: DeviceSettingsManager

override fun onClick() {
toggleProxy()
}

override fun onStartListening() {
updateTile()
}

private fun toggleProxy() {
val proxy = deviceSettingsManager.proxySetting.value ?: Proxy.Disabled
if (proxy.isEnabled) {
deviceSettingsManager.disableProxy()
} else {
// TODO Take this from SharedPrefs once the user is able to input
deviceSettingsManager.enableProxy(Proxy("192.168.1.215", "8888"))
}
updateTile()
}

private fun updateTile() {
val proxy = deviceSettingsManager.proxySetting.value ?: Proxy.Disabled
if (proxy.isEnabled) {
qsTile.apply {
label = proxy.toString()
state = Tile.STATE_ACTIVE
updateTile()
}
} else {
qsTile.apply {
label = "Proxy Disabled"
state = Tile.STATE_INACTIVE
updateTile()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.kinandcarta.create.proxytoggle.feature.widget

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.view.View
import android.widget.RemoteViews
import com.kinandcarta.create.proxytoggle.R
import com.kinandcarta.create.proxytoggle.android.DeviceSettingsManager
import com.kinandcarta.create.proxytoggle.model.Proxy
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.internal.managers.BroadcastReceiverComponentManager
import dagger.hilt.internal.UnsafeCasts
import javax.inject.Inject

@AndroidEntryPoint
class ToggleWidgetProvider : AppWidgetProvider() {

// TODO Handle the scenario when the user adds the widget before the proxy

companion object {
private const val ACTION_PROXY_ENABLE = "Enable Proxy"
private const val ACTION_PROXY_DISABLE = "Disable Proxy"
}

@Inject
lateinit var deviceSettingsManager: DeviceSettingsManager

override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
appWidgetIds.forEach { appWidgetId ->
// Instantiate the RemoteViews object for the app widget layout.
val remoteView = RemoteViews(context.packageName, R.layout.widget_toggle)

val proxy = deviceSettingsManager.proxySetting.value ?: Proxy.Disabled

if (proxy.isEnabled) {
buildEnabledView(remoteView, proxy, context)
} else {
buildDisabledView(remoteView, context)
}

appWidgetManager.updateAppWidget(appWidgetId, remoteView)
}
}

private fun buildDisabledView(remoteView: RemoteViews, context: Context) {
remoteView.apply {
setTextViewText(R.id.button, "Enable")
setViewVisibility(R.id.proxy, View.GONE)
setOnClickPendingIntent(
R.id.button,
ACTION_PROXY_ENABLE.asPendingIntent(context)
)
}
}

private fun buildEnabledView(remoteView: RemoteViews, proxy: Proxy, context: Context) {
remoteView.apply {
setTextViewText(R.id.button, "Disable")
setViewVisibility(R.id.proxy, View.VISIBLE)
setTextViewText(R.id.proxy, proxy.toString())
setOnClickPendingIntent(
R.id.button,
ACTION_PROXY_DISABLE.asPendingIntent(context)
)
}
}

override fun onReceive(context: Context, intent: Intent) {
// Hilt has some issues injecting onReceive() BroadcastReceivers:
// More info: https://github.com/google/dagger/issues/1918
// TODO Remove me when Hilt is updated
(BroadcastReceiverComponentManager.generatedComponent(context) as
ToggleWidgetProvider_GeneratedInjector).injectToggleWidgetProvider(
UnsafeCasts.unsafeCast<ToggleWidgetProvider>(this)
)

when (intent.action) {
ACTION_PROXY_ENABLE -> enableProxy()
ACTION_PROXY_DISABLE -> disableProxy()
else -> super.onReceive(context, intent)
}
}

private fun enableProxy() {
// TODO Take this from SharedPrefs once the user is able to input
deviceSettingsManager.enableProxy(Proxy("192.168.1.215", "8888"))
}

private fun disableProxy() {
deviceSettingsManager.disableProxy()
}

private fun String.asPendingIntent(context: Context): PendingIntent {
val intent = Intent(context, ToggleWidgetProvider::class.java).apply {
action = this@asPendingIntent
}
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.kinandcarta.create.proxytoggle.feature.widget.broadcast

import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import com.kinandcarta.create.proxytoggle.broadcast.ProxyUpdateListener
import com.kinandcarta.create.proxytoggle.feature.widget.ToggleWidgetProvider
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject

class WidgetProxyUpdateListener @Inject constructor(
@ApplicationContext private val context: Context
) : ProxyUpdateListener {

override fun onProxyUpdate() {
val intent = Intent(context, ToggleWidgetProvider::class.java).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
}
val appWidgetManager = AppWidgetManager.getInstance(context)
val widgetComponent = ComponentName(context, ToggleWidgetProvider::class.java)
val ids = appWidgetManager.getAppWidgetIds(widgetComponent)
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
context.sendBroadcast(intent)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.kinandcarta.create.proxytoggle.view
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.kinandcarta.create.proxytoggle.R
import com.kinandcarta.create.proxytoggle.view.manager.ProxyManagerFragment
import com.kinandcarta.create.proxytoggle.feature.manager.view.ProxyManagerFragment
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.kinandcarta.create.proxytoggle.databinding.FragmentProxyManagerBinding
import com.kinandcarta.create.proxytoggle.viewmodel.ProxyManagerViewModel
import com.kinandcarta.create.proxytoggle.feature.manager.view.ProxyState
import com.kinandcarta.create.proxytoggle.feature.manager.viewmodel.ProxyManagerViewModel
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand Down
50 changes: 50 additions & 0 deletions app/src/main/res/drawable/ic_proxy.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="225dp"
android:height="225dp"
android:viewportWidth="225"
android:viewportHeight="225">
<path
android:pathData="M95,6.4c-10.3,3.1 -18.8,7.6 -25.1,13.4 -3.7,3.4 -5.1,5.3 -4.6,6.5 1,2.7 3.2,2 10,-3.2 14.9,-11.2 31.5,-15.3 49.3,-12 7.9,1.4 20.8,7.6 26.6,12.8 4.9,4.4 8.2,5.2 9.3,2.3 0.9,-2.3 -7.2,-9.5 -16.3,-14.5 -14.6,-7.8 -33.9,-9.9 -49.2,-5.3z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M106,23.1c-8.4,1.2 -16.6,4.6 -22.3,9.3 -5.8,4.7 -6.8,6.9 -3.8,8.5 1.6,0.9 2.7,0.5 6.3,-2.6 2.3,-2 6.8,-4.8 9.8,-6.2 4.9,-2.3 6.8,-2.6 16.5,-2.6 9.9,-0 11.6,0.3 16.7,2.7 3.2,1.5 7.8,4.3 10.4,6.2 3.6,2.8 5,3.3 6,2.5 2.5,-2.1 1.4,-4.7 -3.3,-8.2 -11.6,-8.4 -23.4,-11.5 -36.3,-9.6z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M104.4,42.1c-4.4,1.3 -12.8,7.1 -13.2,9.1 -0.2,0.9 0.5,2.1 1.6,2.7 1.4,0.8 2.9,0.2 6.8,-2.5 8.6,-6 19.4,-5.7 27.6,0.7 4.1,3.2 6.8,3 6.8,-0.6 0,-2.8 -5.9,-7.1 -12.6,-9.1 -5.2,-1.6 -12.3,-1.7 -17,-0.3z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M104.4,61.4c-2.9,2.9 -3.4,4.1 -3.4,8 0,5.3 2,9 6.1,11.2 8.3,4.2 17.9,-1.4 17.9,-10.6 0,-7.1 -5.3,-12 -13.1,-12 -3.3,-0 -4.7,0.6 -7.5,3.4z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M109,95.5l0,5.5 -29.7,0.2 -29.8,0.3 -0.3,10.7 -0.3,10.8 3.1,-0 3,-0 0,-8 0,-8 57.5,-0 57.5,-0 0,8 0,8 3,-0 3,-0 0,-10.9c0,-9 -0.3,-11 -1.6,-11.5 -0.9,-0.3 -14.4,-0.6 -30,-0.6l-28.4,-0 0,-5 0,-5 -3.5,-0 -3.5,-0 0,5.5z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M5.7,130.8c-1.6,0.3 -1.7,3.2 -1.5,35l0.3,34.7 46.7,0.3c44,0.2 46.8,0.1 47.7,-1.6 1.1,-2.1 1.4,-65.1 0.3,-66.9 -0.6,-1 -11.6,-1.3 -46.3,-1.5 -25.1,-0.2 -46.3,-0.2 -47.2,-0zM82.8,147.2c1.8,1.8 1.7,35.2 -0.2,36.7 -0.9,0.8 -10.1,1.1 -31.7,0.9l-30.4,-0.3 -0.3,-17.9c-0.2,-12.3 0.1,-18.3 0.9,-19.2 1.6,-1.9 59.8,-2.1 61.7,-0.2z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M27,166l0,12 25,-0 25,-0 0,-12 0,-12 -25,-0 -25,-0 0,12z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M125.5,132.2c-0.3,0.7 -0.4,16.4 -0.3,34.8l0.3,33.5 47.5,-0 47.5,-0 0,-34.5 0,-34.5 -47.3,-0.3c-37.4,-0.2 -47.4,-0 -47.7,1zM204,147c1.2,0.7 1.6,4 1.8,16.7 0.2,9.4 -0.1,16.9 -0.7,18.6l-1.1,2.7 -30.3,-0c-22.2,-0 -30.6,-0.3 -31.5,-1.2 -0.8,-0.8 -1.2,-6.3 -1.2,-18.3 0,-12 0.4,-17.5 1.2,-18.3 1.5,-1.5 59.5,-1.7 61.8,-0.2z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M149,166l0,12 24.5,-0 24.5,-0 0,-12 0,-12 -24.5,-0 -24.5,-0 0,12z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M35.7,211.9c-0.6,2.7 -1.1,3 -4.9,3.3 -3.9,0.3 -4.3,0.6 -4.6,3.1l-0.3,2.7 25.8,-0.2c24.3,-0.3 25.8,-0.4 26.1,-2.2 0.5,-2.4 -1.4,-3.6 -6,-3.6 -3.2,-0 -3.7,-0.3 -4.3,-3l-0.7,-3 -15.3,-0 -15.2,-0 -0.6,2.9z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
<path
android:pathData="M157.4,211.9c-0.6,2.7 -1,3 -5.3,3.3 -4.2,0.3 -4.6,0.5 -4.6,2.8l0,2.5 25.5,-0 25.5,-0 0,-2.5c0,-2.3 -0.4,-2.5 -4.6,-2.8 -4.3,-0.3 -4.7,-0.6 -5.3,-3.3l-0.5,-2.9 -15.1,-0 -15,-0 -0.6,2.9z"
android:fillColor="#000000"
android:strokeColor="#00000000" />
</vector>
Loading

0 comments on commit e0b4afe

Please sign in to comment.