Unverified Commit 045623a8 authored by Filipe de Lima Brito's avatar Filipe de Lima Brito Committed by GitHub

Merge branch 'develop' into feature/save-unfinished-message

parents 3b969743 d4ced11a
...@@ -93,6 +93,7 @@ dependencies { ...@@ -93,6 +93,7 @@ dependencies {
implementation project(':draw') implementation project(':draw')
implementation project(':util') implementation project(':util')
implementation project(':core') implementation project(':core')
implementation project(':suggestions')
implementation libraries.kotlin implementation libraries.kotlin
implementation libraries.coroutines implementation libraries.coroutines
......
...@@ -7,9 +7,9 @@ import android.widget.TextView ...@@ -7,9 +7,9 @@ import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter.CommandSuggestionsViewHolder import chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter.CommandSuggestionsViewHolder
import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder import chat.rocket.android.suggestions.ui.BaseSuggestionViewHolder
import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter import chat.rocket.android.suggestions.ui.SuggestionsAdapter
class CommandSuggestionsAdapter : SuggestionsAdapter<CommandSuggestionsViewHolder>(token = "/", class CommandSuggestionsAdapter : SuggestionsAdapter<CommandSuggestionsViewHolder>(token = "/",
constraint = CONSTRAINT_BOUND_TO_START, threshold = RESULT_COUNT_UNLIMITED) { constraint = CONSTRAINT_BOUND_TO_START, threshold = RESULT_COUNT_UNLIMITED) {
......
...@@ -11,9 +11,9 @@ import chat.rocket.android.R ...@@ -11,9 +11,9 @@ import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder
import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import chat.rocket.android.util.extensions.setVisible import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder import chat.rocket.android.suggestions.ui.BaseSuggestionViewHolder
import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter import chat.rocket.android.suggestions.ui.SuggestionsAdapter
import com.facebook.drawee.view.SimpleDraweeView import com.facebook.drawee.view.SimpleDraweeView
class PeopleSuggestionsAdapter(context: Context) : SuggestionsAdapter<PeopleSuggestionViewHolder>("@") { class PeopleSuggestionsAdapter(context: Context) : SuggestionsAdapter<PeopleSuggestionViewHolder>("@") {
......
...@@ -7,9 +7,9 @@ import android.widget.TextView ...@@ -7,9 +7,9 @@ import android.widget.TextView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter.RoomSuggestionsViewHolder import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter.RoomSuggestionsViewHolder
import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder import chat.rocket.android.suggestions.ui.BaseSuggestionViewHolder
import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter import chat.rocket.android.suggestions.ui.SuggestionsAdapter
class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#") { class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#") {
......
package chat.rocket.android.chatroom.uimodel.suggestion package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
class ChatRoomSuggestionUiModel(text: String, class ChatRoomSuggestionUiModel(text: String,
val fullName: String, val fullName: String,
......
package chat.rocket.android.chatroom.uimodel.suggestion package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
class CommandSuggestionUiModel(text: String, class CommandSuggestionUiModel(text: String,
val description: String, val description: String,
......
package chat.rocket.android.chatroom.uimodel.suggestion package chat.rocket.android.chatroom.uimodel.suggestion
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
class PeopleSuggestionUiModel(val imageUri: String?, class PeopleSuggestionUiModel(val imageUri: String?,
......
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" /> tools:visibility="visible" />
<chat.rocket.android.widget.autocompletion.ui.SuggestionsView <chat.rocket.android.suggestions.ui.SuggestionsView
android:id="@+id/suggestions_view" android:id="@+id/suggestions_view"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
......
...@@ -41,10 +41,6 @@ ...@@ -41,10 +41,6 @@
<dimen name="padding_mention">4dp</dimen> <dimen name="padding_mention">4dp</dimen>
<dimen name="radius_mention">6dp</dimen> <dimen name="radius_mention">6dp</dimen>
<!-- Autocomplete Popup -->
<dimen name="popup_max_height">150dp</dimen>
<dimen name="suggestions_box_max_height">250dp</dimen>
<dimen name="viewer_toolbar_padding">16dp</dimen> <dimen name="viewer_toolbar_padding">16dp</dimen>
<dimen name="viewer_toolbar_title">16sp</dimen> <dimen name="viewer_toolbar_title">16sp</dimen>
......
...@@ -10,7 +10,7 @@ buildscript { ...@@ -10,7 +10,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-rc02' classpath 'com.android.tools.build:gradle:3.2.0-rc03'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath 'com.google.gms:google-services:4.0.2' classpath 'com.google.gms:google-services:4.0.2'
......
include ':app', ':player', ':emoji', ':draw', ':util', ':core' //, ':wear' include ':app', ':player', ':emoji', ':draw', ':util', ':core', ':suggestions' //, ':wear'
\ No newline at end of file \ No newline at end of file
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation libraries.kotlin
implementation libraries.recyclerview
implementation libraries.appCompat
implementation libraries.material
}
androidExtensions {
experimental = true
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
package yampsample.leonardoaramaki.github.com.suggestions;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("yampsample.leonardoaramaki.github.com.suggestions.test", appContext.getPackageName());
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="chat.rocket.android.suggestions" />
package chat.rocket.android.widget.autocompletion.model package chat.rocket.android.suggestions.model
abstract class SuggestionModel(val text: String, // This is the text key for searches, must be unique. abstract class SuggestionModel(val text: String, // This is the text key for searches, must be unique.
val searchList: List<String> = emptyList(), // Where to search for matches. val searchList: List<String> = emptyList(), // Where to search for matches.
...@@ -15,4 +15,4 @@ abstract class SuggestionModel(val text: String, // This is the text key for sea ...@@ -15,4 +15,4 @@ abstract class SuggestionModel(val text: String, // This is the text key for sea
override fun hashCode(): Int { override fun hashCode(): Int {
return text.hashCode() return text.hashCode()
} }
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.repository package chat.rocket.android.suggestions.repository
interface LocalSuggestionProvider { interface LocalSuggestionProvider {
fun find(prefix: String) fun find(prefix: String)
......
package chat.rocket.android.widget.autocompletion.strategy package chat.rocket.android.suggestions.strategy
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
interface CompletionStrategy { interface CompletionStrategy {
fun getItem(prefix: String, position: Int): SuggestionModel fun getItem(prefix: String, position: Int): SuggestionModel
...@@ -8,4 +8,4 @@ interface CompletionStrategy { ...@@ -8,4 +8,4 @@ interface CompletionStrategy {
fun addAll(list: List<SuggestionModel>) fun addAll(list: List<SuggestionModel>)
fun addPinned(list: List<SuggestionModel>) fun addPinned(list: List<SuggestionModel>)
fun size(): Int fun size(): Int
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.strategy.regex package chat.rocket.android.suggestions.strategy.regex
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.strategy.CompletionStrategy import chat.rocket.android.suggestions.strategy.CompletionStrategy
import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter.Companion.RESULT_COUNT_UNLIMITED import chat.rocket.android.suggestions.ui.SuggestionsAdapter.Companion.RESULT_COUNT_UNLIMITED
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
internal class StringMatchingCompletionStrategy(private val threshold: Int = RESULT_COUNT_UNLIMITED) : CompletionStrategy { internal class StringMatchingCompletionStrategy(private val threshold: Int = RESULT_COUNT_UNLIMITED) : CompletionStrategy {
...@@ -46,4 +46,4 @@ internal class StringMatchingCompletionStrategy(private val threshold: Int = RES ...@@ -46,4 +46,4 @@ internal class StringMatchingCompletionStrategy(private val threshold: Int = RES
override fun size(): Int { override fun size(): Int {
return list.size return list.size
} }
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.strategy.trie package chat.rocket.android.suggestions.strategy.trie
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.strategy.CompletionStrategy import chat.rocket.android.suggestions.strategy.CompletionStrategy
import chat.rocket.android.widget.autocompletion.strategy.trie.data.Trie import chat.rocket.android.suggestions.strategy.trie.data.Trie
class TrieCompletionStrategy : CompletionStrategy { class TrieCompletionStrategy : CompletionStrategy {
private val items = mutableListOf<SuggestionModel>() private val items = mutableListOf<SuggestionModel>()
...@@ -28,8 +28,7 @@ class TrieCompletionStrategy : CompletionStrategy { ...@@ -28,8 +28,7 @@ class TrieCompletionStrategy : CompletionStrategy {
} }
override fun addPinned(list: List<SuggestionModel>) { override fun addPinned(list: List<SuggestionModel>) {
} }
override fun size() = items.size override fun size() = items.size
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.strategy.trie.data package chat.rocket.android.suggestions.strategy.trie.data
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
internal class Trie { internal class Trie {
private val root = TrieNode(' ') private val root = TrieNode(' ')
...@@ -67,4 +67,4 @@ internal class Trie { ...@@ -67,4 +67,4 @@ internal class Trie {
} }
fun getCount() = count fun getCount() = count
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.strategy.trie.data package chat.rocket.android.suggestions.strategy.trie.data
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
internal class TrieNode(internal var data: Char, internal class TrieNode(internal var data: Char,
internal var parent: TrieNode? = null, internal var parent: TrieNode? = null,
...@@ -44,4 +44,4 @@ internal class TrieNode(internal var data: Char, ...@@ -44,4 +44,4 @@ internal class TrieNode(internal var data: Char,
} }
override fun toString(): String = if (parent == null) "" else "${parent.toString()}$data" override fun toString(): String = if (parent == null) "" else "${parent.toString()}$data"
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.ui package chat.rocket.android.suggestions.ui
import androidx.recyclerview.widget.RecyclerView
import android.view.View import android.view.View
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.suggestions.model.SuggestionModel
abstract class BaseSuggestionViewHolder(view: View) : RecyclerView.ViewHolder(view) { abstract class BaseSuggestionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
abstract fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?) abstract fun bind(item: SuggestionModel, itemClickListener: SuggestionsAdapter.ItemClickListener?)
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.ui package chat.rocket.android.suggestions.ui
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.WindowManager import android.view.WindowManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R import chat.rocket.android.suggestions.R
internal class PopupRecyclerView : RecyclerView { internal class PopupRecyclerView : RecyclerView {
private var displayWidth: Int = 0 private var displayWidth: Int = 0
...@@ -38,4 +38,4 @@ internal class PopupRecyclerView : RecyclerView { ...@@ -38,4 +38,4 @@ internal class PopupRecyclerView : RecyclerView {
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l + 40, t, r - 40, b) super.onLayout(changed, l + 40, t, r - 40, b)
} }
} }
\ No newline at end of file
package chat.rocket.android.widget.autocompletion.ui package chat.rocket.android.suggestions.ui
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.android.widget.autocompletion.strategy.CompletionStrategy import chat.rocket.android.suggestions.strategy.CompletionStrategy
import chat.rocket.android.widget.autocompletion.strategy.regex.StringMatchingCompletionStrategy import chat.rocket.android.suggestions.strategy.regex.StringMatchingCompletionStrategy
import java.lang.reflect.Type import java.lang.reflect.Type
import kotlin.properties.Delegates import kotlin.properties.Delegates
...@@ -32,10 +32,10 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>( ...@@ -32,10 +32,10 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>(
// The strategy used for suggesting completions. // The strategy used for suggesting completions.
private val strategy: CompletionStrategy = StringMatchingCompletionStrategy(resultsThreshold) private val strategy: CompletionStrategy = StringMatchingCompletionStrategy(resultsThreshold)
// Current input term to look up for suggestions. // Current input term to look up for suggestions.
private var currentTerm: String by Delegates.observable("", { _, _, newTerm -> private var currentTerm: String by Delegates.observable("") { _, _, newTerm ->
val items = strategy.autocompleteItems(newTerm) val items = strategy.autocompleteItems(newTerm)
notifyDataSetChanged() notifyDataSetChanged()
}) }
init { init {
setHasStableIds(true) setHasStableIds(true)
......
package chat.rocket.android.widget.autocompletion.ui package chat.rocket.android.suggestions.ui
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
import androidx.transition.Slide
import androidx.transition.TransitionManager
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.text.Editable import android.text.Editable
import android.text.InputType import android.text.InputType
import android.text.TextWatcher import android.text.TextWatcher
import android.transition.Slide
import android.transition.TransitionManager
import android.util.AttributeSet import android.util.AttributeSet
import android.view.Gravity import android.view.Gravity
import android.view.View import android.view.View
import android.widget.EditText import android.widget.EditText
import android.widget.FrameLayout import android.widget.FrameLayout
import chat.rocket.android.R import androidx.annotation.DrawableRes
import chat.rocket.android.widget.autocompletion.model.SuggestionModel import androidx.core.content.ContextCompat
import chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter.Companion.CONSTRAINT_BOUND_TO_START import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.suggestions.R
import chat.rocket.android.suggestions.model.SuggestionModel
import chat.rocket.android.suggestions.ui.SuggestionsAdapter.Companion.CONSTRAINT_BOUND_TO_START
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
...@@ -103,7 +103,8 @@ class SuggestionsView : FrameLayout, TextWatcher { ...@@ -103,7 +103,8 @@ class SuggestionsView : FrameLayout, TextWatcher {
val prefixEndIndex = this.editor?.get()?.selectionStart ?: NO_STATE_INDEX val prefixEndIndex = this.editor?.get()?.selectionStart ?: NO_STATE_INDEX
if (prefixEndIndex == NO_STATE_INDEX || prefixEndIndex < completionOffset.get()) return if (prefixEndIndex == NO_STATE_INDEX || prefixEndIndex < completionOffset.get()) return
val prefix = s.subSequence(completionOffset.get(), this.editor?.get()?.selectionStart ?: completionOffset.get()).toString() val prefix = s.subSequence(completionOffset.get(), this.editor?.get()?.selectionStart
?: completionOffset.get()).toString()
recyclerView.adapter?.let { recyclerView.adapter?.let {
it as SuggestionsAdapter it as SuggestionsAdapter
// we need to look up only after the '@' // we need to look up only after the '@'
...@@ -156,7 +157,7 @@ class SuggestionsView : FrameLayout, TextWatcher { ...@@ -156,7 +157,7 @@ class SuggestionsView : FrameLayout, TextWatcher {
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
val adapter = adapter(token) val adapter = adapter(token)
localProvidersByToken.getOrPut(token, { hashMapOf() }) localProvidersByToken.getOrPut(token, { hashMapOf() })
.put(adapter.term(), list) .put(adapter.term(), list)
if (completionOffset.get() > NO_STATE_INDEX && adapter.itemCount == 0) expand() if (completionOffset.get() > NO_STATE_INDEX && adapter.itemCount == 0) expand()
adapter.addItems(list) adapter.addItems(list)
} }
...@@ -192,7 +193,8 @@ class SuggestionsView : FrameLayout, TextWatcher { ...@@ -192,7 +193,8 @@ class SuggestionsView : FrameLayout, TextWatcher {
} }
private fun adapter(token: String): SuggestionsAdapter<*> { private fun adapter(token: String): SuggestionsAdapter<*> {
return adaptersByToken[token] ?: throw IllegalStateException("no adapter binds to token \"$token\"") return adaptersByToken[token]
?: throw IllegalStateException("no adapter binds to token \"$token\"")
} }
private fun cancelSuggestions(haltCompletion: Boolean) { private fun cancelSuggestions(haltCompletion: Boolean) {
......
...@@ -8,4 +8,4 @@ ...@@ -8,4 +8,4 @@
<size android:height="2dp" /> <size android:height="2dp" />
</shape> </shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="popup_max_height">150dp</dimen>
<dimen name="suggestions_box_max_height">250dp</dimen>
</resources>
\ No newline at end of file
<resources>
<string name="app_name">suggestions</string>
</resources>
package yampsample.leonardoaramaki.github.com.suggestions;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment