<lambda>null1 package leakcanary.internal.navigation
2
3 import android.app.Activity
4 import android.content.Intent
5 import android.os.Build.VERSION.SDK_INT
6 import android.os.Bundle
7 import android.os.Parcelable
8 import android.view.Menu
9 import android.view.MenuItem
10 import android.view.View
11 import android.view.ViewGroup
12 import android.view.animation.AnimationUtils.loadAnimation
13 import com.squareup.leakcanary.core.R
14
15 /**
16 * A simple backstack navigating activity
17 */
18 internal abstract class NavigatingActivity : Activity() {
19
20 private lateinit var backstack: ArrayList<BackstackFrame>
21 private lateinit var currentScreen: Screen
22
23 private lateinit var container: ViewGroup
24 private lateinit var currentView: View
25
26 var onCreateOptionsMenu = NO_MENU
27
28 fun installNavigation(
29 savedInstanceState: Bundle?,
30 container: ViewGroup
31 ) {
32 this.container = container
33
34 if (savedInstanceState == null) {
35 backstack = ArrayList()
36 val screens = parseIntentScreens(intent)
37 currentScreen = if (screens.isNotEmpty()) {
38 screens.dropLast(1)
39 .forEach { screen ->
40 backstack.add(BackstackFrame(screen))
41 }
42 screens.last()
43 } else {
44 getLauncherScreen()
45 }
46 } else {
47 currentScreen = savedInstanceState.getSerializable("currentScreen") as Screen
48 @Suppress("UNCHECKED_CAST")
49 backstack = savedInstanceState.getParcelableArrayList<Parcelable>(
50 "backstack"
51 ) as ArrayList<BackstackFrame>
52 }
53 currentView = currentScreen.createView(container)
54 container.addView(currentView)
55
56 actionBar?.run {
57 setHomeButtonEnabled(true)
58 setDisplayHomeAsUpEnabled(true)
59 }
60 screenUpdated()
61 }
62
63 override fun onNewIntent(intent: Intent) {
64 val screens = parseIntentScreens(intent)
65 if (screens.isNotEmpty()) {
66 backstack.clear()
67 screens.dropLast(1)
68 .forEach { screen ->
69 backstack.add(BackstackFrame(screen))
70 }
71 goTo(screens.last())
72 }
73 }
74
75 abstract fun parseIntentScreens(intent: Intent): List<Screen>
76
77 open fun getLauncherScreen(): Screen {
78 TODO("Launcher activities should override getLauncherScreen()")
79 }
80
81 public override fun onSaveInstanceState(outState: Bundle) {
82 super.onSaveInstanceState(outState)
83 outState.putSerializable("currentScreen", currentScreen)
84 outState.putParcelableArrayList("backstack", backstack)
85 }
86
87 override fun onBackPressed() {
88 if (backstack.size > 0) {
89 goBack()
90 return
91 }
92 super.onBackPressed()
93 }
94
95 fun resetTo(screen: Screen) {
96 onCreateOptionsMenu = NO_MENU
97
98 currentView.startAnimation(loadAnimation(this, R.anim.leak_canary_exit_alpha))
99 container.removeView(currentView)
100 currentView.notifyScreenExiting()
101
102 backstack.clear()
103
104 currentScreen = screen
105 currentView = currentScreen.createView(container)
106 currentView.startAnimation(loadAnimation(this, R.anim.leak_canary_enter_alpha))
107 container.addView(currentView)
108
109 screenUpdated()
110 }
111
112 fun goTo(screen: Screen) {
113 onCreateOptionsMenu = NO_MENU
114
115 currentView.startAnimation(loadAnimation(this, R.anim.leak_canary_exit_forward))
116 container.removeView(currentView)
117 currentView.notifyScreenExiting()
118 val backstackFrame = BackstackFrame(currentScreen, currentView)
119 backstack.add(backstackFrame)
120
121 currentScreen = screen
122 currentView = currentScreen.createView(container)
123 currentView.startAnimation(loadAnimation(this, R.anim.leak_canary_enter_forward))
124 container.addView(currentView)
125
126 screenUpdated()
127 }
128
129 fun refreshCurrentScreen() {
130 onCreateOptionsMenu = NO_MENU
131 container.removeView(currentView)
132 currentView.notifyScreenExiting()
133 currentView = currentScreen.createView(container)
134 container.addView(currentView)
135
136 screenUpdated()
137 }
138
139 fun goBack() {
140 onCreateOptionsMenu = NO_MENU
141
142 currentView.startAnimation(loadAnimation(this, R.anim.leak_canary_exit_backward))
143 container.removeView(currentView)
144 currentView.notifyScreenExiting()
145
146 val latest = backstack.removeAt(backstack.size - 1)
147 currentScreen = latest.screen
148 currentView = currentScreen.createView(container)
149 currentView.startAnimation(loadAnimation(this, R.anim.leak_canary_enter_backward))
150 container.addView(currentView, 0)
151 latest.restore(currentView)
152
153 screenUpdated()
154 }
155
156 private fun screenUpdated() {
157 invalidateOptionsMenu()
158 if (SDK_INT >= 18) {
159 actionBar?.run {
160 val goBack = backstack.size > 0
161 val indicator = if (goBack) 0 else android.R.drawable.ic_menu_close_clear_cancel
162 setHomeAsUpIndicator(indicator)
163 }
164 }
165 onNewScreen(currentScreen)
166 }
167
168 protected open fun onNewScreen(screen: Screen) {
169 }
170
171 override fun onCreateOptionsMenu(menu: Menu): Boolean {
172 onCreateOptionsMenu.invoke(menu)
173 return true
174 }
175
176 override fun onOptionsItemSelected(item: MenuItem): Boolean =
177 when (item.itemId) {
178 android.R.id.home -> {
179 onBackPressed()
180 true
181 }
182 else -> super.onOptionsItemSelected(item)
183 }
184
185 override fun onDestroy() {
186 super.onDestroy()
187 currentView.notifyScreenExiting()
188 }
189
190 companion object {
191 val NO_MENU: ((Menu) -> Unit) = {}
192 }
193 }
194